fix(dao-vote-delegation): scale delegated VP on same-percent refresh (audit Critical 1) - #933
Open
noahsaso wants to merge 2 commits into
Open
fix(dao-vote-delegation): scale delegated VP on same-percent refresh (audit Critical 1)#933noahsaso wants to merge 2 commits into
noahsaso wants to merge 2 commits into
Conversation
Cover the audit's Finding 5 scenario (a delegation created while expiry was disabled and refreshed after the DAO enabled it must not remove a co-delegator's contribution) and a mixed-percentage invariant check that the delegate's total always equals the sum of scaled live delegations across refreshes and expirations. All three refresh tests fail without the fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YBSNZfoCq2XqymbVV9r5rE
noahsaso
force-pushed
the
fix-delegation-refresh-weight
branch
from
September 1, 2026 20:56
ba81189 to
d4aee45
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## development #933 +/- ##
===============================================
- Coverage 96.56% 92.11% -4.46%
===============================================
Files 199 159 -40
Lines 67407 28775 -38632
===============================================
- Hits 65094 26507 -38587
+ Misses 2313 2268 -45 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes audit Finding 1 (Critical): "A delegation refresh can credit a delegate with the delegator's full weight rather than the delegated share". Also closes the other face of the same defect, Finding 5 (High): "The same refresh can instead destroy a co-delegator's voting power".
Root cause
When a delegator re-delegates to the same delegate with the same percent before the delegation expires,
handle_redelegationonly moves the scheduled expiration. It calledupdate_delegated_vp_expirationwith the delegator's raw voting power instead of the delegated share (calculate_delegated_vp(vp, percent)), while every other path (new delegation, undelegation, percent change, voting power change hooks) uses the scaled amount.At a 100% delegation the two amounts coincide, which is why the existing
test_expiration_updatetest never caught it.Fix
calculate_delegated_vp(delegator_vp, new_percent)on the same-percent refresh path.add_delegated_vp,remove_delegated_vp_if_not_expiredandupdate_delegated_vp_expirationfromvptodelegated_vp, and the raw-power argument ofhandle_redelegationtodelegator_vp, so the two quantities can no longer be confused (as recommended by the audit).Tests
Three new tests, all of which fail on
developmentand pass with the fix:test_same_percent_refresh_moves_only_delegated_voting_power: 50% refresh with a co-delegator; only the refreshing delegator's scaled share moves to the new expiration.test_same_percent_refresh_after_enabling_expiration_preserves_co_delegator_vp: the Finding 5 scenario (delegation created with expiry disabled, DAO enables expiry, delegator refreshes); the co-delegator's non-expiring contribution survives.test_mixed_percent_refreshes_keep_total_equal_to_sum_of_scaled_delegations: four delegators with different weights and percents (60/50/75/100%), two refreshed mid-period; the delegate's total equals the sum of scaled live delegations at every expiration boundary.Verified locally:
cargo test -p dao-vote-delegation(51 passed),cargo +nightly-2024-01-08 fmt --all -- --check,cargo +nightly-2024-01-08 clippy --all-targets -- -D warnings.Not included (audit follow-ups)
cw-wormhole::decrementwith a checked one so an accounting inconsistency surfaces as a named error rather than a trap. That is a separate package change and is left for a follow-up.🤖 Generated with Claude Code
https://claude.ai/code/session_01YBSNZfoCq2XqymbVV9r5rE