feat(sns-governance): expose latest reward-event shares on neurons - #11078
feat(sns-governance): expose latest reward-event shares on neurons#11078aodl wants to merge 2 commits into
Conversation
Persist each participating neuron's exact reward shares from the existing reward-settlement calculation, tagged with the reward event end timestamp, and expose them through the existing neuron query responses. Participation remains available when native reward rates are zero, while maturity allocation, proposal settlement, ballot clearing, reward timing, and neuron pagination remain unchanged.
There was a problem hiding this comment.
This pull request changes code owned by the Governance team. Therefore, make sure that
you have considered the following (for Governance-owned code):
-
Update
unreleased_changelog.md(if there are behavior changes, even if they are
non-breaking). -
Are there BREAKING changes?
-
Is a data migration needed?
-
Security review?
How to Satisfy This Automatic Review
-
Go to the bottom of the pull request page.
-
Look for where it says this bot is requesting changes.
-
Click the three dots to the right.
-
Select "Dismiss review".
-
In the text entry box, respond to each of the numbered items in the previous
section, declare one of the following:
-
Done.
-
$REASON_WHY_NO_NEED. E.g. for
unreleased_changelog.md, "No
canister behavior changes.", or for item 2, "Existing APIs
behave as before.".
Brief Guide to "Externally Visible" Changes
"Externally visible behavior change" is very often due to some NEW canister API.
Changes to EXISTING APIs are more likely to be "breaking".
If these changes are breaking, make sure that clients know how to migrate, how to
maintain their continuity of operations.
If your changes are behind a feature flag, then, do NOT add entrie(s) to
unreleased_changelog.md in this PR! But rather, add entrie(s) later, in the PR
that enables these changes in production.
Reference(s)
For a more comprehensive checklist, see here.
GOVERNANCE_CHECKLIST_REMINDER_DEDUP
|
Dear @aodl, In order to potentially merge your code in this open-source repository and therefore proceed with your contribution, we need to have your approval on DFINITY's CLA. If you decide to agree with it, please visit this issue and read the instructions there. Once you have signed it, re-trigger the workflow on this PR to see if your code can be merged. — The DFINITY Foundation |
|
✅ No security or compliance issues detected. Reviewed everything up to 97dfffb. Security Overview
Detected Code Changes
|
Consumer review from
|
Narrow follow-up on the privacy point aboveAfter re-reading the current patch, I think the concern can be addressed without introducing a new commitment system or substantially expanding this PR. The important distinction is between:
The second part creates a public, neuron-level activity dataset containing both participation and reward-share magnitude. Because neuron IDs are stable, repeated snapshots can be correlated over time. Splitting does not make this a reliable measure of holder-level participation: it mainly makes correlation easier for unsplit neurons than for holders who deliberately reorganize their stake. My narrow recommendation for this PR is therefore:
If per-neuron access is required in this PR, a bounded compromise would be:
That policy would apply uniformly to every neuron, without stake thresholds or holder-specific exceptions. This also needs a clear scope boundary in the API documentation: this is an SNS reward-accounting feature and should not establish a general governance API pattern. Any equivalent NNS exposure should require its own design, privacy, and governance review. At minimum, I would add tests proving that:
This seems like the smallest change that preserves the useful accounting work while avoiding a permanent anonymous per-neuron activity feed. |
How SNS could become a precedent for NNSThere is no automatic SNS-to-NNS path. A hypothetical progression would require several separate decisions:
That would require a separate NNS code change, review, canister upgrade proposal, and NNS vote. This PR cannot make it happen by itself. |
|
imo fix the privacy issues or it's going to be a problem |
Yes. That's correct, this is tightly scoped to the SNS framework
Please could you articulate your concern regarding privacy? This PR doesn't change the status quo regarding privacy in any way, but I'd be happy to discuss this with you further if you disagree. Thanks for your interest. |
Done |
There is no such permission guard on readability. It's all unconditionally public. If you'd like the public/private toggle that the NNS has but for SNSs, I would suggest taking that to a new PR. Note that that would actually be a bigger change than you expected. If it were well implemented though, I'd probably support it. |
|
@daniel-wong-dfinity-org, @basvandijk, I'm not sure why the CLA task is still blocking. I actioned the request yesterday |
|
https://forum.dfinity.org/t/beyond-the-sns-why-toko-could-be-its-natural-successor/74992/2 - I think we're going to replace the SNS anyway |

Context -> https://forum.dfinity.org/t/exposing-sns-voting-participation-shares-after-reward-settlement/74916
What
SNS Governance already calculates exact per-neuron reward shares while settling each reward event, but currently discards them after using them to allocate native maturity.
This change stores each participating neuron's positive share together with the existing reward-event end timestamp in a new optional
Neuron.latest_reward_event_participationfield. The field is exposed through the existingget_neuronand paginatedlist_neuronsAPIs.Participation is recorded independently of the native reward configuration, so it remains available when SNS voting reward rates are zero. Existing maturity allocation, proposal settlement, ballot clearing, reward timing, neuron visibility, and pagination remain unchanged.
Why
This makes the canonical SNS voting-participation weighting available after settlement, allowing generic SNS applications to allocate external, non-inflationary rewards without independently reconstructing ballots.
Semantics and consumer contract
reward_sharesis:Consequently:
YesandNoballots contribute their recorded voting power.Unspecifiedballots contribute nothing.The value is not:
The field identifies the neuron's most recent event with positive participation, which is not necessarily the globally latest reward event. Consumers must compare:
An absent field or a different timestamp means the neuron has zero shares in the target event.
Only positive participants are updated. A neuron that does not participate in a newer event may retain an older tagged value; the timestamp makes that value unambiguously stale without requiring Governance to rewrite every neuron.
RewardEvent.settled_proposalscontinues to distinguish:Consumers may normalize the raw shares over whatever eligible neuron set their application defines.
API representation
The Candid shape is equivalent to:
The unsigned value is reconstructed as:
u128is used because one neuron'su64ballot voting power can be summed over multiple proposals in the same reward event. Protobuf has no nativeuint128, so the value follows the repository's established high/low representation pattern.The inner
reward_sharesis optional because protobuf message fields have presence semantics. Governance always populates it when writing a participation record; consumers should still handle an absent inner value defensively.Implementation and design decisions
neuron_id_to_reward_sharesmap after it has been fully calculated.RewardEventis reused as the event tag.Decimalinvariant is checked before exact conversion tou128; negative or fractional values are rejected.latest_reward_event_participation = None.When a neuron is split, the parent retains its historical participation and the new child starts with
None. The settled event attributed the ballots to the parent's neuron ID; copying the value would double the event total, while dividing it would introduce a new post-settlement redistribution policy rather than exposing the calculation Governance actually made.Reading a consistent paginated snapshot
A client can safely obtain the latest event's complete participation snapshot using the existing APIs:
get_latest_reward_eventand recordend_timestamp_seconds.list_neuronswithof_principal = None.get_latest_reward_eventagain.Governance does not need to hold a read lock across query calls.
Validation
The following passed locally after implementation:
cargo fmt --all -- --checkcargo clippy -p ic-sns-governance --all-targets -- -D warningscargo test -p ic-sns-governance --lib— 328 tests//rs/sns/governance/...— all 11 test targetsCoverage includes:
YesandNovotes;Unspecifiedballots;get_neuron;u64::MAX;Related discussions
This addresses a recurring request to retain usable participation information after proposal ballots are cleared:
In addition to the tests within this repository, I've also run a separate SNS project against this release locally and confirmed the desired behaviour against tests within that repo too.