This vulnerability arises when an attacker front-runs the first legitimate deposit by using the donateTokens
function to deposit a small amount (e.g., 1 wei). This causes the totalStaked
variable to increase without minting any shares leaving totalShares at 0. When the legitimate first deposit occurs, the share calculation ((_amount * totalShares) / totalStaked) returns 0. This leads to a revert when the contract attempts to subtract DEAD_SHARES from the deposit(shares) while minting first deposit shares causing the first deposit to always fail.
The attacker monitors the mempool for the first legitimate deposit transaction.
The attacker front-runs this transaction with a call to stakingPool.donateTokens()
, depositing a small amount (e.g., 1 wei).
The donateTokens
function updates totalStaked
without minting any shares. Now, totalStaked > 0
, but totalShares
remains 0.
The legitimate user's deposit transaction is then processed. The PriorityPool contract calls the deposit function in the StakingPool contract:
Within the deposit function, the _mint function (inherited from StakingRewardsPool) is called:
The _mint function calls getSharesByStake, also defined in StakingRewardsPool
Since totalStaked > 0 (due to the donation) but totalShares == 0, the calculation (_amount * totalShares) / totalStaked will returns 0 for first deposit
The _mintShares function receives 0 as the sharesToMint value.
When _mintShares is called, the subtraction `_amount(sharesToMint) - DEAD_SHARES` causes the transaction to revert due to an underflow, effectively blocking the first and consecutive legitimate deposits.
Legitimate users attempting to deposit tokens will have their transactions reverted preventing them from participating in the staking pool.
Manual Analysis
Modify the donateTokens
function to block donations when totalShares=0
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.