fix: use 1-address-1-vote model to prevent flash-loan voting (#469) - #689
fix: use 1-address-1-vote model to prevent flash-loan voting (#469)#6890dillon wants to merge 4 commits into
Conversation
…#469) Replace token-weighted voting with 1-address-1-vote in cast_vote and verify_with_votes. Each eligible token holder now contributes exactly 1 to the vote count regardless of their balance, closing the flash-loan attack vector where an attacker borrows a large balance, votes with inflated weight, and returns the tokens before verification. Changes: - cast_vote: weight = 1 instead of weight = balance - verify_with_votes: threshold computed from vote counts, not token weights - Updated tests and proptests for the new 1-address-1-vote model - Updated overflow regression test (Iris-IV#354) for safe weight addition Closes Iris-IV#469
|
@0dillon Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
solid, minimal fix for #469. incrementing the weight sums by 1 instead of the voter's balance (src/voting.rs:393, 403) and computing approval bps from counts in a few notes:
heads up that #709 solves the same issue (#448/#469) with a fuller cleanup; maintainers should pick one and close the other. this branch is in conflict with main, so please resolve conflicts and rebase, then this is mergeable from my side. |
Closes #469
Summary
Replace token-weighted voting with a 1-address-1-vote model to close the flash-loan attack vector where an attacker borrows a large token balance, votes with inflated weight, and returns the tokens before verification.
What Changed
cast_vote: Each vote now contributes exactly1to the weight sum instead of the voter's live token balance. The token-holder gate (min_voting_balance) is preserved — you still need tokens to vote, but your balance doesn't affect your voting power.verify_with_votes: Threshold calculation now uses vote counts (approve_votes/reject_votes) instead of token weights. This is safe because the quorum check already guaranteestotal_votes > 0.approve_weightandreject_weightstorage keys are still incremented (by 1 per vote) so existing campaigns with stored voting state remain valid.Design Decision
Three options were considered from the issue: snapshot at creation, minimum holding period, or 1-address-1-vote. 1-address-1-vote was chosen because it's the simplest, most gas-efficient fix that fully eliminates the flash-loan vector without requiring expensive on-chain iteration of all token holders at campaign creation time.
Acceptance Criteria
cast_voteno longer uses live balance for voting weightverify_with_votesthreshold immune to flash-loan inflationmin_voting_balance)test_campaign_update)Test Output
Follow-ups (out of scope)
approve_weight/reject_weightstorage entirely since they now equal vote counts (backward-compat cleanup)EVENT_PAYLOADS.mdto reflect changed event shapeSecurity Note
This fix prevents flash-loan governance attacks. The 1-address-1-vote model is Sybil-resistant only to the extent that obtaining token balances across many addresses costs real capital. The
min_voting_balanceadmin parameter can be raised to increase this cost.