Skip to content

Latest commit

 

History

History
58 lines (40 loc) · 2.83 KB

File metadata and controls

58 lines (40 loc) · 2.83 KB

Ancient Neon Koala

Medium

Invalid initial reward in CGDAIncentive

Summary

CGDAIncentive incorrectly calculates the initial reward for the first claim, and is not to specification. This can lead to unexpected behavior and loss of funds for some claimaints.

Vulnerability Detail

In CGDAIncentive, the initialReward parameter is documented as the initial reward amount.

However, in initialize the lastClaimTime = block.timestamp:

    function initialize(bytes calldata data_) public override initializer {
        InitPayload memory init_ = abi.decode(data_, (InitPayload));

        cgdaParams = CGDAParameters({
            rewardDecay: init_.rewardDecay,
            rewardBoost: init_.rewardBoost,
            lastClaimTime: block.timestamp,
            currentReward: init_.initialReward
        });

And when the first claim is made, it is calculated in currentReward:

    function currentReward() public view override returns (uint256) {
        uint256 timeSinceLastClaim = block.timestamp - cgdaParams.lastClaimTime;
        uint256 available = asset.balanceOf(address(this));

        // Calculate the current reward based on the time elapsed since the last claim
        // on a linear scale, with `1 * rewardBoost` added for each hour without a claim
        uint256 projectedReward = cgdaParams.currentReward + (timeSinceLastClaim * cgdaParams.rewardBoost) / 3600;
        return projectedReward > available ? available : projectedReward;
    }

Crucially, since cgdaParams.lastClaimTime was set in the initializer, the first claim reward will be cgdaParams.currentReward + (timeSinceLastClaim * cgdaParams.rewardBoost) / 3600. If timeSinceLastClaim is nonzero, the initial reward will exceed the parameter set in the initializer.

Impact

Code is not to specification.

Importantly, if a non-trivial timespan passes between initialization and claims, the initialReward will potentially be much higher than what was set by the boostCreator. This is likely to be the case for many boosts, since it will take some time for users to begin completing actions and claiming their rewards. It's unlikely that claims would immediately begin after initialization.

Boost creators who follow this specification thinking initialReward will be the claim reward of the first claimaint will misconfigure their vault, which can result in unintended behavior such as an incorrectly calculated total budget, prevent some claimants from claiming and causing unintended loss of funds.

Code Snippet

https://github.com/sherlock-audit/2024-06-boost-aa-wallet/blob/main/boost-protocol/packages/evm/contracts/incentives/CGDAIncentive.sol#L123-L131

Tool used

Manual Review

Recommendation

Consider giving the first claimaint the fixed amount initialReward and using currentReward with cgdaParams.lastClaimTime thereafter.