sherlock-audit / 2023-07-perennial-judging

2 stars 1 forks source link

n33k - Kept.sol: Keeper could be rewarded with wrong amount of token because of stale eth price #122

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

n33k

high

Kept.sol: Keeper could be rewarded with wrong amount of token because of stale eth price

Summary

Keeper is incentivized with a keeper fee to commit oracle updates. The keeper fee is calculated based on the gas value, which is determined by eth price. The eth price is queryed from chainlink but price staleness is not checked. Keeper will be rewarded with wrong amount of token because of stale eth price.

Vulnerability Detail

The keeperFee is calculated and rewarded during oracle update. It could be wrong because of the stale eth price returned from _etherPrice(). Keeper could get a wrong fee because of stale price.

    modifier keep(UFixed18 multiplier, uint256 buffer, bytes memory data) {
        uint256 startGas = gasleft();

        _;

        uint256 gasUsed = startGas - gasleft();
        UFixed18 keeperFee = UFixed18Lib.from(gasUsed)
            .mul(multiplier)
            .add(UFixed18Lib.from(buffer))
            .mul(_etherPrice())
            .mul(UFixed18.wrap(block.basefee));

        _raiseKeeperFee(keeperFee, data);

        keeperToken().push(msg.sender, keeperFee);

        emit KeeperCall(msg.sender, gasUsed, multiplier, buffer, keeperFee);
    }

    function _etherPrice() private view returns (UFixed18) {
        (, int256 answer, , ,) = ethTokenOracleFeed().latestRoundData();
        return UFixed18Lib.from(Fixed18Lib.ratio(answer, 1e8)); // chainlink eth-usd feed uses 8 decimals
    }

Impact

The protocol loses tokens to keeper or keeper loses tokens to the protocol.

If the keeper is profiting, he can repeatedly commit oracle updates to drawn the keeper fee reserves.

Code Snippet

https://github.com/sherlock-audit/2023-07-perennial/blob/main/root/contracts/attribute/Kept.sol#L62

Tool used

Manual Review

Recommendation

Should check if the price returned from latestRoundData() is stale.

Duplicate of #159

sherlock-admin commented 1 year ago

2 comment(s) were left on this issue during the judging contest.

141345 commented:

d

n33k commented:

unhandled stale price returned from latestRoundData()