🥏Vulnerability: _lpToken and Reward Token Confusion in Staking Contracts

Overview:

This vulnerability arises in staking contracts where both the staking token (_lpToken) and the reward token are treated similarly. If the staking token used in a new pool is the same as the reward token, the reward calculation becomes flawed. This is because the balance of the staking token is often used to calculate rewards, and if the staking token is the same as the reward token, the contract’s reward balance will incorrectly inflate the staking token balance, leading to improper reward distribution.

This flaw allows for rewards to be under-allocated to legitimate stakers, as the balance used for reward calculation will be artificially high due to the rewards being added to the same balance as the staking tokens. The incorrect calculation reduces the rewards that should have been distributed to stakers, leading to stakers receiving less than they are entitled to.


Impact:

If the staking token (_lpToken) is the same as the reward token, the following issues can arise:

  1. Inflated Staking Pool Balance:

    • The staking pool’s balance is calculated using the balance of _lpToken. However, if the rewards (which are also in the form of the reward token) are deposited into the contract, they will inflate the total supply of _lpToken. This inflated balance will be used in reward calculations, skewing the results and reducing the reward-per-share for stakers.

  2. Under-rewarding Stakers:

    • Since the balance used to calculate rewards (i.e., lpSupply) is inflated by the reward token itself, each staker’s rewards will be reduced. This is because the rewards will be distributed over a larger pool of tokens than should be considered, meaning that stakers receive fewer rewards than expected.

  3. Reduced Trust in the Protocol:

    • If stakers realize that they are receiving fewer rewards than they should, the protocol's reputation could be damaged. This can lead to stakers withdrawing their tokens from the platform, reducing overall liquidity and trust in the staking mechanism.


Vulnerable Code Example (ConvexMasterChef):

function add(
    uint256 _allocPoint,
    IERC20 _lpToken,
    IRewarder _rewarder,
    bool _withUpdate
) public onlyOwner {
    if (_withUpdate) {
        massUpdatePools();
    }
    uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
    totalAllocPoint = totalAllocPoint.add(_allocPoint);
    poolInfo.push(
        PoolInfo({
            lpToken: _lpToken,
            allocPoint: _allocPoint,
            lastRewardBlock: lastRewardBlock,
            accCvxPerShare: 0,
            rewarder: _rewarder
        })
    );
}

Flaw:

  • No check is made to ensure that _lpToken is not the same as the reward token (e.g., cvx in the case of Convex).

  • If _lpToken is the same as cvx, the balance of cvx in the contract will be inflated by the rewards being added, leading to under-allocation of rewards for stakers.

function updatePool(uint256 _pid) public {
    PoolInfo storage pool = poolInfo[_pid];
    if (block.number <= pool.lastRewardBlock) {
        return;
    }
    uint256 lpSupply = pool.lpToken.balanceOf(address(this)); // Vulnerable: Includes reward tokens in balance
    if (lpSupply == 0) {
        pool.lastRewardBlock = block.number;
        return;
    }
    uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
    uint256 cvxReward = multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
    pool.accCvxPerShare = pool.accCvxPerShare.add(cvxReward.mul(1e12).div(lpSupply)); // lpSupply is inflated
    pool.lastRewardBlock = block.number;
}

Flaw:

  • The lpSupply used in the reward calculation is inflated by the reward token itself (since the reward token and _lpToken are the same), leading to a lower reward-per-share for stakers.

Conclusion:

The lack of a check to ensure that the staking token _lpToken is not the same as the reward token introduces a significant vulnerability in staking contracts. This leads to incorrect reward calculations, under-rewarding legitimate stakers by diluting the reward-per-share due to inflated token balances. By implementing simple checks and keeping staking and reward tokens separate, developers can ensure that rewards are fairly and accurately distributed to stakers. This protects users from receiving fewer rewards than they are entitled to and maintains trust in the staking mechanism.

Last updated