Lucene search

K
code423n4Code4renaCODE423N4:2022-04-BACKD-FINDINGS-ISSUES-132
HistoryApr 27, 2022 - 12:00 a.m.

[WP-H15] AmmConvexGauge.sol#poolCheckpoint() cvxStakedIntegral can be manipulated by the attacker

2022-04-2700:00:00
Code4rena
github.com
3
manipulation
profit
vulnerability
ammconvexgauge
cvxstakedintegral
security
tokens
reward
update

Lines of code

Vulnerability details

function poolCheckpoint() public virtual override returns (bool) {
    if (killed) {
        return false;
    }
    uint256 timeElapsed = block.timestamp - uint256(ammLastUpdated);
    uint256 currentRate = IController(controller).inflationManager().getAmmRateForToken(
        ammToken
    );
    uint256 crvEarned = IERC20(crv).balanceOf(address(this)) -
        _preClaimRewardsCrvEarned +
        crvRewardsContract.earned(address(this));
    uint256 cvxEarned = getCvxMintAmount(crvEarned);

    // Update the integral of total token supply for the pool
    if (totalStaked > 0) {
        if (inflationRecipient == address(0)) {
            ammStakedIntegral += (currentRate * timeElapsed).scaledDiv(totalStaked);
        } else {
            perUserShare[inflationRecipient] += currentRate * timeElapsed;
        }
        crvStakedIntegral += (crvEarned - _crvLastEarned).scaledDiv(totalStaked);
        cvxStakedIntegral += (cvxEarned - _cvxLastEarned).scaledDiv(totalStaked);
    }
    _crvLastEarned = crvEarned;
    _cvxLastEarned = cvxEarned;
    ammLastUpdated = uint48(block.timestamp);
    return true;
}

In the current implementation, crvEarned is the new crv reward earned since the last claim.

However, anyone can send crv tokens to the contract to increase crvEarned.

Since cvxEarned is based on crvEarned, by increasing crvEarned, cvxStakedIntegral can be increased artificially.

When the increased cvx is worth more than the crv tokens sent, the attacker can net a profit from it.

PoC

Given:

  • CRV = 2 USD
  • CVX = 26 USD
  • CVX_TOKEN.totalSupply() = 80 mil
  • 2,000 CVX left in contract
  1. The attacker deposits a lot of tokens and take 80% of totalStaked;
  2. The attacker sends 10,000 CRV to the contract, the claimRewards():
  • crvEarned = 10,000
  • cvxEarned = 2,000
  1. The attacker receives 1,600 CVX, worth 41,600 USD

Recommendation

Consider updating the cvxStakedIntegral after crvRewardsContract.getReward(); with the actual amount of CVX tokens received.


The text was updated successfully, but these errors were encountered:

All reactions