diff --git a/src/deployments/contracts/procedures/AaveV3HelpersProcedureTwo.sol b/src/deployments/contracts/procedures/AaveV3HelpersProcedureTwo.sol index 01b456e1..e8d40b76 100644 --- a/src/deployments/contracts/procedures/AaveV3HelpersProcedureTwo.sol +++ b/src/deployments/contracts/procedures/AaveV3HelpersProcedureTwo.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import '../../interfaces/IMarketReportTypes.sol'; import {TransparentProxyFactory, ITransparentProxyFactory} from 'solidity-utils/contracts/transparent-proxy/TransparentProxyFactory.sol'; import {StataTokenV2} from 'aave-v3-periphery/contracts/static-a-token/StataTokenV2.sol'; -import {StaticATokenFactory} from 'aave-v3-periphery/contracts/static-a-token/StaticATokenFactory.sol'; +import {StataTokenFactory} from 'aave-v3-periphery/contracts/static-a-token/StataTokenFactory.sol'; import {IErrors} from '../../interfaces/IErrors.sol'; contract AaveV3HelpersProcedureTwo is IErrors { @@ -20,7 +20,7 @@ contract AaveV3HelpersProcedureTwo is IErrors { new StataTokenV2(IPool(pool), IRewardsController(rewardsController)) ); staticATokenReport.staticATokenFactoryImplementation = address( - new StaticATokenFactory( + new StataTokenFactory( IPool(pool), proxyAdmin, ITransparentProxyFactory(staticATokenReport.transparentProxyFactory), @@ -33,7 +33,7 @@ contract AaveV3HelpersProcedureTwo is IErrors { ).create( staticATokenReport.staticATokenFactoryImplementation, proxyAdmin, - abi.encodeWithSelector(StaticATokenFactory.initialize.selector) + abi.encodeWithSelector(StataTokenFactory.initialize.selector) ); return staticATokenReport; diff --git a/src/periphery/contracts/static-a-token/README.md b/src/periphery/contracts/static-a-token/README.md index 599d3d83..90d998df 100644 --- a/src/periphery/contracts/static-a-token/README.md +++ b/src/periphery/contracts/static-a-token/README.md @@ -6,23 +6,22 @@ ## About -The static-a-token contains an [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) generic token vault/wrapper for all Aave v3 pools. +The StataToken in an [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) generic token vault/wrapper intended to be used with aave v3 aTokens. ## Features - **Full [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) compatibility.** - **Accounting for any potential liquidity mining rewards.** Let’s say some team of the Aave ecosystem (or the Aave community itself) decides to incentivize deposits of USDC on Aave v3 Ethereum. By holding `stataUSDC`, the user will still be eligible for those incentives. It is important to highlight that while currently the wrapper supports infinite reward tokens by design (e.g. AAVE incentivizing stETH & Lido incentivizing stETH as well), each reward needs to be permissionlessly registered which bears some [⁽¹⁾](#limitations). -- **Meta-transactions support.** To enable interfaces to offer gas-less transactions to deposit/withdraw on the wrapper/Aave protocol (also supported on Aave v3). Including permit() for transfers of the `stataAToken` itself. -- **Upgradable by the Aave governance.** Similar to other contracts of the Aave ecosystem, the Level 1 executor (short executor) will be able to add new features to the deployed instances of the `stataTokens`. -- **Powered by a stataToken Factory.** Whenever a token will be listed on Aave v3, anybody will be able to call the stataToken Factory to deploy an instance for the new asset, permissionless, but still assuring the code used and permissions are properly configured without any extra headache. +- **Upgradable by the Aave governance.** Similar to other contracts of the Aave ecosystem, the Level 1 executor (short executor) will be able to add new features to the deployed instances of the `StataTokens`. +- **Powered by a StataTokenFactory.** Whenever a token will be listed on Aave v3, anybody will be able to call the StataTokenFactory to deploy an instance for the new asset, permissionless, but still assuring the code used and permissions are properly configured without any extra headache. See [IStata4626LM.sol](./interfaces/IERC20AaveLM.sol) for detailed method documentation. ## Deployed Addresses -The staticATokenFactory is deployed for all major Aave v3 pools. -An up to date address can be fetched from the respective [address-book pool library](https://github.com/bgd-labs/aave-address-book/blob/main/src/AaveV3Ethereum.sol). +The StataTokenFactory is deployed for all major Aave v3 pools. +An up to date address can be fetched from the respective [address-book pool library](https://search.onaave.com/?q=stata%20factory). ## Limitations @@ -37,6 +36,8 @@ For this project, the security procedures applied/being finished are: - The test suite of the codebase itself. - Certora audit/property checking for all the dynamics of the `stataToken`, including respecting all the specs of [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626). +--- + ## Upgrade Notes StataTokenV2 ### Inheritance @@ -54,6 +55,8 @@ The implementation is seperated in two ERC20 extentions and one actual "merger" In addition it adds a `latestAnswer` priceFeed, which returns the share price based on how aave prices the underlying. 3. `StataTokenV2` is the main contract inheriting `ERC20AaveLM` and `ERC4626StataToken`, while also adding `Pausability`, `Rescuability`, `Permit` and the actual initialization. +![inheritance graph](./inheritance.png) + ### Libraries The previous `StaticATokenLM` relied on `WadRayMath` and `WadRayMathExplicitRounding` - a custom version where one can specify the rounding behavior - for math operations. diff --git a/src/periphery/contracts/static-a-token/StaticATokenFactory.sol b/src/periphery/contracts/static-a-token/StataTokenFactory.sol similarity index 78% rename from src/periphery/contracts/static-a-token/StaticATokenFactory.sol rename to src/periphery/contracts/static-a-token/StataTokenFactory.sol index 91af7f72..f8343ba6 100644 --- a/src/periphery/contracts/static-a-token/StaticATokenFactory.sol +++ b/src/periphery/contracts/static-a-token/StataTokenFactory.sol @@ -6,16 +6,16 @@ import {IERC20Metadata} from 'solidity-utils/contracts/oz-common/interfaces/IERC import {ITransparentProxyFactory} from 'solidity-utils/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol'; import {Initializable} from 'solidity-utils/contracts/transparent-proxy/Initializable.sol'; import {StataTokenV2} from './StataTokenV2.sol'; -import {IStaticATokenFactory} from './interfaces/IStaticATokenFactory.sol'; +import {IStataTokenFactory} from './interfaces/IStataTokenFactory.sol'; /** - * @title StaticATokenFactory - * @notice Factory contract that keeps track of all deployed static aToken wrappers for a specified pool. - * This registry also acts as a factory, allowing to deploy new static aTokens on demand. - * There can only be one static aToken per underlying on the registry at a time. + * @title StataTokenFactory + * @notice Factory contract that keeps track of all deployed StataTokens for a specified pool. + * This registry also acts as a factory, allowing to deploy new StataTokens on demand. + * There can only be one StataToken per underlying on the registry at any time. * @author BGD labs */ -contract StaticATokenFactory is Initializable, IStaticATokenFactory { +contract StataTokenFactory is Initializable, IStataTokenFactory { IPool public immutable POOL; address public immutable PROXY_ADMIN; ITransparentProxyFactory public immutable TRANSPARENT_PROXY_FACTORY; @@ -40,8 +40,8 @@ contract StaticATokenFactory is Initializable, IStaticATokenFactory { function initialize() external initializer {} - ///@inheritdoc IStaticATokenFactory - function createStaticATokens(address[] memory underlyings) external returns (address[] memory) { + ///@inheritdoc IStataTokenFactory + function createStataTokens(address[] memory underlyings) external returns (address[] memory) { address[] memory staticATokens = new address[](underlyings.length); for (uint256 i = 0; i < underlyings.length; i++) { address cachedStaticAToken = _underlyingToStaticAToken[underlyings[i]]; @@ -79,13 +79,13 @@ contract StaticATokenFactory is Initializable, IStaticATokenFactory { return staticATokens; } - ///@inheritdoc IStaticATokenFactory - function getStaticATokens() external view returns (address[] memory) { + ///@inheritdoc IStataTokenFactory + function getStataTokens() external view returns (address[] memory) { return _staticATokens; } - ///@inheritdoc IStaticATokenFactory - function getStaticAToken(address underlying) external view returns (address) { + ///@inheritdoc IStataTokenFactory + function getStataToken(address underlying) external view returns (address) { return _underlyingToStaticAToken[underlying]; } } diff --git a/src/periphery/contracts/static-a-token/StataTokenV2.sol b/src/periphery/contracts/static-a-token/StataTokenV2.sol index 0142fff3..e984b2b6 100644 --- a/src/periphery/contracts/static-a-token/StataTokenV2.sol +++ b/src/periphery/contracts/static-a-token/StataTokenV2.sol @@ -10,6 +10,11 @@ import {ERC4626Upgradeable, ERC4626StataTokenUpgradeable, IPool} from './ERC4626 import {ERC20AaveLMUpgradeable, IRewardsController} from './ERC20AaveLMUpgradeable.sol'; import {IStataTokenV2} from './interfaces/IStataTokenV2.sol'; +/** + * @title StataTokenV2 + * @notice A 4626 Vault which wrapps aTokens in order to translate the rebasing nature of yield accrual into a non-rebasing value accrual. + * @author BGD labs + */ contract StataTokenV2 is ERC20PermitUpgradeable, ERC20AaveLMUpgradeable, diff --git a/src/periphery/contracts/static-a-token/inheritance.png b/src/periphery/contracts/static-a-token/inheritance.png new file mode 100644 index 00000000..ba79976a Binary files /dev/null and b/src/periphery/contracts/static-a-token/inheritance.png differ diff --git a/src/periphery/contracts/static-a-token/interfaces/IStataTokenFactory.sol b/src/periphery/contracts/static-a-token/interfaces/IStataTokenFactory.sol new file mode 100644 index 00000000..2eaf187b --- /dev/null +++ b/src/periphery/contracts/static-a-token/interfaces/IStataTokenFactory.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +interface IStataTokenFactory { + error NotListedUnderlying(address underlying); + + /** + * @notice Creates new StataTokens + * @param underlyings the addresses of the underlyings to create. + * @return address[] addresses of the new StataTokens. + */ + function createStataTokens(address[] memory underlyings) external returns (address[] memory); + + /** + * @notice Returns all StataTokens deployed via this registry. + * @return address[] list of StataTokens + */ + function getStataTokens() external view returns (address[] memory); + + /** + * @notice Returns the StataToken for a given underlying. + * @param underlying the address of the underlying. + * @return address the StataToken address. + */ + function getStataToken(address underlying) external view returns (address); +} diff --git a/src/periphery/contracts/static-a-token/interfaces/IStaticATokenFactory.sol b/src/periphery/contracts/static-a-token/interfaces/IStaticATokenFactory.sol deleted file mode 100644 index 1aee13d4..00000000 --- a/src/periphery/contracts/static-a-token/interfaces/IStaticATokenFactory.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IStaticATokenFactory { - error NotListedUnderlying(address underlying); - - /** - * @notice Creates new staticATokens - * @param underlyings the addresses of the underlyings to create. - * @return address[] addresses of the new staticATokens. - */ - function createStaticATokens(address[] memory underlyings) external returns (address[] memory); - - /** - * @notice Returns all tokens deployed via this registry. - * @return address[] list of tokens - */ - function getStaticATokens() external view returns (address[] memory); - - /** - * @notice Returns the staticAToken for a given underlying. - * @param underlying the address of the underlying. - * @return address the staticAToken address. - */ - function getStaticAToken(address underlying) external view returns (address); -} diff --git a/tests/periphery/static-a-token/TestBase.sol b/tests/periphery/static-a-token/TestBase.sol index cc14fc3e..0365fb21 100644 --- a/tests/periphery/static-a-token/TestBase.sol +++ b/tests/periphery/static-a-token/TestBase.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.10; import {IERC20Metadata, IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import {TransparentUpgradeableProxy} from 'solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol'; import {ITransparentProxyFactory} from 'solidity-utils/contracts/transparent-proxy/TransparentProxyFactory.sol'; -import {StaticATokenFactory} from '../../../src/periphery/contracts/static-a-token/StaticATokenFactory.sol'; +import {StataTokenFactory} from '../../../src/periphery/contracts/static-a-token/StataTokenFactory.sol'; import {StataTokenV2} from '../../../src/periphery/contracts/static-a-token/StataTokenV2.sol'; import {IERC20AaveLM} from '../../../src/periphery/contracts/static-a-token/interfaces/IERC20AaveLM.sol'; import {TestnetProcedures, TestnetERC20} from '../../utils/TestnetProcedures.sol'; @@ -24,7 +24,7 @@ abstract contract BaseTest is TestnetProcedures { StataTokenV2 public stataTokenV2; address public proxyAdmin; ITransparentProxyFactory public proxyFactory; - StaticATokenFactory public factory; + StataTokenFactory public factory; address[] rewardTokens; @@ -53,10 +53,10 @@ abstract contract BaseTest is TestnetProcedures { proxyFactory = ITransparentProxyFactory(report.transparentProxyFactory); proxyAdmin = report.proxyAdmin; - factory = StaticATokenFactory(report.staticATokenFactoryProxy); - factory.createStaticATokens(contracts.poolProxy.getReservesList()); + factory = StataTokenFactory(report.staticATokenFactoryProxy); + factory.createStataTokens(contracts.poolProxy.getReservesList()); - stataTokenV2 = StataTokenV2(factory.getStaticAToken(underlying)); + stataTokenV2 = StataTokenV2(factory.getStataToken(underlying)); } function _skipBlocks(uint128 blocks) internal {