diff --git a/contracts/oracles/default/RedstoneAdapterPriceOracleWrsETH.sol b/contracts/oracles/default/RedstoneAdapterPriceOracleWrsETH.sol new file mode 100644 index 00000000..d1488b86 --- /dev/null +++ b/contracts/oracles/default/RedstoneAdapterPriceOracleWrsETH.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.0; + +import "openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol"; + +import "../../external/redstone/IRedstoneOracle.sol"; +import "../BasePriceOracle.sol"; + +/** + * @title RedstoneAdapterPriceOracle + * @notice Returns prices from Redstone. + * @dev Implements `BasePriceOracle`. + * @author Veliko Minkov (https://github.com/vminkov) + */ +contract RedstoneAdapterPriceOracleWrsETH is BasePriceOracle { + /** + * @notice The Redstone oracle contract + */ + IRedstoneOracle public REDSTONE_ORACLE; + + /** + * @dev Constructor to set admin, wtoken address and native token USD price feed address + * @param redstoneOracle The Redstone oracle contract address + */ + constructor(address redstoneOracle) { + REDSTONE_ORACLE = IRedstoneOracle(redstoneOracle); + } + + /** + * @notice Internal function returning the price in of `underlying`. + * @dev will return a price denominated in the native token + */ + function _price(address underlying) internal view returns (uint256) { + // special case for wrsETH + // if input is wrsETH, we need to get the price of rsETH + if (underlying == 0xe7903B1F75C534Dd8159b313d92cDCfbC62cB3Cd) { + underlying = 0x4186BFC76E2E237523CBC30FD220FE055156b41F; + } + uint256 priceInUsd = REDSTONE_ORACLE.priceOf(underlying); + uint256 priceOfNativeInUsd = REDSTONE_ORACLE.priceOfETH(); + return (priceInUsd * 1e18) / priceOfNativeInUsd; + } + + /** + * @notice Returns the price in of `underlying` either in the + * native token (implements `BasePriceOracle`). + */ + function price(address underlying) external view override returns (uint256) { + return _price(underlying); + } + + /** + * @notice Returns the price in WNATIVE of the token underlying `cToken`. + * @dev Implements the `BasePriceOracle` interface for Ionic pools (and Compound v2). + * @return Price in WNATIVE of the token underlying `cToken`, scaled by `10 ** (36 - underlyingDecimals)`. + */ + function getUnderlyingPrice(ICErc20 cToken) external view override returns (uint256) { + // Get underlying token address + address underlying = cToken.underlying(); + + uint256 oraclePrice = _price(underlying); + + uint256 underlyingDecimals = uint256(ERC20Upgradeable(underlying).decimals()); + return + underlyingDecimals <= 18 + ? uint256(oraclePrice) * (10 ** (18 - underlyingDecimals)) + : uint256(oraclePrice) / (10 ** (underlyingDecimals - 18)); + } +} diff --git a/contracts/test/DevTesting.t.sol b/contracts/test/DevTesting.t.sol index c2ba32d1..b4d31073 100644 --- a/contracts/test/DevTesting.t.sol +++ b/contracts/test/DevTesting.t.sol @@ -12,6 +12,7 @@ import { DiamondExtension } from "../ionic/DiamondExtension.sol"; import { ICErc20 } from "../compound/CTokenInterfaces.sol"; import { ISwapRouter } from "../external/uniswap/ISwapRouter.sol"; import { RedstoneAdapterPriceOracle } from "../oracles/default/RedstoneAdapterPriceOracle.sol"; +import { RedstoneAdapterPriceOracleWrsETH } from "../oracles/default/RedstoneAdapterPriceOracleWrsETH.sol"; import { MasterPriceOracle, BasePriceOracle } from "../oracles/MasterPriceOracle.sol"; import { PoolLens } from "../PoolLens.sol"; import { PoolLensSecondary } from "../PoolLensSecondary.sol"; @@ -410,6 +411,22 @@ contract DevTesting is BaseTest { require(errCode == 0, "should be unable to supply"); } + function testModeWrsETH() public debuggingOnly forkAtBlock(MODE_MAINNET, 6635923) { + address wrsEth = 0x4186BFC76E2E237523CBC30FD220FE055156b41F; + RedstoneAdapterPriceOracleWrsETH oracle = new RedstoneAdapterPriceOracleWrsETH( + 0x7C1DAAE7BB0688C9bfE3A918A4224041c7177256 + ); + MasterPriceOracle mpo = MasterPriceOracle(ap.getAddress("MasterPriceOracle")); + + BasePriceOracle[] memory oracles = new BasePriceOracle[](1); + oracles[0] = oracle; + vm.prank(multisig); + mpo.add(asArray(wrsEth), oracles); + + uint256 price = mpo.price(wrsEth); + emit log_named_uint("price of wrsEth", price); + } + function _functionCall( address target, bytes memory data,