From d681a212722475125973db757839930d47324419 Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 13 Oct 2020 10:28:52 +0200 Subject: [PATCH 1/5] Added immutable proxies --- .../BaseImmutableAdminUpgradeabilityProxy.sol | 80 +++++++++++++++++++ .../ImmutableAdminUpgradeabilityProxy.sol | 35 ++++++++ 2 files changed, 115 insertions(+) create mode 100644 contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol create mode 100644 contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol diff --git a/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol new file mode 100644 index 00000000..23a5f2eb --- /dev/null +++ b/contracts/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; + +import '../openzeppelin-upgradeability/BaseUpgradeabilityProxy.sol'; + +/** + * @title BaseAdminUpgradeabilityProxy + * @dev This contract combines an upgradeability proxy with an authorization + * mechanism for administrative tasks. + * 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. + */ +contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { + + address immutable ADMIN; + + constructor(address admin) public { + ADMIN = admin; + } + + modifier ifAdmin() { + if (msg.sender == ADMIN) { + _; + } else { + _fallback(); + } + } + + /** + * @return The address of the proxy admin. + */ + function admin() external ifAdmin returns (address) { + return ADMIN; + } + + /** + * @return The address of the implementation. + */ + function implementation() external ifAdmin returns (address) { + return _implementation(); + } + + /** + * @dev Upgrade the backing implementation of the proxy. + * Only the admin can call this function. + * @param newImplementation Address of the new implementation. + */ + function upgradeTo(address newImplementation) external ifAdmin { + _upgradeTo(newImplementation); + } + + /** + * @dev Upgrade the backing implementation of the proxy and call a function + * on the new implementation. + * This is useful to initialize the proxied contract. + * @param newImplementation Address of the new implementation. + * @param data Data to send as msg.data in the low level call. + * It should include the signature and the parameters of the function to be called, as described in + * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. + */ + function upgradeToAndCall(address newImplementation, bytes calldata data) + external + payable + ifAdmin + { + _upgradeTo(newImplementation); + (bool success, ) = newImplementation.delegatecall(data); + require(success); + } + + + /** + * @dev Only fall back when the sender is not the admin. + */ + function _willFallback() internal virtual override { + require(msg.sender != ADMIN, 'Cannot call fallback function from the proxy admin'); + super._willFallback(); + } +} diff --git a/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol new file mode 100644 index 00000000..5ee8f914 --- /dev/null +++ b/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; + +import './BaseImmutableAdminUpgradeabilityProxy.sol'; +import '../openzeppelin-upgradeability/UpgradeabilityProxy.sol'; + +/** + * @title AdminUpgradeabilityProxy + * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for + * initializing the implementation, admin, and init data. + */ +contract ImmutableAdminUpgradeabilityProxy is BaseImmutableAdminUpgradeabilityProxy, UpgradeabilityProxy { + /** + * Contract constructor. + * @param _logic address of the initial implementation. + * @param _admin Address of the proxy administrator. + * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. + * It should include the signature and the parameters of the function to be called, as described in + * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. + * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. + */ + constructor( + address _logic, + address _admin, + bytes memory _data + ) public payable UpgradeabilityProxy(_logic, _data) BaseImmutableAdminUpgradeabilityProxy(_admin) { + } + + /** + * @dev Only fall back when the sender is not the admin. + */ + function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) { + BaseImmutableAdminUpgradeabilityProxy._willFallback(); + } +} From 94c9b7156cc9504f9b02c1207b169a254222847f Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 13 Oct 2020 10:35:06 +0200 Subject: [PATCH 2/5] Added InitializableImmutableAdminUpgradeabilityProxy --- .../ImmutableAdminUpgradeabilityProxy.sol | 35 ------------------- ...zableImmutableAdminUpgradeabilityProxy.sol | 26 ++++++++++++++ 2 files changed, 26 insertions(+), 35 deletions(-) delete mode 100644 contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol create mode 100644 contracts/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol diff --git a/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol deleted file mode 100644 index 5ee8f914..00000000 --- a/contracts/libraries/aave-upgradeability/ImmutableAdminUpgradeabilityProxy.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity ^0.6.8; - -import './BaseImmutableAdminUpgradeabilityProxy.sol'; -import '../openzeppelin-upgradeability/UpgradeabilityProxy.sol'; - -/** - * @title AdminUpgradeabilityProxy - * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for - * initializing the implementation, admin, and init data. - */ -contract ImmutableAdminUpgradeabilityProxy is BaseImmutableAdminUpgradeabilityProxy, UpgradeabilityProxy { - /** - * Contract constructor. - * @param _logic address of the initial implementation. - * @param _admin Address of the proxy administrator. - * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. - * It should include the signature and the parameters of the function to be called, as described in - * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. - * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. - */ - constructor( - address _logic, - address _admin, - bytes memory _data - ) public payable UpgradeabilityProxy(_logic, _data) BaseImmutableAdminUpgradeabilityProxy(_admin) { - } - - /** - * @dev Only fall back when the sender is not the admin. - */ - function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) { - BaseImmutableAdminUpgradeabilityProxy._willFallback(); - } -} diff --git a/contracts/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol new file mode 100644 index 00000000..9e24d896 --- /dev/null +++ b/contracts/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; + +import './BaseImmutableAdminUpgradeabilityProxy.sol'; +import '../openzeppelin-upgradeability/InitializableUpgradeabilityProxy.sol'; + +/** + * @title InitializableAdminUpgradeabilityProxy + * @dev Extends from BaseAdminUpgradeabilityProxy with an initializer for + * initializing the implementation, admin, and init data. + */ +contract InitializableImmutableAdminUpgradeabilityProxy is + BaseImmutableAdminUpgradeabilityProxy, + InitializableUpgradeabilityProxy +{ + + constructor(address admin) public BaseImmutableAdminUpgradeabilityProxy(admin) { + } + + /** + * @dev Only fall back when the sender is not the admin. + */ + function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) { + BaseImmutableAdminUpgradeabilityProxy._willFallback(); + } +} From 6839be6dca68c3c2b06b62103de7c0e9473bf873 Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 13 Oct 2020 10:38:22 +0200 Subject: [PATCH 3/5] Updated addresses provider, configurator --- .../configuration/LendingPoolAddressesProvider.sol | 10 +++++----- contracts/lendingpool/LendingPoolConfigurator.sol | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/configuration/LendingPoolAddressesProvider.sol b/contracts/configuration/LendingPoolAddressesProvider.sol index 90fe8555..fed14236 100644 --- a/contracts/configuration/LendingPoolAddressesProvider.sol +++ b/contracts/configuration/LendingPoolAddressesProvider.sol @@ -3,8 +3,8 @@ pragma solidity ^0.6.8; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; import { - InitializableAdminUpgradeabilityProxy -} from '../libraries/openzeppelin-upgradeability/InitializableAdminUpgradeabilityProxy.sol'; + InitializableImmutableAdminUpgradeabilityProxy +} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; @@ -153,14 +153,14 @@ contract LendingPoolAddressesProvider is Ownable, ILendingPoolAddressesProvider function _updateImpl(bytes32 id, address newAddress) internal { address payable proxyAddress = payable(_addresses[id]); - InitializableAdminUpgradeabilityProxy proxy = InitializableAdminUpgradeabilityProxy( + InitializableImmutableAdminUpgradeabilityProxy proxy = InitializableImmutableAdminUpgradeabilityProxy( proxyAddress ); bytes memory params = abi.encodeWithSignature('initialize(address)', address(this)); if (proxyAddress == address(0)) { - proxy = new InitializableAdminUpgradeabilityProxy(); - proxy.initialize(newAddress, address(this), params); + proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this)); + proxy.initialize(newAddress, params); _addresses[id] = address(proxy); emit ProxyCreated(id, address(proxy)); } else { diff --git a/contracts/lendingpool/LendingPoolConfigurator.sol b/contracts/lendingpool/LendingPoolConfigurator.sol index 6bedff76..04d3d728 100644 --- a/contracts/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/lendingpool/LendingPoolConfigurator.sol @@ -7,8 +7,8 @@ import { VersionedInitializable } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; import { - InitializableAdminUpgradeabilityProxy -} from '../libraries/openzeppelin-upgradeability/InitializableAdminUpgradeabilityProxy.sol'; + InitializableImmutableAdminUpgradeabilityProxy +} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {ILendingPool} from '../interfaces/ILendingPool.sol'; @@ -559,7 +559,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param decimals the decimals of the token **/ function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) { - InitializableAdminUpgradeabilityProxy proxy = new InitializableAdminUpgradeabilityProxy(); + InitializableImmutableAdminUpgradeabilityProxy proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this)); bytes memory params = abi.encodeWithSignature( 'initialize(uint8,string,string)', @@ -568,7 +568,7 @@ contract LendingPoolConfigurator is VersionedInitializable { IERC20Detailed(implementation).symbol() ); - proxy.initialize(implementation, address(this), params); + proxy.initialize(implementation, params); return address(proxy); } @@ -578,7 +578,7 @@ contract LendingPoolConfigurator is VersionedInitializable { address proxyAddress, address implementation ) internal { - InitializableAdminUpgradeabilityProxy proxy = InitializableAdminUpgradeabilityProxy( + InitializableImmutableAdminUpgradeabilityProxy proxy = InitializableImmutableAdminUpgradeabilityProxy( payable(proxyAddress) ); From 1b4bc6f855da7ce5ca3b0a4fd6bcd7adc35c3efc Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 13 Oct 2020 13:21:11 +0200 Subject: [PATCH 4/5] 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; + } +} From 45f3c2613922dce5e79bb7d679a430e59e8afb98 Mon Sep 17 00:00:00 2001 From: The3D Date: Wed, 14 Oct 2020 13:55:38 +0200 Subject: [PATCH 5/5] Removed ERC20 proxy --- .../lendingpool/LendingPoolConfigurator.sol | 12 +-- ...zableImmutableAdminUpgradeabilityProxy.sol | 89 ------------------- 2 files changed, 6 insertions(+), 95 deletions(-) delete mode 100644 contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol diff --git a/contracts/lendingpool/LendingPoolConfigurator.sol b/contracts/lendingpool/LendingPoolConfigurator.sol index d6791034..cd64e586 100644 --- a/contracts/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/lendingpool/LendingPoolConfigurator.sol @@ -7,8 +7,8 @@ import { VersionedInitializable } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; import { - ERC20InitializableImmutableAdminUpgradeabilityProxy -} from '../libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol'; + InitializableImmutableAdminUpgradeabilityProxy +} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {ILendingPool} from '../interfaces/ILendingPool.sol'; @@ -559,8 +559,8 @@ contract LendingPoolConfigurator is VersionedInitializable { **/ function _initTokenWithProxy(address implementation, uint8 decimals) internal returns (address) { - ERC20InitializableImmutableAdminUpgradeabilityProxy proxy - = new ERC20InitializableImmutableAdminUpgradeabilityProxy(address(this)); + InitializableImmutableAdminUpgradeabilityProxy proxy + = new InitializableImmutableAdminUpgradeabilityProxy(address(this)); bytes memory params = abi.encodeWithSignature( 'initialize(uint8,string,string)', @@ -580,8 +580,8 @@ contract LendingPoolConfigurator is VersionedInitializable { address implementation ) internal { - ERC20InitializableImmutableAdminUpgradeabilityProxy proxy - = ERC20InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress)); + InitializableImmutableAdminUpgradeabilityProxy proxy + = InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress)); (uint256 decimals, , , , , , , , , , ) = pool.getReserveConfigurationData(asset); diff --git a/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol b/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol deleted file mode 100644 index b290291b..00000000 --- a/contracts/libraries/aave-upgradeability/ERC20InitializableImmutableAdminUpgradeabilityProxy.sol +++ /dev/null @@ -1,89 +0,0 @@ -// 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; - } -}