31397 - [SC - Critical] In Bribesol _writeVotingCheckpoint isnt called ...
Submitted on May 18th 2024 at 01:42:23 UTC by @Praise for Boost | Alchemix
Report ID: #31397
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/Bribe.sol
Impacts:
necessary updates aren't done
Description
Brief/Intro
in Bribe.sol, _writeVotingCheckpoint() isn't called to update votingCheckpoints and votingNumCheckpoints whenever votes are withdrawn or there's a reset
Vulnerability Details
In Bribe.deposit(), whenever votes are allocated to a given guage totalVoting is updated with the amount and _writeVotingCheckpoint() is called to update votingCheckpoints and votingNumCheckpoints.
function deposit(uint256 amount, uint256 tokenId) external {
require(msg.sender == voter);
totalSupply += amount;
balanceOf[tokenId] += amount;
totalVoting += amount;
_writeCheckpoint(tokenId, balanceOf[tokenId]);
_writeSupplyCheckpoint();
_writeVotingCheckpoint();
emit Deposit(msg.sender, tokenId, amount);
}Now the issue lies in Bribe.withdraw() & Bribe.resetVoting(), where necessary updates aren't done.
in
Bribe.withdraw()whenever votes are withdrawn from a given guage, the withdrawn votes aren't deducted fromtotalVotingand_writeVotingCheckpoint()isn't called to updatevotingCheckpointsandvotingNumCheckpoints
function withdraw(uint256 amount, uint256 tokenId) external {
require(msg.sender == voter);
totalSupply -= amount;
balanceOf[tokenId] -= amount;
_writeCheckpoint(tokenId, balanceOf[tokenId]);
_writeSupplyCheckpoint();
emit Withdraw(msg.sender, tokenId, amount);
}In
Bribe.resetVoting()whentotalVotingis reset by making it 0,_writeVotingCheckpoint()isn't called to updatevotingCheckpointsandvotingNumCheckpoints
function resetVoting() external {
require(msg.sender == voter);
totalVoting = 0;
}So whenever Bribe.withdraw() / Bribe.resetVoting() is done, record of balance checkpoints for voting period is not updated.
Impact Details
After
Bribe.withdraw()is done, withdrawn votes doesn't reflect ontotalVoting. This is wrongresetting of votes is never updated in
votingCheckpointsandvotingNumCheckpoints
Necessary updates aren't done after such trivial operations.
References
https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/Bribe.sol#L319
https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/Bribe.sol#L332
Proof of Concept
function testBribe_sol() public {
uint256 tokenId1 = createVeAlcx(admin, TOKEN_1, MAXTIME, false);
uint256 tokenId2 = createVeAlcx(beef, TOKEN_1, MAXTIME, false);
address bribeAddress = voter.bribes(address(sushiGauge));
// voter deposits votes to bribe.
hevm.startPrank(address(voter));
Bribe(bribeAddress).deposit(1000e18, tokenId1);
uint256 amt1 = Bribe(bribeAddress).totalVoting();
console.log("total Voting after Deposit", amt1);
// voter withdraws votes from bribe BUT it doesn't reflect in totalVoting
Bribe(bribeAddress).withdraw(1000e18, tokenId1);
uint256 amt2 = Bribe(bribeAddress).totalVoting();
console.log("total Voting after withdraw", amt2);
hevm.stopPrank();
///scenario to show totalVoting still exists in `votingCheckpoints` even after resetVoting()
hevm.startPrank(address(voter));
Bribe(bribeAddress).deposit(1000e18, tokenId1);
uint256 amt1a = Bribe(bribeAddress).totalVoting();
console.log("total Voting after Deposit", amt1a);
Bribe(bribeAddress).resetVoting();
(uint256 timeHere, uint256 amt2a) = Bribe(bribeAddress).votingCheckpoints(0);
console.log("total Voting still existing in votingCheckpoints", amt2a);
}Last updated
Was this helpful?