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 fromtotalVoting
and_writeVotingCheckpoint()
isn't called to updatevotingCheckpoints
andvotingNumCheckpoints
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()
whentotalVoting
is reset by making it 0,_writeVotingCheckpoint()
isn't called to updatevotingCheckpoints
andvotingNumCheckpoints
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
votingCheckpoints
andvotingNumCheckpoints
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?