31484 - [SC - High] Rewards for the first epoch at rewards distribu...
Submitted on May 20th 2024 at 06:25:57 UTC by @MahdiKarimi for Boost | Alchemix
Report ID: #31484
Report type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RewardsDistributor.sol
Impacts:
Permanent freezing of unclaimed yield
Description
Brief/Intro
Some parts of rewards at rewards distributor would be lost
Vulnerability Details
RewardsDistributor distributes ALCX rewards to veALCX holders, rewards are distributed based on the balance of users at the end of an epoch, for the first time that the minter distributes rewards, some part of it is being allocated to the first epoch which can be withdrawn only if there was a user at the start of the first epoch ( end of last epoch ) but since rewards distributor and voting escrow ( mints veALCX ) are being deployed in the same time so there is no user at that timestamp so no one can claim those rewards and rewards gets stuck in contract forever
Impact Details
loss of rewards at rewards distributor in the first epoch
References
https://github.com/alchemix-finance/alchemix-v2-dao/blob/f1007439ad3a32e412468c4c42f62f676822dc1f/src/RewardsDistributor.sol#L244-L248
Proof of Concept
function testLostRewardsFirstEpoch() public {
initializeVotingEscrow();
// assert alcx balance of rewards distributor is zero
uint256 distributorBalance = alcx.balanceOf(address(distributor));
assertEq(distributorBalance, 0);
// Fast forward 1/2 epoch
// create a lock
hevm.warp(block.timestamp + nextEpoch / 2);
hevm.roll(block.number + 1);
uint256 tokenId1 = createVeAlcx(admin, TOKEN_1, MAXTIME, false);
// Finish the epoch and distribute some rewards
hevm.warp(newEpoch());
voter.distribute();
// assert alcx balance of rewards distributor is greater than zero which means some tokens has been transffered as reward
uint256 distributorBalanceEnd = alcx.balanceOf(address(distributor));
assertGt(distributorBalanceEnd, 0);
// calculate claimable amount by token1
uint256 claimable1 = distributor.claimable(tokenId1);
// as we see token1 can't claim all alcx tokens despite that he's only user (on one can claim it)
assert(distributorBalanceEnd > claimable1);
// to ensure diffrence is high we check freezed amount is at least 3 time more than claimable amount
assert(distributorBalanceEnd > 3 * claimable1);
}
Last updated
Was this helpful?