sherlock-audit / 2024-06-leveraged-vaults-judging

9 stars 8 forks source link

4b - Chainlink feed not validated in `PendlePTOracle` #107

Closed sherlock-admin2 closed 2 months ago

sherlock-admin2 commented 2 months ago

4b

Medium

Chainlink feed not validated in PendlePTOracle

Summary

In PendlePTOracle::_calculateBaseToQuote we can observe that there's a L2 squencer uptime check but there's no check to verify the freshness of that data on L1 networks

Vulnerability Detail

This internal function _calculateBaseToQuote is called in external functions like latestRoundData, latestAnswer and latestTimestamp as we see in the internal function there are no checks to validate if the data being returned is stale or not, same applies to these external functions. Rather it only checks if it is greater than 0 which is a flawed logic because a stale price can be greater than zero but doesn't make it the right price.

Impact

Stale data can be returned

Code Snippet

function _calculateBaseToQuote() internal view returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    ) {
        _checkSequencer();

        int256 baseToUSD;
        (
            roundId,
            baseToUSD,
            startedAt,
            updatedAt,
            answeredInRound
        ) = baseToUSDOracle.latestRoundData();
        // @audit
        require(baseToUSD > 0, "Chainlink Rate Error");
        // Overflow and div by zero not possible
        if (invertBase) baseToUSD = (baseToUSDDecimals * baseToUSDDecimals) / baseToUSD;

        // Past expiration, hardcode the PT oracle price to 1. It is no longer tradable and
        // is worth 1 unit of the underlying SY at expiration.
        int256 ptRate = expiry <= block.timestamp ? ptDecimals : _getPTRate();

        answer = (ptRate * baseToUSD * rateDecimals) /
            (baseToUSDDecimals * ptDecimals);
    }

    function latestRoundData() external view override returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    ) {
        return _calculateBaseToQuote();
    }

    function latestAnswer() external view override returns (int256 answer) {
        (/* */, answer, /* */, /* */, /* */) = _calculateBaseToQuote();
    }

    function latestTimestamp() external view override returns (uint256 updatedAt) {
        (/* */, /* */, /* */, updatedAt, /* */) = _calculateBaseToQuote();
    }

    function latestRound() external view override returns (uint256 roundId) {
        (roundId, /* */, /* */, /* */, /* */) = _calculateBaseToQuote();
    }

Tool used

Manual Review

Recommendation

Implement checks to verify freshness of data

sherlock-admin2 commented 2 months ago

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

0xmystery commented:

Protocol validate chainlink oracle staleness inside the trading module with their own staleness setting across all vaults