From 9ef0ef33b195212b40c9f6c14d36e1b8d1476efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Tesa=C5=99?= Date: Tue, 20 May 2025 10:30:00 +0200 Subject: [PATCH 1/4] Prepare contracts for deployment --- contracts/IWstETH.sol | 9 ++++++++ contracts/WstETHApi3ReaderProxyV1.sol | 33 +++++++++++++++++++++++++++ scripts/deploy-morpho.ts | 22 ++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 contracts/IWstETH.sol create mode 100644 contracts/WstETHApi3ReaderProxyV1.sol create mode 100644 scripts/deploy-morpho.ts diff --git a/contracts/IWstETH.sol b/contracts/IWstETH.sol new file mode 100644 index 0000000..a037db8 --- /dev/null +++ b/contracts/IWstETH.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/// @title A minimal interface for the wstETH contract indended to read the +/// stETH value per token value of 1 unit of wstETH. +interface IWstETH { + /// @notice Returns the stETH value per token value of 1 unit of wstETH. + function stEthPerToken() external view returns (uint256); +} diff --git a/contracts/WstETHApi3ReaderProxyV1.sol b/contracts/WstETHApi3ReaderProxyV1.sol new file mode 100644 index 0000000..7af97c1 --- /dev/null +++ b/contracts/WstETHApi3ReaderProxyV1.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import "@api3/contracts/interfaces/IApi3ReaderProxy.sol"; +import "./IWstETH.sol"; + +/// @title An immutable proxy contract that reads the price of wstETH directly +/// from the WstETH contract on Ethereum. +/// @dev This contract implements only the IApi3ReaderProxy and not the +/// AggregatorV2V3Interface which is usually implemented with Api3 proxies. The +/// user of this contract needs to be aware of this and only use this contract +/// where the IApi3ReaderProxy interface is expected. +contract WstETHApi3ReaderProxyV1 is IApi3ReaderProxy { + address public constant WST_ETH = + 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + + constructor() {} + + /// @inheritdoc IApi3ReaderProxy + /// @dev The value returned by this function is the stETH value scaled to 18 + /// decimals. The timestamp returned is the current block timestamp. + function read() + public + view + override + returns (int224 value, uint32 timestamp) + { + uint256 stEthPerToken = IWstETH(WST_ETH).stEthPerToken(); + + value = int224(int256(stEthPerToken)); // stEthPerToken value has 18 decimals. + timestamp = uint32(block.timestamp); + } +} diff --git a/scripts/deploy-morpho.ts b/scripts/deploy-morpho.ts new file mode 100644 index 0000000..dd93ae5 --- /dev/null +++ b/scripts/deploy-morpho.ts @@ -0,0 +1,22 @@ +import { ethers } from 'ethers'; + +import { ProductApi3ReaderProxyV1__factory } from '../typechain-types'; + +const deployPriceFeedProxy = async () => { + const provider = new ethers.JsonRpcProvider(process.env.PROVIDER); + const signer = new ethers.Wallet(process.env.PK!, provider); + const productApi3ReaderProxyV1Factory = new ProductApi3ReaderProxyV1__factory(signer); + console.info('Deploying product proxy...'); + const tx = await productApi3ReaderProxyV1Factory.deploy( + '', // TODO: Deploy WstETHApi3ReaderProxyV1.sol + '0x37422cC8e1487a0452cc0D0BF75877d86c63c88A' // https://market.api3.org/ethereum/eth-usd/integrate?dappAlias=morpho-wsteth-usdc-860-lltv + ); + const productApi3ReaderProxyV1 = await tx.waitForDeployment(); + console.info('Deployed ProductApi3ReaderProxyV1:', await productApi3ReaderProxyV1.getAddress()); + console.info('ProductApi3ReaderProxyV1.read():', await productApi3ReaderProxyV1.read()); + // Deployed on Base: 0x707991d5533021021cC360dF093f1B396340Ef3E +}; + +deployPriceFeedProxy(); + +// NOTE: https://market.api3.org/ethereum/usdc-usd/integrate?dappAlias=morpho-wsteth-usdc-860-lltv From 0830eb46fe57e7aecc15e6965548ce75829e58b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Tesa=C5=99?= Date: Tue, 20 May 2025 10:32:14 +0200 Subject: [PATCH 2/4] Small docs updates --- contracts/IWstETH.sol | 4 ++-- contracts/WstETHApi3ReaderProxyV1.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/IWstETH.sol b/contracts/IWstETH.sol index a037db8..a57b419 100644 --- a/contracts/IWstETH.sol +++ b/contracts/IWstETH.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -/// @title A minimal interface for the wstETH contract indended to read the -/// stETH value per token value of 1 unit of wstETH. +/// @title A minimal interface for the wstETH contract on Ethereum, used to read +/// the stETH value per token value of 1 unit of wstETH. interface IWstETH { /// @notice Returns the stETH value per token value of 1 unit of wstETH. function stEthPerToken() external view returns (uint256); diff --git a/contracts/WstETHApi3ReaderProxyV1.sol b/contracts/WstETHApi3ReaderProxyV1.sol index 7af97c1..c2b1be0 100644 --- a/contracts/WstETHApi3ReaderProxyV1.sol +++ b/contracts/WstETHApi3ReaderProxyV1.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.27; import "@api3/contracts/interfaces/IApi3ReaderProxy.sol"; import "./IWstETH.sol"; -/// @title An immutable proxy contract that reads the price of wstETH directly -/// from the WstETH contract on Ethereum. +/// @title An immutable proxy contract that reads the price of wstETH/stETH +/// directly from the WstETH contract on Ethereum. /// @dev This contract implements only the IApi3ReaderProxy and not the /// AggregatorV2V3Interface which is usually implemented with Api3 proxies. The /// user of this contract needs to be aware of this and only use this contract From 9e1e697e969f58e2e231ae1968e54b7edc52cc05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Tesa=C5=99?= Date: Wed, 21 May 2025 16:41:04 +0200 Subject: [PATCH 3/4] Address review comments --- contracts/WstETHApi3ReaderProxyV1.sol | 5 ++--- contracts/{ => interfaces}/IWstETH.sol | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) rename contracts/{ => interfaces}/IWstETH.sol (65%) diff --git a/contracts/WstETHApi3ReaderProxyV1.sol b/contracts/WstETHApi3ReaderProxyV1.sol index c2b1be0..79e3822 100644 --- a/contracts/WstETHApi3ReaderProxyV1.sol +++ b/contracts/WstETHApi3ReaderProxyV1.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import "@api3/contracts/interfaces/IApi3ReaderProxy.sol"; -import "./IWstETH.sol"; +import "./interfaces/IWstETH.sol"; /// @title An immutable proxy contract that reads the price of wstETH/stETH /// directly from the WstETH contract on Ethereum. @@ -11,11 +11,10 @@ import "./IWstETH.sol"; /// user of this contract needs to be aware of this and only use this contract /// where the IApi3ReaderProxy interface is expected. contract WstETHApi3ReaderProxyV1 is IApi3ReaderProxy { + /// @notice The address of the wstETH contract on Ethereum mainnet. address public constant WST_ETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; - constructor() {} - /// @inheritdoc IApi3ReaderProxy /// @dev The value returned by this function is the stETH value scaled to 18 /// decimals. The timestamp returned is the current block timestamp. diff --git a/contracts/IWstETH.sol b/contracts/interfaces/IWstETH.sol similarity index 65% rename from contracts/IWstETH.sol rename to contracts/interfaces/IWstETH.sol index a57b419..eebe4d8 100644 --- a/contracts/IWstETH.sol +++ b/contracts/interfaces/IWstETH.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.27; /// @title A minimal interface for the wstETH contract on Ethereum, used to read /// the stETH value per token value of 1 unit of wstETH. +/// @dev The returned value is scaled to 18 decimals. interface IWstETH { - /// @notice Returns the stETH value per token value of 1 unit of wstETH. + /// @return The stETH value per token value of 1 unit of wstETH, scaled to 18 decimals. function stEthPerToken() external view returns (uint256); } From a5a3f139effb2471a42f85030dffb8ca11992edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Tesa=C5=99?= Date: Wed, 21 May 2025 16:50:38 +0200 Subject: [PATCH 4/4] Improve docs --- contracts/WstETHApi3ReaderProxyV1.sol | 14 +++++++------- contracts/interfaces/IWstETH.sol | 9 +++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/contracts/WstETHApi3ReaderProxyV1.sol b/contracts/WstETHApi3ReaderProxyV1.sol index 79e3822..7e5eb1d 100644 --- a/contracts/WstETHApi3ReaderProxyV1.sol +++ b/contracts/WstETHApi3ReaderProxyV1.sol @@ -4,20 +4,20 @@ pragma solidity ^0.8.27; import "@api3/contracts/interfaces/IApi3ReaderProxy.sol"; import "./interfaces/IWstETH.sol"; -/// @title An immutable proxy contract that reads the price of wstETH/stETH +/// @title An immutable proxy contract that reads the stETH per wstETH ratio /// directly from the WstETH contract on Ethereum. -/// @dev This contract implements only the IApi3ReaderProxy and not the -/// AggregatorV2V3Interface which is usually implemented with Api3 proxies. The -/// user of this contract needs to be aware of this and only use this contract -/// where the IApi3ReaderProxy interface is expected. +/// @dev This contract implements only the IApi3ReaderProxy interface and not the +/// AggregatorV2V3Interface which is usually implemented by Api3 proxies. The +/// user of this contract needs to be aware of this limitation and only use this +/// contract where the IApi3ReaderProxy interface is expected. contract WstETHApi3ReaderProxyV1 is IApi3ReaderProxy { /// @notice The address of the wstETH contract on Ethereum mainnet. address public constant WST_ETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; /// @inheritdoc IApi3ReaderProxy - /// @dev The value returned by this function is the stETH value scaled to 18 - /// decimals. The timestamp returned is the current block timestamp. + /// @dev Returns the stETH/wstETH exchange rate with 18 decimals precision. + /// The timestamp returned is the current block timestamp. function read() public view diff --git a/contracts/interfaces/IWstETH.sol b/contracts/interfaces/IWstETH.sol index eebe4d8..019e4b6 100644 --- a/contracts/interfaces/IWstETH.sol +++ b/contracts/interfaces/IWstETH.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -/// @title A minimal interface for the wstETH contract on Ethereum, used to read -/// the stETH value per token value of 1 unit of wstETH. -/// @dev The returned value is scaled to 18 decimals. +/// @title A minimal interface for the wstETH contract on Ethereum +/// @dev This interface only includes the stEthPerToken function needed to read +/// the exchange rate between stETH and wstETH. interface IWstETH { - /// @return The stETH value per token value of 1 unit of wstETH, scaled to 18 decimals. + /// @notice Returns the amount of stETH that corresponds to 1 wstETH + /// @return The stETH/wstETH exchange rate with 18 decimals precision function stEthPerToken() external view returns (uint256); }