all files / plugins/assets/lido/ LidoStakedEthCollateral.sol

100% Statements 6/6
100% Branches 4/4
100% Functions 3/3
100% Lines 11/11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74                                                                      21× 20× 19× 19×                                   50×     47× 42×   42× 42×           83× 83×      
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
 
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../../../libraries/Fixed.sol";
import "../AppreciatingFiatCollateral.sol";
import "../OracleLib.sol";
import "./IWSTETH.sol";
 
/**
 * @title Lido Staked Eth Collateral
 * @notice Collateral plugin for Lido stETH,
 * tok = wstETH  (wrapped stETH)
 * ref = stETH (pegged to ETH 1:1)
 * tar = ETH
 * UoA = USD
 */
contract LidoStakedEthCollateral is AppreciatingFiatCollateral {
    using OracleLib for AggregatorV3Interface;
    using FixLib for uint192;
 
    // In order to provide tighter price estimates this contract uses {UoA/tok} and {ref/target}
    // price feeds. Here we include them directly and ignore the parent class' chainlinkFeed.
 
    AggregatorV3Interface public immutable targetPerRefChainlinkFeed; // {target/ref}
    uint48 public immutable targetPerRefChainlinkTimeout; // {s}
 
    /// @param config.chainlinkFeed {UoA/ref}
    /// @param config.oracleError {1} Should be the oracle error _only_ for the {UoA/tok} feed
    constructor(
        CollateralConfig memory config,
        uint192 revenueHiding,
        AggregatorV3Interface _targetPerRefChainlinkFeed,
        uint48 _targetPerRefChainlinkTimeout
    ) AppreciatingFiatCollateral(config, revenueHiding) {
        require(address(_targetPerRefChainlinkFeed) != address(0), "missing targetPerRef feed");
        require(_targetPerRefChainlinkTimeout > 0, "targetPerRefChainlinkTimeout zero");
        targetPerRefChainlinkFeed = _targetPerRefChainlinkFeed;
        targetPerRefChainlinkTimeout = _targetPerRefChainlinkTimeout;
    }
 
    /// Can revert, used by other contract functions in order to catch errors
    /// @return low {UoA/tok} The low price estimate
    /// @return high {UoA/tok} The high price estimate
    /// @return pegPrice {target/ref} The actual price observed in the peg
    function tryPrice()
        external
        view
        override
        returns (
            uint192 low,
            uint192 high,
            uint192 pegPrice
        )
    {
        // {target/ref} Get current market peg ({eth/steth})
        pegPrice = targetPerRefChainlinkFeed.price(targetPerRefChainlinkTimeout);
 
        // {UoA/tok} = {UoA/ref} * {ref/tok}
        uint192 p = chainlinkFeed.price(oracleTimeout).mul(_underlyingRefPerTok());
        uint192 err = p.mul(oracleError, CEIL);
 
        high = p + err;
        low = p - err;
        // assert(low <= high); obviously true just by inspection
    }
 
    /// @return {ref/tok} Quantity of whole reference units per whole collateral tokens
    function _underlyingRefPerTok() internal view override returns (uint192) {
        uint256 rate = IWSTETH(address(erc20)).stEthPerToken();
        return _safeWrap(rate);
    }
}