-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from morpho-org/feat/wsteth-oracle
wstETH/ETH oracle using exchange rate only
- Loading branch information
Showing
13 changed files
with
134 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
30 changes: 30 additions & 0 deletions
30
src/wsteth-exchange-rate-adapter/WstEthStEthExchangeRateChainlinkAdapter.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.21; | ||
|
||
import {IStEth} from "./interfaces/IStEth.sol"; | ||
import {MinimalAggregatorV3Interface} from "./interfaces/MinimalAggregatorV3Interface.sol"; | ||
|
||
/// @title WstEthStEthExchangeRateChainlinkAdapter | ||
/// @author Morpho Labs | ||
/// @custom:contact [email protected] | ||
/// @notice wstETH/stETH exchange rate price feed. | ||
/// @dev This contract should only be deployed on Ethereum and used as a price feed for Morpho oracles. | ||
contract WstEthStEthExchangeRateChainlinkAdapter is MinimalAggregatorV3Interface { | ||
/// @inheritdoc MinimalAggregatorV3Interface | ||
// @dev The calculated price has 18 decimals precision, whatever the value of `decimals`. | ||
uint8 public constant decimals = 18; | ||
|
||
/// @notice The description of the price feed. | ||
string public constant description = "wstETH/stETH exchange rate"; | ||
|
||
/// @notice The address of stETH on Ethereum. | ||
IStEth public constant ST_ETH = IStEth(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); | ||
|
||
/// @inheritdoc MinimalAggregatorV3Interface | ||
/// @dev Returns zero for roundId, startedAt, updatedAt and answeredInRound. | ||
/// @dev Silently overflows if `getPooledEthByShares`'s return value is greater than `type(int256).max`. | ||
function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) { | ||
// It is assumed that `getPooledEthByShares` returns a price with 18 decimals precision. | ||
return (0, int256(ST_ETH.getPooledEthByShares(1 ether)), 0, 0, 0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.5.0; | ||
|
||
interface IStEth { | ||
function getPooledEthByShares(uint256) external view returns (uint256); | ||
} |
17 changes: 17 additions & 0 deletions
17
src/wsteth-exchange-rate-adapter/interfaces/MinimalAggregatorV3Interface.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.5.0; | ||
|
||
/// @dev Inspired by | ||
/// https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol | ||
/// @dev This is the minimal feed interface required by `MorphoChainlinkOracleV2`. | ||
interface MinimalAggregatorV3Interface { | ||
/// @notice Returns the precision of the feed. | ||
function decimals() external view returns (uint8); | ||
|
||
/// @notice Returns Chainlink's `latestRoundData` return values. | ||
/// @notice Only the `answer` field is used by `MorphoChainlinkOracleV2`. | ||
function latestRoundData() | ||
external | ||
view | ||
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity ^0.8.0; | ||
|
||
import "./helpers/Constants.sol"; | ||
import "../lib/forge-std/src/Test.sol"; | ||
import {ChainlinkOracle} from "../src/morpho-chainlink-v1/ChainlinkOracle.sol"; | ||
import "../src/wsteth-exchange-rate-adapter/WstEthStEthExchangeRateChainlinkAdapter.sol"; | ||
|
||
contract WstEthStEthExchangeRateChainlinkAdapterTest is Test { | ||
IStEth internal constant ST_ETH = IStEth(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); | ||
|
||
WstEthStEthExchangeRateChainlinkAdapter internal oracle; | ||
ChainlinkOracle internal chainlinkOracle; | ||
|
||
function setUp() public { | ||
vm.createSelectFork(vm.envString("ETH_RPC_URL")); | ||
oracle = new WstEthStEthExchangeRateChainlinkAdapter(); | ||
chainlinkOracle = new ChainlinkOracle( | ||
vaultZero, AggregatorV3Interface(address(oracle)), feedZero, feedZero, feedZero, 1, 18, 18 | ||
); | ||
} | ||
|
||
function testDecimals() public { | ||
assertEq(oracle.decimals(), uint8(18)); | ||
} | ||
|
||
function testDescription() public { | ||
assertEq(oracle.description(), "wstETH/stETH exchange rate"); | ||
} | ||
|
||
function testLatestRoundData() public { | ||
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = | ||
oracle.latestRoundData(); | ||
assertEq(roundId, 0); | ||
assertEq(uint256(answer), ST_ETH.getPooledEthByShares(1 ether)); | ||
assertEq(startedAt, 0); | ||
assertEq(updatedAt, 0); | ||
assertEq(answeredInRound, 0); | ||
} | ||
|
||
function testLatestRoundDataBounds() public { | ||
(, int256 answer,,,) = oracle.latestRoundData(); | ||
assertGe(uint256(answer), 1154690031824824994); // Exchange rate queried at block 19070943 | ||
assertLe(uint256(answer), 1.5e18); // Max bounds of the exchange rate. Should work for a long enough time. | ||
} | ||
|
||
function testOracleWstEthStEthExchangeRate() public { | ||
(, int256 expectedPrice,,,) = oracle.latestRoundData(); | ||
assertEq(chainlinkOracle.price(), uint256(expectedPrice) * 10 ** (36 + 18 - 18 - 18)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC4626, AggregatorV3Interface} from "../../src/morpho-chainlink-v1/ChainlinkOracle.sol"; | ||
|
||
AggregatorV3Interface constant feedZero = AggregatorV3Interface(address(0)); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant btcUsdFeed = AggregatorV3Interface(0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant usdcUsdFeed = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6); | ||
// 18 decimals of precision | ||
AggregatorV3Interface constant btcEthFeed = AggregatorV3Interface(0xdeb288F737066589598e9214E782fa5A8eD689e8); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant wBtcBtcFeed = AggregatorV3Interface(0xfdFD9C85aD200c506Cf9e21F1FD8dd01932FBB23); | ||
// 18 decimals of precision | ||
AggregatorV3Interface constant stEthEthFeed = AggregatorV3Interface(0x86392dC19c0b719886221c78AB11eb8Cf5c52812); | ||
// 18 decimals of precision | ||
AggregatorV3Interface constant usdcEthFeed = AggregatorV3Interface(0x986b5E1e1755e3C2440e960477f25201B0a8bbD4); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant ethUsdFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419); | ||
// 18 decimals of precision | ||
AggregatorV3Interface constant daiEthFeed = AggregatorV3Interface(0x773616E4d11A78F511299002da57A0a94577F1f4); | ||
|
||
IERC4626 constant vaultZero = IERC4626(address(0)); | ||
IERC4626 constant sDaiVault = IERC4626(0x83F20F44975D03b1b09e64809B757c47f942BEeA); |