31453 - [SC - Critical] The balance of RevenueHandler can be drained
Submitted on May 19th 2024 at 18:09:45 UTC by @DuckAstronomer for Boost | Alchemix
Report ID: #31453
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RevenueHandler.sol
Impacts:
Theft of unclaimed yield
Description
Vulnerability Details
Normally, veALCX holders can claim the reward that has been accrued during the current Epoch from the RevenueHandler
contract in the next Epoch.
The epochUserVeBalance
variable contains the veALCX user's balance for the previous epoch, while the epochTotalVeSupply
variable contains the total veALCX supply for the previous epoch.
https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RevenueHandler.sol#L322
https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RevenueHandler.sol#L319
However, the balanceOfTokenAt()
function has a strong less condition:
https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/VotingEscrow.sol#L1430
Therefore, if the veALCX has been created in a block where block.timestamp == New EPOCH beginning
, the RevenueHandler._claimable()
function will return a positive value (> 0).
This means that an attacker can flash-mint veALCX at that specific block and claim the reward from the RevenueHandler
for the previous Epoch, effectively stealing the rewards for the previous Epoch.
Impact Details
Theft on reward from the RevenueHandler
contract.
Proof of Concept
Poc scenario:
In the current epoch, two whales (whale_1 and whale_2) mint veALCX.
The Revenue Handler accrues the revenue in DAI (10k DAI), and the
checkpoint()
method is called.However, the whales can claim the reward in the next epoch.
The bad guy (attacker) crafts an attack transaction in the block where
block.timestamp == New EPOCH beginning
.In this scenario, the attacker can mint veALCX and claim a portion of the DAI reward from the previous epoch due to the condition
block.timestamp == New EPOCH beginning
, effectively stealing the reward from the whales.The attacker can then proceed to drain the entire DAI balance from the Revenue Handler.
This is achieved by creating a new veALCX with a small amount of BAL and then calling
veALCX.merge()
. This action transfers the balance from the previous veALCX to the new one, providing another opportunity to claim DAI from the Revenue Handler.Repeat step 7 until the Revenue Handler's balance reaches 0.
To run the PoC, place the code below in the PoC.t.sol
file and execute the command: forge test --mp src/test/PoC.t.sol --fork-url 'URL'
.
Last updated