31199 - [SC - Critical] Users might receive less rewars token after Vot...
Submitted on May 14th 2024 at 20:56:20 UTC by @jasonxiale for Boost | Alchemix
Report ID: #31199
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/Bribe.sol
Impacts:
Permanent freezing of unclaimed yield
Description
Brief/Intro
A token owner can call Voter.poke to update the voting power, during the Voter.poke call, the Bribe.totalVoting isn't updated correctly, which results that the Bribe.earned will not calculate the rewards correctly.
Vulnerability Details
While a token owner calls Voter.poke, Voter._reset is called at the beginning of the Voter._vote. In Voter._reset, Bribe.withdraw is called in Voter.sol#L396 And Bribe.withdraw is defined as
319 function withdraw(uint256 amount, uint256 tokenId) external {
320 require(msg.sender == voter);
321
322 totalSupply -= amount;
323 balanceOf[tokenId] -= amount;
324
325 _writeCheckpoint(tokenId, balanceOf[tokenId]);
326 _writeSupplyCheckpoint();
327
328 emit Withdraw(msg.sender, tokenId, amount);
329 }On other side, Bribe.deposit is defined as
As show above, totalVoting isn't updated in Bribe.withdraw, and the function doesn't call _writeVotingCheckpoint to update the checkpoint.
Then, while calculating the reward in Bribe.earned, the function uses votingCheckpoints.votes to calculate the rewards in Bribe.sol#L255-L261 and Bribe.sol#L268-L277
So to sum up, during Voter.poke call:
Bribe.withdrawwill be called, but within the functionBribe.totalVotingisn't deductingamountBribe.depositwill be called in Voter._vote, but this time,Bribe.totalVotingis addedamountSoVoter.pokefunction will causeBribe.totalVotingto increase. Then when calculating the rewards amount inBribe.earned,Bribe.totalVotingis used, which will result wrong amount of rewards.
Impact Details
User might receive less reward token after Voter.poke is called, and the unclaimed reward token will stuck in the contract.
References
Add any relevant links to documentation or code
Proof of Concept
Add the following code to src/test/Voting.t.sol, and run
From the output we can see that
in
testAliceBribesNoPokeAlice doesn't callVoter.poke, token1 and token2 will get 50000*1e18 aurain
testAliceBribesPoke, Alice callsVoter.poke3 times, token1 and token2 will get 20000*1e18 aura
Last updated
Was this helpful?