The StakingPool contract has a vulnerability in how it calculates staking shares when users deposit or transfer tokens. The getSharesByStake()
function, used to calculate shares for deposits and transfers, does not account for up-to-date rewards or losses from staking strategies unless the updateStrategyRewards()
function is called. This allows malicious users to manipulate their actions around reward updates, gaining an unfair advantage by strategically depositing or transfering tokens before rewards are updated.
The getSharesByStake()
function determines how many shares a user receives when depositing tokens or how many shares are transferred when transferring staking tokens. It calculates the shares based on the current value of totalStaked
, which represents the total amount of staked tokens in the pool. This value is only updated when the updateStrategyRewards()
function is called, which applies any profits or losses from staking strategies.
However, there's no requirement to call updateStrategyRewards()
before executing the getSharesByStake()
function. As a result, if the function is not called for a period of time, the shares distributed during deposits or transfers are calculated using outdated values, leading to inaccurate and unfair share distribution. Malicious users can exploit this by:
Depositing just before updateStrategyRewards()
is called and then withdrawing immediately after, benefiting from the updated rewards.
Sell tokens just before updateStrategyRewards()
is called, avoiding losses from the pool’s staking strategies.
This behavior effectively allows users to time their actions to their advantage, disrupting fair distribution among stakers.
The vulnerability allows for the following attacks:
Profit Manipulation: A malicious user can deposit tokens just before the rewards update and withdraw them after, increasing their shares unfairly.
Loss Avoidance: Similarly, a user can avoid staking losses by selling tokens right before an update that would decrease the token value.
Unfair Share Distribution: Users not engaging in the attack will have fewer shares than they should due to profit manipulations by malicious actors.
This attack can cause inequity among participants.
Code analysis of StakingPool.sol
Testing environments to simulate deposits and withdrawals around reward updates
To resolve this issue, it is recommended to call the updateStrategyRewards()
function before executing any functions that rely on getSharesByStake()
, specifically:
In the deposit()
function, call _updateStrategyRewards()
before calculating the user's shares.
In the transfer()
function, ensure that the staking strategies' rewards are updated before performing any share calculations.
By forcing an update of the staking rewards before every share calculation, the system can ensure that deposits and transfers reflect the correct and up-to-date value of the staked tokens, preventing any manipulation.
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.