Skip to content

Commit 8b7ca76

Browse files
committed
Merge remote-tracking branch 'origin/feat/wsteth-oracle' into feat/vault-quote
2 parents 831835c + ac54cd1 commit 8b7ca76

File tree

7 files changed

+48
-60
lines changed

7 files changed

+48
-60
lines changed

src/wsteth-exchange-rate-adapter/WstEthEthExchangeRateChainlinkAdapter.sol

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity 0.8.21;
3+
4+
import {IStEth} from "./interfaces/IStEth.sol";
5+
import {MinimalAggregatorV3Interface} from "./interfaces/MinimalAggregatorV3Interface.sol";
6+
7+
/// @title WstEthStEthExchangeRateChainlinkAdapter
8+
/// @author Morpho Labs
9+
/// @custom:contact security@morpho.org
10+
/// @notice wstETH/stETH exchange rate price feed.
11+
/// @dev This contract should only be deployed on Ethereum and used as a price feed for Morpho oracles.
12+
contract WstEthStEthExchangeRateChainlinkAdapter is MinimalAggregatorV3Interface {
13+
/// @inheritdoc MinimalAggregatorV3Interface
14+
// @dev The calculated price has 18 decimals precision, whatever the value of `decimals`.
15+
uint8 public constant decimals = 18;
16+
17+
/// @notice The description of the price feed.
18+
string public constant description = "wstETH/stETH exchange rate";
19+
20+
/// @notice The address of stETH on Ethereum.
21+
IStEth public constant ST_ETH = IStEth(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);
22+
23+
/// @inheritdoc MinimalAggregatorV3Interface
24+
/// @dev Returns zero for roundId, startedAt, updatedAt and answeredInRound.
25+
/// @dev Silently overflows if `getPooledEthByShares`'s return value is greater than `type(int256).max`.
26+
function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {
27+
// It is assumed that `getPooledEthByShares` returns a price with 18 decimals precision.
28+
return (0, int256(ST_ETH.getPooledEthByShares(1 ether)), 0, 0, 0);
29+
}
30+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity >=0.5.0;
3+
4+
interface IStEth {
5+
function getPooledEthByShares(uint256) external view returns (uint256);
6+
}

src/wsteth-exchange-rate-adapter/interfaces/IWstEth.sol

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/wsteth-exchange-rate-adapter/interfaces/MinimalAggregatorV3Interface.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ pragma solidity >=0.5.0;
33

44
/// @dev Inspired by
55
/// https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol
6+
/// @dev This is the minimal feed interface required by `MorphoChainlinkOracleV2`.
67
interface MinimalAggregatorV3Interface {
8+
/// @notice Returns the precision of the feed.
79
function decimals() external view returns (uint8);
810

11+
/// @notice Returns Chainlink's `latestRoundData` return values.
12+
/// @notice Only the `answer` field is used by `MorphoChainlinkOracleV2`.
913
function latestRoundData()
1014
external
1115
view

src/wsteth-exchange-rate-adapter/libraries/ErrorsLib.sol

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/WstEthEthExchangeRateChainlinkAdapterTest.sol renamed to test/WstEthStEthExchangeRateChainlinkAdapterTest.sol

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ pragma solidity ^0.8.0;
44
import "./helpers/Constants.sol";
55
import "../lib/forge-std/src/Test.sol";
66
import {MorphoChainlinkOracleV2} from "../src/morpho-chainlink/MorphoChainlinkOracleV2.sol";
7-
import "../src/wsteth-exchange-rate-adapter/WstEthEthExchangeRateChainlinkAdapter.sol";
7+
import "../src/wsteth-exchange-rate-adapter/WstEthStEthExchangeRateChainlinkAdapter.sol";
88

9-
contract WstEthEthExchangeRateChainlinkAdapterTest is Test {
10-
IWstEth internal constant WST_ETH = IWstEth(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0);
9+
contract WstEthStEthExchangeRateChainlinkAdapterTest is Test {
10+
IStEth internal constant ST_ETH = IStEth(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);
1111

12-
WstEthEthExchangeRateChainlinkAdapter internal adapter;
12+
WstEthStEthExchangeRateChainlinkAdapter internal adapter;
1313
MorphoChainlinkOracleV2 internal morphoOracle;
1414

1515
function setUp() public {
1616
vm.createSelectFork(vm.envString("ETH_RPC_URL"));
17-
adapter = new WstEthEthExchangeRateChainlinkAdapter(address(WST_ETH));
17+
adapter = new WstEthStEthExchangeRateChainlinkAdapter();
1818
morphoOracle = new MorphoChainlinkOracleV2(
1919
vaultZero, 1, AggregatorV3Interface(address(adapter)), feedZero, 18, vaultZero, 1, feedZero, feedZero, 18
2020
);
@@ -25,19 +25,14 @@ contract WstEthEthExchangeRateChainlinkAdapterTest is Test {
2525
}
2626

2727
function testDescription() public {
28-
assertEq(adapter.description(), "wstETH/ETH exchange rate");
29-
}
30-
31-
function testDeployZeroAddress() public {
32-
vm.expectRevert(bytes(ErrorsLib.ZERO_ADDRESS));
33-
new WstEthEthExchangeRateChainlinkAdapter(address(0));
28+
assertEq(adapter.description(), "wstETH/stETH exchange rate");
3429
}
3530

3631
function testLatestRoundData() public {
3732
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
3833
adapter.latestRoundData();
3934
assertEq(roundId, 0);
40-
assertEq(uint256(answer), WST_ETH.stEthPerToken());
35+
assertEq(uint256(answer), ST_ETH.getPooledEthByShares(1 ether));
4136
assertEq(startedAt, 0);
4237
assertEq(updatedAt, 0);
4338
assertEq(answeredInRound, 0);
@@ -49,7 +44,7 @@ contract WstEthEthExchangeRateChainlinkAdapterTest is Test {
4944
assertLe(uint256(answer), 1.5e18); // Max bounds of the exchange rate. Should work for a long enough time.
5045
}
5146

52-
function testOracleWstEthEthExchangeRate() public {
47+
function testOracleWstEthStEthExchangeRate() public {
5348
(, int256 expectedPrice,,,) = adapter.latestRoundData();
5449
assertEq(morphoOracle.price(), uint256(expectedPrice) * 10 ** (36 + 18 - 18 - 18));
5550
}

0 commit comments

Comments
 (0)