-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Delegate system can be used to increase voting power without resetting the lockEnd #433
Comments
141345 marked the issue as duplicate of #45 |
141345 marked the issue as duplicate of #99 |
141345 marked the issue as duplicate of #178 |
141345 marked the issue as not a duplicate |
141345 marked the issue as low quality report |
invalid delegator/owner increaseAmount(), delegator's locked.end extended, original delegatee's locked.end stays the same, vice versa |
Seems valid to me, @OpenCoreCH? |
Took me some time, but this is intended behaviour and the delegation does not make a difference here: In the PoC, (int128 amount_, uint256 lockEnd_, ,) = ve.locked(vm.addr(27));
(int128 finalAmount_, uint256 finalLockEnd_, int128 delegated_, ) = ve.locked(vm.addr(27)); So we have:
Compare that to a situation where the attacker never delegates and just uses two wallets to have different end timestamps. We also assume that in the second wallet, the amount is increased after 100 days. This results in exactly the same situation:
The delegation does not make a difference here and the end timestamp of the user that increases the amount is correctly increased, whereas the one of the delegatee stays constant. |
alcueca marked the issue as unsatisfactory: |
@OpenCoreCH comment is very good and It crossed my mind just after submitting the issue. However, I think there is a small caveat, it's not the same having all the voting power in a wallet or split accross different wallets. As shown in the test below, having the power concentrated in 1 user seems to give more voting power than 2 users with half locked each, being advantageous to perform this attack. function test_POC_OneWalletVsTwoWallets() public {
vm.deal(user1, 100 ether);
vm.startPrank(gov);
gc.add_gauge(user1);
gc.change_gauge_weight(user1, 100);
vm.stopPrank();
uint256 v = 10 ether;
vm.startPrank(user1);
ve.createLock{value: 2*v}(2*v);
gc.vote_for_gauge_weights(user1, 10_000);
vm.stopPrank();
/*vm.startPrank(user2);
ve.createLock{value: v}(v);
gc.vote_for_gauge_weights(user1, 10_000);
vm.stopPrank();*/
uint256 expectedWeight_ = gc.get_gauge_weight(user1);
console.log("expected", expectedWeight_);
// 19868493150519148900 2 users
// 19868493150675792100 1 user
} There might be other differences besides this one. |
As shown in the test, there is a loss of voting power of 10^-9% by splitting voting power between two accounts. That would be about expected if there is any rounding in the system. |
I can't find any benefit other than this by having all the power in only one account. I'll trust your judgement. Thank you! |
Lines of code
https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L301
https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L317
https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L384
Vulnerability details
Impact
The added delegate mechanism allows increasing the voting power without resetting the
lockEnd
.Proof of Concept
IncreaseAmount()
increases the locked amount of amsg.sender
staked native inVotingEscrow
and resets itslockEnd
toblock.timestamp + LOCK_TIME
. Users can bypass this feature by generating several wallets, creating locks for these wallets and delegating to the first lock. There is a check in the code that requires that a lock can only be delegated to a more recent lock, but it can be bypassed by delegating in the same block that the first lock is created.A POC was carried out in Foundry, add the following test to
VotingEscrow.t.sol
:As can be seen, the user is able to increase their voting power without increasing the
lockEnd
of the original stake.Tools Used
Vscode, Foundry
Recommended Mitigation Steps
The current requirement that a lock must be delegated to a longer lock is the following:
Change the requirement to be strictly bigger as following:
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: