@ -5,22 +5,30 @@ pragma solidity ^0.6.0;
import " ./UpgradeableProxy.sol " ;
/**
* @ title TransparentUpgradeableProxy
* @ 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 .
* @ dev This contract implements a proxy that is upgradeable by an admin .
*
* To avoid https : / / medium . com / nomic - labs - blog / malicious - backdoors - in - ethereum - proxies - 62629 adf3357 [ proxy selector
* clashing ] , which can potentially be used in an attack , this contract uses the
* https : / / blog . openzeppelin . com / the - transparent - proxy - pattern / [ transparent proxy pattern ] . This pattern implies two
* things that go hand in hand :
*
* 1 . If any account other than the admin calls the proxy , the call will be forwarded to the implementation , even if
* that call matches one of the admin functions exposed by the proxy itself .
* 2 . If the admin calls the proxy , it can access the admin functions , but its calls will never be forwarded to the
* implementation . If the admin tries to call a function on the implementation it will fail with an error that says
* " admin cannot fallback to proxy target " .
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin , so it ' s best if it ' s a dedicated account that is not used for anything else . This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation .
*
* Our recommendation is for the dedicated account to be an instance of the { ProxyAdmin } contract . If set up this way ,
* you should think of the ` ProxyAdmin ` instance as the real administrative inerface of your proxy .
* /
contract TransparentUpgradeableProxy is UpgradeableProxy {
/**
* 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 .
* @ dev Initializes an upgradeable proxy managed by ` _admin ` , backed by the implementation at ` _logic ` , and
* optionally initialized with ` _data ` as explained in { UpgradeableProxy - constructor } .
* /
constructor ( address _logic , address _admin , bytes memory _data ) public payable UpgradeableProxy ( _logic , _data ) {
assert ( _ADMIN_SLOT == bytes32 ( uint256 ( keccak256 ( " eip1967.proxy.admin " ) ) - 1 ) ) ;
@ -28,9 +36,7 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ dev Emitted when the administration has been transferred .
* @ param previousAdmin Address of the previous admin .
* @ param newAdmin Address of the new admin .
* @ dev Emitted when the admin account has changed .
* /
event AdminChanged ( address previousAdmin , address newAdmin ) ;
@ -39,13 +45,10 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
* This is the keccak - 256 hash of " eip1967.proxy.admin " subtracted by 1 , and is
* validated in the constructor .
* /
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 ;
/**
* @ dev Modifier to check whether the ` msg . sender ` is the admin .
* If it is , it will run the function . Otherwise , it will delegate the call
* to the implementation .
* @ dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin .
* /
modifier ifAdmin ( ) {
if ( msg . sender == _admin ( ) ) {
@ -56,14 +59,26 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ return The address of the proxy admin .
* @ dev Returns the current admin .
*
* NOTE : Only the admin can call this function . See { ProxyAdmin - getProxyAdmin } .
*
* TIP : To get this value clients can read directly from the storage slot shown below ( specified by EIP1967 ) using the
* https : / / eth . wiki / json - rpc / API # eth_getstorageat [ ` eth_getStorageAt ` ] RPC call .
* ` 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 `
* /
function admin ( ) external ifAdmin returns ( address ) {
return _admin ( ) ;
}
/**
* @ return The address of the implementation .
* @ dev Returns the current implementation .
*
* NOTE : Only the admin can call this function . See { ProxyAdmin - getProxyImplementation } .
*
* TIP : To get this value clients can read directly from the storage slot shown below ( specified by EIP1967 ) using the
* https : / / eth . wiki / json - rpc / API # eth_getstorageat [ ` eth_getStorageAt ` ] RPC call .
* ` 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc `
* /
function implementation ( ) external ifAdmin returns ( address ) {
return _implementation ( ) ;
@ -71,8 +86,10 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
/**
* @ dev Changes the admin of the proxy .
* Only the current admin can call this function .
* @ param newAdmin Address to transfer proxy administration to .
*
* Emits an { AdminChanged } event .
*
* NOTE : Only the admin can call this function . See { ProxyAdmin - changeProxyAdmin } .
* /
function changeAdmin ( address newAdmin ) external ifAdmin {
require ( newAdmin != address ( 0 ) , " TransparentUpgradeableProxy: new admin is the zero address " ) ;
@ -81,22 +98,20 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ dev Upgrade the backing implementation of the proxy .
* Only the admin can call this function .
* @ param newImplementation Address of the new implementation .
* @ dev Upgrade the implementation of the proxy .
*
* NOTE : Only the admin can call this function . See { ProxyAdmin - upgrade } .
* /
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 .
* @ dev Upgrade the implementation of the proxy , and then call a function from the new implementation as specified
* by ` data ` , which should be an encoded function call . This is useful to initialize new storage variables in the
* proxied contract .
*
* NOTE : Only the admin can call this function . See { ProxyAdmin - upgradeAndCall } .
* /
function upgradeToAndCall ( address newImplementation , bytes calldata data ) external payable ifAdmin {
_upgradeTo ( newImplementation ) ;
@ -106,7 +121,7 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ return adm The admin slot .
* @ dev Returns the current admin .
* /
function _admin ( ) internal view returns ( address adm ) {
bytes32 slot = _ADMIN_SLOT ;
@ -117,8 +132,7 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ dev Sets the address of the proxy admin .
* @ param newAdmin Address of the new proxy admin .
* @ dev Stores a new address in the EIP1967 admin slot .
* /
function _setAdmin ( address newAdmin ) internal {
bytes32 slot = _ADMIN_SLOT ;
@ -130,7 +144,7 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
}
/**
* @ dev Only fallback when the sender is not the admin .
* @ dev Makes sure the admin cannot access the fallback function . See { Proxy - _willFallback } .
* /
function _willFallback ( ) internal override virtual {
require ( msg . sender != _admin ( ) , " TransparentUpgradeableProxy: admin cannot fallback to proxy target " ) ;