From 1b4bc6f855da7ce5ca3b0a4fd6bcd7adc35c3efc Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 13 Oct 2020 13:21:11 +0200 Subject: [PATCH] Added ERC20 proxy --- .../lendingpool/LendingPoolConfigurator.sol | 17 ++-- .../BaseImmutableAdminUpgradeabilityProxy.sol | 6 +- ...zableImmutableAdminUpgradeabilityProxy.sol | 89 +++++++++++++++++++ 3 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol diff --git a/contracts/lendingpool/LendingPoolConfigurator.sol b/contracts/lendingpool/LendingPoolConfigurator.sol index 04d3d728..d6791034 100644 --- a/contracts/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/lendingpool/LendingPoolConfigurator.sol @@ -7,8 +7,8 @@ import { VersionedInitializable } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; import { - InitializableImmutableAdminUpgradeabilityProxy -} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; + ERC20InitializableImmutableAdminUpgradeabilityProxy +} from '../libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol'; import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {ILendingPool} from '../interfaces/ILendingPool.sol'; @@ -479,7 +479,7 @@ contract LendingPoolConfigurator is VersionedInitializable { emit ReserveBaseLtvChanged(asset, ltv); } - /** + /** * @dev updates the reserve factor of a reserve * @param asset the address of the reserve * @param reserveFactor the new reserve factor of the reserve @@ -494,7 +494,6 @@ contract LendingPoolConfigurator is VersionedInitializable { emit ReserveFactorChanged(asset, reserveFactor); } - /** * @dev updates the liquidation threshold of a reserve. * @param asset the address of the reserve @@ -559,7 +558,9 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param decimals the decimals of the token **/ function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) { - InitializableImmutableAdminUpgradeabilityProxy proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this)); + + ERC20InitializableImmutableAdminUpgradeabilityProxy proxy + = new ERC20InitializableImmutableAdminUpgradeabilityProxy(address(this)); bytes memory params = abi.encodeWithSignature( 'initialize(uint8,string,string)', @@ -578,9 +579,9 @@ contract LendingPoolConfigurator is VersionedInitializable { address proxyAddress, address implementation ) internal { - InitializableImmutableAdminUpgradeabilityProxy proxy = InitializableImmutableAdminUpgradeabilityProxy( - payable(proxyAddress) - ); + + ERC20InitializableImmutableAdminUpgradeabilityProxy proxy + = ERC20InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress)); (uint256 decimals, , , , , , , , , , ) = pool.getReserveConfigurationData(asset); diff --git a/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol index 23a5f2eb..05a94805 100644 --- a/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol +++ b/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol @@ -4,9 +4,11 @@ pragma solidity ^0.6.8; import '../openzeppelin-upgradeability/BaseUpgradeabilityProxy.sol'; /** - * @title BaseAdminUpgradeabilityProxy + * @title BaseImmutableAdminUpgradeabilityProxy + * @author Aave, inspired by the OpenZeppelin upgradeability proxy pattern * @dev This contract combines an upgradeability proxy with an authorization - * mechanism for administrative tasks. + * mechanism for administrative tasks. The admin role is stored in an immutable, which + * helps saving transactions costs * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. diff --git a/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol new file mode 100644 index 00000000..b290291b --- /dev/null +++ b/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; + +import './InitializableImmutableAdminUpgradeabilityProxy.sol'; +import '../openzeppelin-upgradeability/InitializableUpgradeabilityProxy.sol'; + +/** + * @title ERC20InitializableImmutableAdminUpgradeabilityProxy + * @dev Extends from BaseAdminUpgradeabilityProxy with an initializer for + * initializing the implementation, admin, and init data. + * It also implement native functions to map the ERC20 calls, to further save gas + * by directly calling the implementation. + */ +contract ERC20InitializableImmutableAdminUpgradeabilityProxy is + InitializableImmutableAdminUpgradeabilityProxy +{ + constructor(address admin) public InitializableImmutableAdminUpgradeabilityProxy(admin) {} + + function totalSupply() external view returns (uint256) { + abi.decode(_delegateView(abi.encodeWithSignature('totalSupply()')), (uint256)); + } + + function balanceOf(address account) external view returns (uint256) { + abi.decode(_delegateView(abi.encodeWithSignature('balanceOf(address)', account)), (uint256)); + } + + function transfer(address recipient, uint256 amount) external returns (bool) { + abi.decode( + _delegateToImpl(abi.encodeWithSignature('balanceOf(address,uint256)', recipient, amount)), + (bool) + ); + } + + function allowance(address owner, address spender) external view returns (uint256) { + abi.decode( + _delegateView(abi.encodeWithSignature('allowance(address,address)', owner, spender)), + (uint256) + ); + } + + function approve(address spender, uint256 amount) external returns (bool) { + abi.decode( + _delegateToImpl(abi.encodeWithSignature('approve(address,uint256)', spender, amount)), + (bool) + ); + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool) { + abi.decode( + _delegateToImpl( + abi.encodeWithSignature('transferFrom(address,address,uint256)', sender, recipient, amount) + ), + (bool) + ); + } + + /** + * @notice Delegates execution to an implementation contract + * @dev It returns to the external caller whatever the implementation returns or forwards reverts + * There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop. + * @param data The raw data to delegatecall + * @return The returned bytes from the delegatecall + */ + function _delegateView(bytes memory data) internal view returns (bytes memory) { + (bool success, bytes memory returnData) = address(this).staticcall( + abi.encodeWithSignature('delegateToImpl(bytes)', data) + ); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + return returnData; + } + + function _delegateToImpl(bytes memory data) internal returns (bytes memory) { + (bool success, bytes memory returnData) = _implementation().delegatecall(data); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + return returnData; + } +}