Uniswap / v3-staker

Canonical liquidity mining contract for Uniswap V3
https://uniswap.org
GNU General Public License v3.0
355 stars 202 forks source link

ToB: DoS possible with many stakes #205

Closed ewilz closed 3 years ago

ewilz commented 3 years ago
DoS possible with many stakes
Severity: Low                       Difficulty: Medium
Type:                           Finding ID: TOB-UNI-STK-004
Target: UniswapV3Staker.sol

Description To end an incentive a receive a refund for unclaimed rewards, an incentive creator must call the endIncentive function:

  function endIncentive(IncentiveKey memory key) external override returns (uint256 refund) {
        require(block.timestamp >= key.endTime, 'UniswapV3Staker::endIncentive: cannot end incentive before end time');
        bytes32 incentiveId = IncentiveId.compute(key);
        Incentive storage incentive = incentives[incentiveId];
        refund = incentive.totalRewardUnclaimed;
        require(refund > 0, 'UniswapV3Staker::endIncentive: no refund available');
        require(
            incentive.numberOfStakes == 0,
            'UniswapV3Staker::endIncentive: cannot end incentive while deposits are staked'
        );
        // issue the refund
        incentive.totalRewardUnclaimed = 0;
        TransferHelper.safeTransfer(address(key.rewardToken), key.refundee, refund);
        // note we never clear totalSecondsClaimedX128
        emit IncentiveEnded(incentiveId, refund);
    }

Figure 4.1: endIncentive function The function requires that the number of stakes in the incentive be nil. A stake can be unstaked by anyone after the end of the incentive. Nevertheless, it can happen that an attacker willing to pay a sufficiently high gas fee can prevent the incentive creator from withdrawing their refund. Exploit Scenario Eve deposits 1000 NFTs representing negligible position amounts. She stakes them all unto one incentive. Alice, an incentive creator, cannot end her incentive and withdraw her refund. Recommendation Consider adding a mechanism to allow an incentive creator to end an incentive if a sufficient amount of time has passed after the end of the incentive. In that case, ensure that users can still unstake & withdraw their token, even if they might not get rewards anymore.