From 3328bdbe99fd03be3f353aadca31ff51325992d6 Mon Sep 17 00:00:00 2001 From: Pablo Veyrat Date: Fri, 29 Sep 2023 09:02:32 +0200 Subject: [PATCH 1/6] feat: add an ERC4626 rate provider --- contracts/ERC4626RateProvider.sol | 39 +++++++++++++++++++++++++++++++ package.json | 2 +- yarn.lock | 8 +++---- 3 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 contracts/ERC4626RateProvider.sol diff --git a/contracts/ERC4626RateProvider.sol b/contracts/ERC4626RateProvider.sol new file mode 100644 index 0000000..d5ffbf9 --- /dev/null +++ b/contracts/ERC4626RateProvider.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.0; + +import "./interfaces/IRateProvider.sol"; +import "@openzeppelin/contracts/interfaces/IERC4626.sol"; + +/** + * @title ERC4626 Rate Provider + * @notice Returns the value of 1 share of an ERC4626 in terms of the underlying asset + */ +contract ERC4626RateProvider is IRateProvider { + IERC4626 public immutable erc4626; + uint256 public immutable baseDecimals; + + constructor(IERC4626 _erc4626) { + erc4626 = _erc4626; + baseDecimals = 10**(_erc4626.decimals()); + } + + /** + * @return the value of 1 share of an ERC4626 in terms of the underlying asset + */ + function getRate() external view override returns (uint256) { + return erc4626.convertToAssets(baseDecimals); + } +} diff --git a/package.json b/package.json index 6116288..7932f70 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@chainlink/contracts": "^0.2.1", "@nomiclabs/hardhat-ethers": "^2.0.1", "@nomiclabs/hardhat-waffle": "^2.0.0", - "@openzeppelin/contracts": "^4.3.0", + "@openzeppelin/contracts": "^4.7.3", "@types/chai": "^4.2.12", "@types/mocha": "^8.0.3", "@types/node": "^14.6.0", diff --git a/yarn.lock b/yarn.lock index ed25654..04d93c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -620,10 +620,10 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" -"@openzeppelin/contracts@^4.3.0": - version "4.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.0.tgz#345236d4ec73ef381ab4907c6ef66fd55e5dedad" - integrity sha512-+uBDl/TrmR0Kch6mq3tuxMex/fK7huR6+fQMae+zJk1K5T+dp0pFl12Hbc+1L6oYMXoyDSBJ8zqhRIntrREDFA== +"@openzeppelin/contracts@^4.7.3": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" + integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== "@resolver-engine/core@^0.3.3": version "0.3.3" From 54bf30571328b5a3a23ecb8e7e34b9ce6e0f4bf6 Mon Sep 17 00:00:00 2001 From: Pablo Veyrat Date: Thu, 12 Oct 2023 18:22:02 +0200 Subject: [PATCH 2/6] fix: adapt to IRateProvider spec --- contracts/ERC4626RateProvider.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/ERC4626RateProvider.sol b/contracts/ERC4626RateProvider.sol index d5ffbf9..a594e72 100644 --- a/contracts/ERC4626RateProvider.sol +++ b/contracts/ERC4626RateProvider.sol @@ -19,21 +19,21 @@ import "@openzeppelin/contracts/interfaces/IERC4626.sol"; /** * @title ERC4626 Rate Provider - * @notice Returns the value of 1 share of an ERC4626 in terms of the underlying asset + * @notice Returns an 18 decimal fixed point number that is the exchange rate of the + * shares of an ERC4626 to the underlying asset */ contract ERC4626RateProvider is IRateProvider { IERC4626 public immutable erc4626; - uint256 public immutable baseDecimals; constructor(IERC4626 _erc4626) { erc4626 = _erc4626; - baseDecimals = 10**(_erc4626.decimals()); } /** - * @return the value of 1 share of an ERC4626 in terms of the underlying asset + * @return An 18 decimal fixed point number that is the exchange rate of the + * shares of an ERC4626 to the underlying asset */ function getRate() external view override returns (uint256) { - return erc4626.convertToAssets(baseDecimals); + return erc4626.convertToAssets(1e18); } } From c1205df42e651ba025c379c6ce7aad6e397b0aaf Mon Sep 17 00:00:00 2001 From: Pablo Veyrat Date: Thu, 12 Oct 2023 19:04:10 +0200 Subject: [PATCH 3/6] fix: token decimal computation --- contracts/ERC4626RateProvider.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/ERC4626RateProvider.sol b/contracts/ERC4626RateProvider.sol index a594e72..1ee8fd4 100644 --- a/contracts/ERC4626RateProvider.sol +++ b/contracts/ERC4626RateProvider.sol @@ -24,9 +24,12 @@ import "@openzeppelin/contracts/interfaces/IERC4626.sol"; */ contract ERC4626RateProvider is IRateProvider { IERC4626 public immutable erc4626; + uint256 public immutable base; constructor(IERC4626 _erc4626) { erc4626 = _erc4626; + // Balancer does not support tokens with more than 18 decimals so this will never underflow + base = 10**(18 + _erc4626.decimals() - IERC4626(address(_erc4626.asset())).decimals()); } /** @@ -34,6 +37,6 @@ contract ERC4626RateProvider is IRateProvider { * shares of an ERC4626 to the underlying asset */ function getRate() external view override returns (uint256) { - return erc4626.convertToAssets(1e18); + return erc4626.convertToAssets(base); } } From eae89e5aeee7498828356afc3e8aa62809eec4cf Mon Sep 17 00:00:00 2001 From: baileyspraggins Date: Tue, 17 Oct 2023 21:34:04 -0500 Subject: [PATCH 4/6] Factory added for ERC4626RateProvider --- contracts/ERC4626RateProviderFactory.sol | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 contracts/ERC4626RateProviderFactory.sol diff --git a/contracts/ERC4626RateProviderFactory.sol b/contracts/ERC4626RateProviderFactory.sol new file mode 100644 index 0000000..84cd62e --- /dev/null +++ b/contracts/ERC4626RateProviderFactory.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.0; + +import "./BaseRateProviderFactory.sol"; +import "./ERC4626RateProvider.sol"; + +/** + * @title ERC4626 Rate Provider Factory + * @notice Factory for creating ERC4626RateProviders + * @dev This contract is used to create ERC4626RateProvider contracts. + */ +contract ERC4626RateProviderFactory is BaseRateProviderFactory { + /** + * @notice Deploys a new ERC4626RateProvider contract using an ERC4626 contract. + * @param erc4626 - The ERC4626 contract. + */ + function create(IERC4626 erc4626) external returns (ERC4626RateProvider) { + ERC4626RateProvider rateProvider = new ERC4626RateProvider(erc4626); + _onCreate(address(rateProvider)); + return rateProvider; + } +} \ No newline at end of file From f1a4709bb85904d06386fffaabcd89ed3b9b3882 Mon Sep 17 00:00:00 2001 From: baileyspraggins Date: Tue, 17 Oct 2023 21:41:36 -0500 Subject: [PATCH 5/6] Lint fix --- contracts/ERC4626RateProviderFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/ERC4626RateProviderFactory.sol b/contracts/ERC4626RateProviderFactory.sol index 84cd62e..4fe732a 100644 --- a/contracts/ERC4626RateProviderFactory.sol +++ b/contracts/ERC4626RateProviderFactory.sol @@ -32,4 +32,4 @@ contract ERC4626RateProviderFactory is BaseRateProviderFactory { _onCreate(address(rateProvider)); return rateProvider; } -} \ No newline at end of file +} From bd2818c598d86c1748f3fe73b8c7aca80bca32fa Mon Sep 17 00:00:00 2001 From: Pablo Veyrat Date: Thu, 26 Oct 2023 18:04:23 +0200 Subject: [PATCH 6/6] fix: comments from baileyspraggins --- contracts/ERC4626RateProvider.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/ERC4626RateProvider.sol b/contracts/ERC4626RateProvider.sol index 1ee8fd4..3f79c56 100644 --- a/contracts/ERC4626RateProvider.sol +++ b/contracts/ERC4626RateProvider.sol @@ -14,9 +14,10 @@ pragma solidity ^0.8.0; -import "./interfaces/IRateProvider.sol"; import "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import "./interfaces/IRateProvider.sol"; + /** * @title ERC4626 Rate Provider * @notice Returns an 18 decimal fixed point number that is the exchange rate of the @@ -24,12 +25,13 @@ import "@openzeppelin/contracts/interfaces/IERC4626.sol"; */ contract ERC4626RateProvider is IRateProvider { IERC4626 public immutable erc4626; - uint256 public immutable base; + uint256 public immutable fixedPointOne; constructor(IERC4626 _erc4626) { erc4626 = _erc4626; + uint256 underlyingDecimals = IERC4626(_erc4626.asset()).decimals(); // Balancer does not support tokens with more than 18 decimals so this will never underflow - base = 10**(18 + _erc4626.decimals() - IERC4626(address(_erc4626.asset())).decimals()); + fixedPointOne = 10**(18 + _erc4626.decimals() - underlyingDecimals); } /** @@ -37,6 +39,6 @@ contract ERC4626RateProvider is IRateProvider { * shares of an ERC4626 to the underlying asset */ function getRate() external view override returns (uint256) { - return erc4626.convertToAssets(base); + return erc4626.convertToAssets(fixedPointOne); } }