From 177ee630285e8214e4ca74591beb46ffb2df7ae6 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:38:14 +0000 Subject: [PATCH] Update docs --- .changeset/thirty-shrimps-mix.md | 5 + contracts/interfaces/IERC1967.sol | 25 ++ contracts/mocks/ClashingImplementation.sol | 7 +- contracts/proxy/ERC1967/ERC1967Upgrade.sol | 18 +- contracts/proxy/transparent/ProxyAdmin.sol | 10 +- .../TransparentUpgradeableProxy.sol | 107 +++++-- docs/modules/api/pages/proxy.adoc | 270 +++++++----------- test/proxy/transparent/ProxyAdmin.test.js | 4 +- .../TransparentUpgradeableProxy.behaviour.js | 29 +- .../TransparentUpgradeableProxy.test.js | 4 +- 10 files changed, 262 insertions(+), 217 deletions(-) create mode 100644 .changeset/thirty-shrimps-mix.md create mode 100644 contracts/interfaces/IERC1967.sol diff --git a/.changeset/thirty-shrimps-mix.md b/.changeset/thirty-shrimps-mix.md new file mode 100644 index 000000000..656edbf92 --- /dev/null +++ b/.changeset/thirty-shrimps-mix.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. diff --git a/contracts/interfaces/IERC1967.sol b/contracts/interfaces/IERC1967.sol new file mode 100644 index 000000000..e5deebee9 --- /dev/null +++ b/contracts/interfaces/IERC1967.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + * + * _Available since v4.9._ + */ +interface IERC1967 { + /** + * @dev Emitted when the implementation is upgraded. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Emitted when the admin account has changed. + */ + event AdminChanged(address previousAdmin, address newAdmin); + + /** + * @dev Emitted when the beacon is changed. + */ + event BeaconUpgraded(address indexed beacon); +} diff --git a/contracts/mocks/ClashingImplementation.sol b/contracts/mocks/ClashingImplementation.sol index 80aca0c29..5c272a89d 100644 --- a/contracts/mocks/ClashingImplementation.sol +++ b/contracts/mocks/ClashingImplementation.sol @@ -3,12 +3,11 @@ pragma solidity ^0.8.0; /** - * @dev Implementation contract with an admin() function made to clash with - * @dev TransparentUpgradeableProxy's to test correct functioning of the - * @dev Transparent Proxy feature. + * @dev Implementation contract with a payable admin() function made to clash with TransparentUpgradeableProxy's to + * test correct functioning of the Transparent Proxy feature. */ contract ClashingImplementation { - function admin() external pure returns (address) { + function admin() external payable returns (address) { return 0x0000000000000000000000000000000011111142; } diff --git a/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/contracts/proxy/ERC1967/ERC1967Upgrade.sol index 77fbdd165..fdd532a3e 100644 --- a/contracts/proxy/ERC1967/ERC1967Upgrade.sol +++ b/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; +import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; @@ -16,7 +17,7 @@ import "../../utils/StorageSlot.sol"; * * @custom:oz-upgrades-unsafe-allow delegatecall */ -abstract contract ERC1967Upgrade { +abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; @@ -27,11 +28,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - /** - * @dev Emitted when the implementation is upgraded. - */ - event Upgraded(address indexed implementation); - /** * @dev Returns the current implementation address. */ @@ -105,11 +101,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; - /** - * @dev Emitted when the admin account has changed. - */ - event AdminChanged(address previousAdmin, address newAdmin); - /** * @dev Returns the current admin. */ @@ -141,11 +132,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; - /** - * @dev Emitted when the beacon is upgraded. - */ - event BeaconUpgraded(address indexed beacon); - /** * @dev Returns the current beacon. */ diff --git a/contracts/proxy/transparent/ProxyAdmin.sol b/contracts/proxy/transparent/ProxyAdmin.sol index 839534298..1a9698196 100644 --- a/contracts/proxy/transparent/ProxyAdmin.sol +++ b/contracts/proxy/transparent/ProxyAdmin.sol @@ -18,7 +18,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) { + function getProxyImplementation(ITransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); @@ -33,7 +33,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) { + function getProxyAdmin(ITransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); @@ -48,7 +48,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the current admin of `proxy`. */ - function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { + function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { proxy.changeAdmin(newAdmin); } @@ -59,7 +59,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { + function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { proxy.upgradeTo(implementation); } @@ -72,7 +72,7 @@ contract ProxyAdmin is Ownable { * - This contract must be the admin of `proxy`. */ function upgradeAndCall( - TransparentUpgradeableProxy proxy, + ITransparentUpgradeableProxy proxy, address implementation, bytes memory data ) public payable virtual onlyOwner { diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 4de85075a..909ef6405 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -5,6 +5,24 @@ pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; +/** + * @dev Interface for the {TransparentUpgradeableProxy}. This is useful because {TransparentUpgradeableProxy} uses a + * custom call-routing mechanism, the compiler is unaware of the functions being exposed, and cannot list them. Also + * {TransparentUpgradeableProxy} does not inherit from this interface because it's implemented in a way that the + * compiler doesn't understand and cannot verify. + */ +interface ITransparentUpgradeableProxy is IERC1967 { + function admin() external view returns (address); + + function implementation() external view returns (address); + + function changeAdmin(address) external; + + function upgradeTo(address) external; + + function upgradeToAndCall(address, bytes memory) external payable; +} + /** * @dev This contract implements a proxy that is upgradeable by an admin. * @@ -25,6 +43,13 @@ import "../ERC1967/ERC1967Proxy.sol"; * * 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 interface of your proxy. + * + * WARNING: This contract does not inherit from {ITransparentUpgradeableProxy}, and the admin function is implicitly + * implemented using a custom call-routing mechanism in `_fallback`. Consequently, the compiler will not produce an + * ABI for this contract. Also, if you inherit from this contract and add additional functions, the compiler will not + * check that there are no selector conflicts. A selector clash between any new function and the functions declared in + * {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could render the admin operations + * inaccessible, which could prevent upgradeability. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** @@ -41,6 +66,9 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. + * + * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the + * implementation provides a function with the same selector. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { @@ -50,61 +78,98 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { } } + /** + * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior + */ + function _fallback() internal virtual override { + if (msg.sender == _getAdmin()) { + bytes memory ret; + bytes4 selector = msg.sig; + if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) { + ret = _dispatchUpgradeTo(); + } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) { + ret = _dispatchUpgradeToAndCall(); + } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) { + ret = _dispatchChangeAdmin(); + } else if (selector == ITransparentUpgradeableProxy.admin.selector) { + ret = _dispatchAdmin(); + } else if (selector == ITransparentUpgradeableProxy.implementation.selector) { + ret = _dispatchImplementation(); + } else { + revert("TransparentUpgradeableProxy: admin cannot fallback to proxy target"); + } + assembly { + return(add(ret, 0x20), mload(ret)) + } + } else { + super._fallback(); + } + } + /** * @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 admin_) { - admin_ = _getAdmin(); + function _dispatchAdmin() private returns (bytes memory) { + _requireZeroValue(); + + address admin = _getAdmin(); + return abi.encode(admin); } /** * @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 implementation_) { - implementation_ = _implementation(); + function _dispatchImplementation() private returns (bytes memory) { + _requireZeroValue(); + + address implementation = _implementation(); + return abi.encode(implementation); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. - * - * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ - function changeAdmin(address newAdmin) external virtual ifAdmin { + function _dispatchChangeAdmin() private returns (bytes memory) { + _requireZeroValue(); + + address newAdmin = abi.decode(msg.data[4:], (address)); _changeAdmin(newAdmin); + + return ""; } /** * @dev Upgrade the implementation of the proxy. - * - * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ - function upgradeTo(address newImplementation) external ifAdmin { + function _dispatchUpgradeTo() private returns (bytes memory) { + _requireZeroValue(); + + address newImplementation = abi.decode(msg.data[4:], (address)); _upgradeToAndCall(newImplementation, bytes(""), false); + + return ""; } /** * @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 { + function _dispatchUpgradeToAndCall() private returns (bytes memory) { + (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); _upgradeToAndCall(newImplementation, data, true); + + return ""; } /** @@ -115,10 +180,10 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { } /** - * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. + * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to + * emulate some proxy functions being non-payable while still allowing value to pass through. */ - function _beforeFallback() internal virtual override { - require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); - super._beforeFallback(); + function _requireZeroValue() private { + require(msg.value == 0); } } diff --git a/docs/modules/api/pages/proxy.adoc b/docs/modules/api/pages/proxy.adoc index a6564875e..38c3c1bb2 100644 --- a/docs/modules/api/pages/proxy.adoc +++ b/docs/modules/api/pages/proxy.adoc @@ -35,9 +35,9 @@ :xref-Proxy-fallback--: xref:proxy.adoc#Proxy-fallback-- :xref-Proxy-receive--: xref:proxy.adoc#Proxy-receive-- :xref-Proxy-_beforeFallback--: xref:proxy.adoc#Proxy-_beforeFallback-- -:xref-ERC1967Upgrade-Upgraded-address-: xref:proxy.adoc#ERC1967Upgrade-Upgraded-address- -:xref-ERC1967Upgrade-AdminChanged-address-address-: xref:proxy.adoc#ERC1967Upgrade-AdminChanged-address-address- -:xref-ERC1967Upgrade-BeaconUpgraded-address-: xref:proxy.adoc#ERC1967Upgrade-BeaconUpgraded-address- +:xref-IERC1967-Upgraded-address-: xref:interfaces.adoc#IERC1967-Upgraded-address- +:xref-IERC1967-AdminChanged-address-address-: xref:interfaces.adoc#IERC1967-AdminChanged-address-address- +:xref-IERC1967-BeaconUpgraded-address-: xref:interfaces.adoc#IERC1967-BeaconUpgraded-address- :xref-ERC1967Upgrade-_getImplementation--: xref:proxy.adoc#ERC1967Upgrade-_getImplementation-- :xref-ERC1967Upgrade-_upgradeTo-address-: xref:proxy.adoc#ERC1967Upgrade-_upgradeTo-address- :xref-ERC1967Upgrade-_upgradeToAndCall-address-bytes-bool-: xref:proxy.adoc#ERC1967Upgrade-_upgradeToAndCall-address-bytes-bool- @@ -46,20 +46,17 @@ :xref-ERC1967Upgrade-_changeAdmin-address-: xref:proxy.adoc#ERC1967Upgrade-_changeAdmin-address- :xref-ERC1967Upgrade-_getBeacon--: xref:proxy.adoc#ERC1967Upgrade-_getBeacon-- :xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-: xref:proxy.adoc#ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool- -:xref-ERC1967Upgrade-Upgraded-address-: xref:proxy.adoc#ERC1967Upgrade-Upgraded-address- -:xref-ERC1967Upgrade-AdminChanged-address-address-: xref:proxy.adoc#ERC1967Upgrade-AdminChanged-address-address- -:xref-ERC1967Upgrade-BeaconUpgraded-address-: xref:proxy.adoc#ERC1967Upgrade-BeaconUpgraded-address- +:xref-IERC1967-Upgraded-address-: xref:interfaces.adoc#IERC1967-Upgraded-address- +:xref-IERC1967-AdminChanged-address-address-: xref:interfaces.adoc#IERC1967-AdminChanged-address-address- +:xref-IERC1967-BeaconUpgraded-address-: xref:interfaces.adoc#IERC1967-BeaconUpgraded-address- :UpgradeableBeacon-_setImplementation: pass:normal[xref:proxy.adoc#UpgradeableBeacon-_setImplementation-address-[`UpgradeableBeacon._setImplementation`]] :ProxyAdmin: pass:normal[xref:proxy.adoc#ProxyAdmin[`ProxyAdmin`]] +:ITransparentUpgradeableProxy: pass:normal[xref:proxy.adoc#ITransparentUpgradeableProxy[`ITransparentUpgradeableProxy`]] +:ITransparentUpgradeableProxy: pass:normal[xref:proxy.adoc#ITransparentUpgradeableProxy[`ITransparentUpgradeableProxy`]] :xref-TransparentUpgradeableProxy-ifAdmin--: xref:proxy.adoc#TransparentUpgradeableProxy-ifAdmin-- :xref-TransparentUpgradeableProxy-constructor-address-address-bytes-: xref:proxy.adoc#TransparentUpgradeableProxy-constructor-address-address-bytes- -:xref-TransparentUpgradeableProxy-admin--: xref:proxy.adoc#TransparentUpgradeableProxy-admin-- -:xref-TransparentUpgradeableProxy-implementation--: xref:proxy.adoc#TransparentUpgradeableProxy-implementation-- -:xref-TransparentUpgradeableProxy-changeAdmin-address-: xref:proxy.adoc#TransparentUpgradeableProxy-changeAdmin-address- -:xref-TransparentUpgradeableProxy-upgradeTo-address-: xref:proxy.adoc#TransparentUpgradeableProxy-upgradeTo-address- -:xref-TransparentUpgradeableProxy-upgradeToAndCall-address-bytes-: xref:proxy.adoc#TransparentUpgradeableProxy-upgradeToAndCall-address-bytes- +:xref-TransparentUpgradeableProxy-_fallback--: xref:proxy.adoc#TransparentUpgradeableProxy-_fallback-- :xref-TransparentUpgradeableProxy-_admin--: xref:proxy.adoc#TransparentUpgradeableProxy-_admin-- -:xref-TransparentUpgradeableProxy-_beforeFallback--: xref:proxy.adoc#TransparentUpgradeableProxy-_beforeFallback-- :xref-ERC1967Proxy-_implementation--: xref:proxy.adoc#ERC1967Proxy-_implementation-- :xref-ERC1967Upgrade-_getImplementation--: xref:proxy.adoc#ERC1967Upgrade-_getImplementation-- :xref-ERC1967Upgrade-_upgradeTo-address-: xref:proxy.adoc#ERC1967Upgrade-_upgradeTo-address- @@ -70,34 +67,26 @@ :xref-ERC1967Upgrade-_getBeacon--: xref:proxy.adoc#ERC1967Upgrade-_getBeacon-- :xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-: xref:proxy.adoc#ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool- :xref-Proxy-_delegate-address-: xref:proxy.adoc#Proxy-_delegate-address- -:xref-Proxy-_fallback--: xref:proxy.adoc#Proxy-_fallback-- :xref-Proxy-fallback--: xref:proxy.adoc#Proxy-fallback-- :xref-Proxy-receive--: xref:proxy.adoc#Proxy-receive-- -:xref-ERC1967Upgrade-Upgraded-address-: xref:proxy.adoc#ERC1967Upgrade-Upgraded-address- -:xref-ERC1967Upgrade-AdminChanged-address-address-: xref:proxy.adoc#ERC1967Upgrade-AdminChanged-address-address- -:xref-ERC1967Upgrade-BeaconUpgraded-address-: xref:proxy.adoc#ERC1967Upgrade-BeaconUpgraded-address- +:xref-Proxy-_beforeFallback--: xref:proxy.adoc#Proxy-_beforeFallback-- +:xref-IERC1967-Upgraded-address-: xref:interfaces.adoc#IERC1967-Upgraded-address- +:xref-IERC1967-AdminChanged-address-address-: xref:interfaces.adoc#IERC1967-AdminChanged-address-address- +:xref-IERC1967-BeaconUpgraded-address-: xref:interfaces.adoc#IERC1967-BeaconUpgraded-address- :ERC1967Proxy-constructor: pass:normal[xref:proxy.adoc#ERC1967Proxy-constructor-address-bytes-[`ERC1967Proxy.constructor`]] -:ProxyAdmin-getProxyAdmin: pass:normal[xref:proxy.adoc#ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy-[`ProxyAdmin.getProxyAdmin`]] -:ProxyAdmin-getProxyImplementation: pass:normal[xref:proxy.adoc#ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy-[`ProxyAdmin.getProxyImplementation`]] -:ProxyAdmin-changeProxyAdmin: pass:normal[xref:proxy.adoc#ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address-[`ProxyAdmin.changeProxyAdmin`]] -:ProxyAdmin-upgrade: pass:normal[xref:proxy.adoc#ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address-[`ProxyAdmin.upgrade`]] -:ProxyAdmin-upgradeAndCall: pass:normal[xref:proxy.adoc#ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes-[`ProxyAdmin.upgradeAndCall`]] -:Proxy-_beforeFallback: pass:normal[xref:proxy.adoc#Proxy-_beforeFallback--[`Proxy._beforeFallback`]] :TransparentUpgradeableProxy: pass:normal[xref:proxy.adoc#TransparentUpgradeableProxy[`TransparentUpgradeableProxy`]] :TransparentUpgradeableProxy: pass:normal[xref:proxy.adoc#TransparentUpgradeableProxy[`TransparentUpgradeableProxy`]] -:xref-ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy-: xref:proxy.adoc#ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy- -:xref-ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy-: xref:proxy.adoc#ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy- -:xref-ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address-: xref:proxy.adoc#ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address- -:xref-ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address-: xref:proxy.adoc#ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address- -:xref-ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes-: xref:proxy.adoc#ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes- +:xref-ProxyAdmin-getProxyImplementation-contract-ITransparentUpgradeableProxy-: xref:proxy.adoc#ProxyAdmin-getProxyImplementation-contract-ITransparentUpgradeableProxy- +:xref-ProxyAdmin-getProxyAdmin-contract-ITransparentUpgradeableProxy-: xref:proxy.adoc#ProxyAdmin-getProxyAdmin-contract-ITransparentUpgradeableProxy- +:xref-ProxyAdmin-changeProxyAdmin-contract-ITransparentUpgradeableProxy-address-: xref:proxy.adoc#ProxyAdmin-changeProxyAdmin-contract-ITransparentUpgradeableProxy-address- +:xref-ProxyAdmin-upgrade-contract-ITransparentUpgradeableProxy-address-: xref:proxy.adoc#ProxyAdmin-upgrade-contract-ITransparentUpgradeableProxy-address- +:xref-ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-: xref:proxy.adoc#ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes- :xref-Ownable-owner--: xref:access.adoc#Ownable-owner-- :xref-Ownable-_checkOwner--: xref:access.adoc#Ownable-_checkOwner-- :xref-Ownable-renounceOwnership--: xref:access.adoc#Ownable-renounceOwnership-- :xref-Ownable-transferOwnership-address-: xref:access.adoc#Ownable-transferOwnership-address- :xref-Ownable-_transferOwnership-address-: xref:access.adoc#Ownable-_transferOwnership-address- :xref-Ownable-OwnershipTransferred-address-address-: xref:access.adoc#Ownable-OwnershipTransferred-address-address- -:TransparentUpgradeableProxy-upgradeTo: pass:normal[xref:proxy.adoc#TransparentUpgradeableProxy-upgradeTo-address-[`TransparentUpgradeableProxy.upgradeTo`]] -:TransparentUpgradeableProxy-upgradeToAndCall: pass:normal[xref:proxy.adoc#TransparentUpgradeableProxy-upgradeToAndCall-address-bytes-[`TransparentUpgradeableProxy.upgradeToAndCall`]] :UpgradeableBeacon: pass:normal[xref:proxy.adoc#UpgradeableBeacon[`UpgradeableBeacon`]] :xref-BeaconProxy-constructor-address-bytes-: xref:proxy.adoc#BeaconProxy-constructor-address-bytes- :xref-BeaconProxy-_beacon--: xref:proxy.adoc#BeaconProxy-_beacon-- @@ -116,9 +105,9 @@ :xref-Proxy-fallback--: xref:proxy.adoc#Proxy-fallback-- :xref-Proxy-receive--: xref:proxy.adoc#Proxy-receive-- :xref-Proxy-_beforeFallback--: xref:proxy.adoc#Proxy-_beforeFallback-- -:xref-ERC1967Upgrade-Upgraded-address-: xref:proxy.adoc#ERC1967Upgrade-Upgraded-address- -:xref-ERC1967Upgrade-AdminChanged-address-address-: xref:proxy.adoc#ERC1967Upgrade-AdminChanged-address-address- -:xref-ERC1967Upgrade-BeaconUpgraded-address-: xref:proxy.adoc#ERC1967Upgrade-BeaconUpgraded-address- +:xref-IERC1967-Upgraded-address-: xref:interfaces.adoc#IERC1967-Upgraded-address- +:xref-IERC1967-AdminChanged-address-address-: xref:interfaces.adoc#IERC1967-AdminChanged-address-address- +:xref-IERC1967-BeaconUpgraded-address-: xref:interfaces.adoc#IERC1967-BeaconUpgraded-address- :IBeacon: pass:normal[xref:proxy.adoc#IBeacon[`IBeacon`]] :BeaconProxy: pass:normal[xref:proxy.adoc#BeaconProxy[`BeaconProxy`]] :xref-IBeacon-implementation--: xref:proxy.adoc#IBeacon-implementation-- @@ -163,9 +152,9 @@ :xref-ERC1967Upgrade-_changeAdmin-address-: xref:proxy.adoc#ERC1967Upgrade-_changeAdmin-address- :xref-ERC1967Upgrade-_getBeacon--: xref:proxy.adoc#ERC1967Upgrade-_getBeacon-- :xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-: xref:proxy.adoc#ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool- -:xref-ERC1967Upgrade-Upgraded-address-: xref:proxy.adoc#ERC1967Upgrade-Upgraded-address- -:xref-ERC1967Upgrade-AdminChanged-address-address-: xref:proxy.adoc#ERC1967Upgrade-AdminChanged-address-address- -:xref-ERC1967Upgrade-BeaconUpgraded-address-: xref:proxy.adoc#ERC1967Upgrade-BeaconUpgraded-address- +:xref-IERC1967-Upgraded-address-: xref:interfaces.adoc#IERC1967-Upgraded-address- +:xref-IERC1967-AdminChanged-address-address-: xref:interfaces.adoc#IERC1967-AdminChanged-address-address- +:xref-IERC1967-BeaconUpgraded-address-: xref:interfaces.adoc#IERC1967-BeaconUpgraded-address- :Ownable-onlyOwner: pass:normal[xref:access.adoc#Ownable-onlyOwner--[`Ownable.onlyOwner`]] = Proxies @@ -340,6 +329,9 @@ implementation behind the proxy. * {xref-ERC1967Upgrade-_getBeacon--}[`++_getBeacon()++`] * {xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-}[`++_upgradeBeaconToAndCall(newBeacon, data, forceCall)++`] +[.contract-subindex-inherited] +.IERC1967 + [.contract-subindex-inherited] .Proxy * {xref-Proxy-_delegate-address-}[`++_delegate(implementation)++`] @@ -356,9 +348,12 @@ implementation behind the proxy. [.contract-subindex-inherited] .ERC1967Upgrade -* {xref-ERC1967Upgrade-Upgraded-address-}[`++Upgraded(implementation)++`] -* {xref-ERC1967Upgrade-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] -* {xref-ERC1967Upgrade-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] + +[.contract-subindex-inherited] +.IERC1967 +* {xref-IERC1967-Upgraded-address-}[`++Upgraded(implementation)++`] +* {xref-IERC1967-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] +* {xref-IERC1967-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] [.contract-subindex-inherited] .Proxy @@ -382,19 +377,16 @@ Returns the current implementation address. :_ROLLBACK_SLOT: pass:normal[xref:#ERC1967Upgrade-_ROLLBACK_SLOT-bytes32[`++_ROLLBACK_SLOT++`]] :_IMPLEMENTATION_SLOT: pass:normal[xref:#ERC1967Upgrade-_IMPLEMENTATION_SLOT-bytes32[`++_IMPLEMENTATION_SLOT++`]] -:Upgraded: pass:normal[xref:#ERC1967Upgrade-Upgraded-address-[`++Upgraded++`]] :_getImplementation: pass:normal[xref:#ERC1967Upgrade-_getImplementation--[`++_getImplementation++`]] :_setImplementation: pass:normal[xref:#ERC1967Upgrade-_setImplementation-address-[`++_setImplementation++`]] :_upgradeTo: pass:normal[xref:#ERC1967Upgrade-_upgradeTo-address-[`++_upgradeTo++`]] :_upgradeToAndCall: pass:normal[xref:#ERC1967Upgrade-_upgradeToAndCall-address-bytes-bool-[`++_upgradeToAndCall++`]] :_upgradeToAndCallUUPS: pass:normal[xref:#ERC1967Upgrade-_upgradeToAndCallUUPS-address-bytes-bool-[`++_upgradeToAndCallUUPS++`]] :_ADMIN_SLOT: pass:normal[xref:#ERC1967Upgrade-_ADMIN_SLOT-bytes32[`++_ADMIN_SLOT++`]] -:AdminChanged: pass:normal[xref:#ERC1967Upgrade-AdminChanged-address-address-[`++AdminChanged++`]] :_getAdmin: pass:normal[xref:#ERC1967Upgrade-_getAdmin--[`++_getAdmin++`]] :_setAdmin: pass:normal[xref:#ERC1967Upgrade-_setAdmin-address-[`++_setAdmin++`]] :_changeAdmin: pass:normal[xref:#ERC1967Upgrade-_changeAdmin-address-[`++_changeAdmin++`]] :_BEACON_SLOT: pass:normal[xref:#ERC1967Upgrade-_BEACON_SLOT-bytes32[`++_BEACON_SLOT++`]] -:BeaconUpgraded: pass:normal[xref:#ERC1967Upgrade-BeaconUpgraded-address-[`++BeaconUpgraded++`]] :_getBeacon: pass:normal[xref:#ERC1967Upgrade-_getBeacon--[`++_getBeacon++`]] :_setBeacon: pass:normal[xref:#ERC1967Upgrade-_setBeacon-address-[`++_setBeacon++`]] :_upgradeBeaconToAndCall: pass:normal[xref:#ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-[`++_upgradeBeaconToAndCall++`]] @@ -425,14 +417,20 @@ _Available since v4.1._ * {xref-ERC1967Upgrade-_getBeacon--}[`++_getBeacon()++`] * {xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-}[`++_upgradeBeaconToAndCall(newBeacon, data, forceCall)++`] +[.contract-subindex-inherited] +.IERC1967 + -- [.contract-index] .Events -- -* {xref-ERC1967Upgrade-Upgraded-address-}[`++Upgraded(implementation)++`] -* {xref-ERC1967Upgrade-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] -* {xref-ERC1967Upgrade-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] + +[.contract-subindex-inherited] +.IERC1967 +* {xref-IERC1967-Upgraded-address-}[`++Upgraded(implementation)++`] +* {xref-IERC1967-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] +* {xref-IERC1967-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] -- @@ -495,35 +493,18 @@ not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_ Emits a {BeaconUpgraded} event. -[.contract-item] -[[ERC1967Upgrade-Upgraded-address-]] -==== `[.contract-item-name]#++Upgraded++#++(address indexed implementation)++` [.item-kind]#event# - -Emitted when the implementation is upgraded. - -[.contract-item] -[[ERC1967Upgrade-AdminChanged-address-address-]] -==== `[.contract-item-name]#++AdminChanged++#++(address previousAdmin, address newAdmin)++` [.item-kind]#event# - -Emitted when the admin account has changed. - -[.contract-item] -[[ERC1967Upgrade-BeaconUpgraded-address-]] -==== `[.contract-item-name]#++BeaconUpgraded++#++(address indexed beacon)++` [.item-kind]#event# - -Emitted when the beacon is upgraded. - == Transparent Proxy :constructor: pass:normal[xref:#TransparentUpgradeableProxy-constructor-address-address-bytes-[`++constructor++`]] :ifAdmin: pass:normal[xref:#TransparentUpgradeableProxy-ifAdmin--[`++ifAdmin++`]] -:admin: pass:normal[xref:#TransparentUpgradeableProxy-admin--[`++admin++`]] -:implementation: pass:normal[xref:#TransparentUpgradeableProxy-implementation--[`++implementation++`]] -:changeAdmin: pass:normal[xref:#TransparentUpgradeableProxy-changeAdmin-address-[`++changeAdmin++`]] -:upgradeTo: pass:normal[xref:#TransparentUpgradeableProxy-upgradeTo-address-[`++upgradeTo++`]] -:upgradeToAndCall: pass:normal[xref:#TransparentUpgradeableProxy-upgradeToAndCall-address-bytes-[`++upgradeToAndCall++`]] +:_fallback: pass:normal[xref:#TransparentUpgradeableProxy-_fallback--[`++_fallback++`]] +:_dispatchAdmin: pass:normal[xref:#TransparentUpgradeableProxy-_dispatchAdmin--[`++_dispatchAdmin++`]] +:_dispatchImplementation: pass:normal[xref:#TransparentUpgradeableProxy-_dispatchImplementation--[`++_dispatchImplementation++`]] +:_dispatchChangeAdmin: pass:normal[xref:#TransparentUpgradeableProxy-_dispatchChangeAdmin--[`++_dispatchChangeAdmin++`]] +:_dispatchUpgradeTo: pass:normal[xref:#TransparentUpgradeableProxy-_dispatchUpgradeTo--[`++_dispatchUpgradeTo++`]] +:_dispatchUpgradeToAndCall: pass:normal[xref:#TransparentUpgradeableProxy-_dispatchUpgradeToAndCall--[`++_dispatchUpgradeToAndCall++`]] :_admin: pass:normal[xref:#TransparentUpgradeableProxy-_admin--[`++_admin++`]] -:_beforeFallback: pass:normal[xref:#TransparentUpgradeableProxy-_beforeFallback--[`++_beforeFallback++`]] +:_requireZeroValue: pass:normal[xref:#TransparentUpgradeableProxy-_requireZeroValue--[`++_requireZeroValue++`]] [.contract] [[TransparentUpgradeableProxy]] @@ -554,6 +535,13 @@ 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 interface of your proxy. +WARNING: This contract does not inherit from {ITransparentUpgradeableProxy}, and the admin function is implicitly +implemented using a custom call-routing mechanism in `_fallback`. Consequently, the compiler will not produce an +ABI for this contract. Also, if you inherit from this contract and add additional functions, the compiler will not +check that there are no selector conflicts. A selector clash between any new function and the functions declared in +{ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could render the admin operations +inaccessible, which could prevent upgradeability. + [.contract-index] .Modifiers -- @@ -564,13 +552,8 @@ you should think of the `ProxyAdmin` instance as the real administrative interfa .Functions -- * {xref-TransparentUpgradeableProxy-constructor-address-address-bytes-}[`++constructor(_logic, admin_, _data)++`] -* {xref-TransparentUpgradeableProxy-admin--}[`++admin()++`] -* {xref-TransparentUpgradeableProxy-implementation--}[`++implementation()++`] -* {xref-TransparentUpgradeableProxy-changeAdmin-address-}[`++changeAdmin(newAdmin)++`] -* {xref-TransparentUpgradeableProxy-upgradeTo-address-}[`++upgradeTo(newImplementation)++`] -* {xref-TransparentUpgradeableProxy-upgradeToAndCall-address-bytes-}[`++upgradeToAndCall(newImplementation, data)++`] +* {xref-TransparentUpgradeableProxy-_fallback--}[`++_fallback()++`] * {xref-TransparentUpgradeableProxy-_admin--}[`++_admin()++`] -* {xref-TransparentUpgradeableProxy-_beforeFallback--}[`++_beforeFallback()++`] [.contract-subindex-inherited] .ERC1967Proxy @@ -587,12 +570,15 @@ you should think of the `ProxyAdmin` instance as the real administrative interfa * {xref-ERC1967Upgrade-_getBeacon--}[`++_getBeacon()++`] * {xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-}[`++_upgradeBeaconToAndCall(newBeacon, data, forceCall)++`] +[.contract-subindex-inherited] +.IERC1967 + [.contract-subindex-inherited] .Proxy * {xref-Proxy-_delegate-address-}[`++_delegate(implementation)++`] -* {xref-Proxy-_fallback--}[`++_fallback()++`] * {xref-Proxy-fallback--}[`++fallback()++`] * {xref-Proxy-receive--}[`++receive()++`] +* {xref-Proxy-_beforeFallback--}[`++_beforeFallback()++`] -- @@ -605,9 +591,12 @@ you should think of the `ProxyAdmin` instance as the real administrative interfa [.contract-subindex-inherited] .ERC1967Upgrade -* {xref-ERC1967Upgrade-Upgraded-address-}[`++Upgraded(implementation)++`] -* {xref-ERC1967Upgrade-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] -* {xref-ERC1967Upgrade-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] + +[.contract-subindex-inherited] +.IERC1967 +* {xref-IERC1967-Upgraded-address-}[`++Upgraded(implementation)++`] +* {xref-IERC1967-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] +* {xref-IERC1967-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] [.contract-subindex-inherited] .Proxy @@ -620,6 +609,9 @@ you should think of the `ProxyAdmin` instance as the real administrative interfa Modifier used internally that will delegate the call to the implementation unless the sender is the admin. +CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the +implementation provides a function with the same selector. + [.contract-item] [[TransparentUpgradeableProxy-constructor-address-address-bytes-]] ==== `[.contract-item-name]#++constructor++#++(address _logic, address admin_, bytes _data)++` [.item-kind]#public# @@ -628,56 +620,10 @@ Initializes an upgradeable proxy managed by `_admin`, backed by the implementati optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. [.contract-item] -[[TransparentUpgradeableProxy-admin--]] -==== `[.contract-item-name]#++admin++#++() → address admin_++` [.item-kind]#external# +[[TransparentUpgradeableProxy-_fallback--]] +==== `[.contract-item-name]#++_fallback++#++()++` [.item-kind]#internal# -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` - -[.contract-item] -[[TransparentUpgradeableProxy-implementation--]] -==== `[.contract-item-name]#++implementation++#++() → address implementation_++` [.item-kind]#external# - -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` - -[.contract-item] -[[TransparentUpgradeableProxy-changeAdmin-address-]] -==== `[.contract-item-name]#++changeAdmin++#++(address newAdmin)++` [.item-kind]#external# - -Changes the admin of the proxy. - -Emits an {AdminChanged} event. - -NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. - -[.contract-item] -[[TransparentUpgradeableProxy-upgradeTo-address-]] -==== `[.contract-item-name]#++upgradeTo++#++(address newImplementation)++` [.item-kind]#external# - -Upgrade the implementation of the proxy. - -NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. - -[.contract-item] -[[TransparentUpgradeableProxy-upgradeToAndCall-address-bytes-]] -==== `[.contract-item-name]#++upgradeToAndCall++#++(address newImplementation, bytes data)++` [.item-kind]#external# - -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}. +If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior [.contract-item] [[TransparentUpgradeableProxy-_admin--]] @@ -685,17 +631,11 @@ NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. Returns the current admin. -[.contract-item] -[[TransparentUpgradeableProxy-_beforeFallback--]] -==== `[.contract-item-name]#++_beforeFallback++#++()++` [.item-kind]#internal# - -Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. - -:getProxyImplementation: pass:normal[xref:#ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy-[`++getProxyImplementation++`]] -:getProxyAdmin: pass:normal[xref:#ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy-[`++getProxyAdmin++`]] -:changeProxyAdmin: pass:normal[xref:#ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address-[`++changeProxyAdmin++`]] -:upgrade: pass:normal[xref:#ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address-[`++upgrade++`]] -:upgradeAndCall: pass:normal[xref:#ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes-[`++upgradeAndCall++`]] +:getProxyImplementation: pass:normal[xref:#ProxyAdmin-getProxyImplementation-contract-ITransparentUpgradeableProxy-[`++getProxyImplementation++`]] +:getProxyAdmin: pass:normal[xref:#ProxyAdmin-getProxyAdmin-contract-ITransparentUpgradeableProxy-[`++getProxyAdmin++`]] +:changeProxyAdmin: pass:normal[xref:#ProxyAdmin-changeProxyAdmin-contract-ITransparentUpgradeableProxy-address-[`++changeProxyAdmin++`]] +:upgrade: pass:normal[xref:#ProxyAdmin-upgrade-contract-ITransparentUpgradeableProxy-address-[`++upgrade++`]] +:upgradeAndCall: pass:normal[xref:#ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-[`++upgradeAndCall++`]] [.contract] [[ProxyAdmin]] @@ -712,11 +652,11 @@ explanation of why you would want to use this see the documentation for {Transpa [.contract-index] .Functions -- -* {xref-ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy-}[`++getProxyImplementation(proxy)++`] -* {xref-ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy-}[`++getProxyAdmin(proxy)++`] -* {xref-ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address-}[`++changeProxyAdmin(proxy, newAdmin)++`] -* {xref-ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address-}[`++upgrade(proxy, implementation)++`] -* {xref-ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes-}[`++upgradeAndCall(proxy, implementation, data)++`] +* {xref-ProxyAdmin-getProxyImplementation-contract-ITransparentUpgradeableProxy-}[`++getProxyImplementation(proxy)++`] +* {xref-ProxyAdmin-getProxyAdmin-contract-ITransparentUpgradeableProxy-}[`++getProxyAdmin(proxy)++`] +* {xref-ProxyAdmin-changeProxyAdmin-contract-ITransparentUpgradeableProxy-address-}[`++changeProxyAdmin(proxy, newAdmin)++`] +* {xref-ProxyAdmin-upgrade-contract-ITransparentUpgradeableProxy-address-}[`++upgrade(proxy, implementation)++`] +* {xref-ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-}[`++upgradeAndCall(proxy, implementation, data)++`] [.contract-subindex-inherited] .Ownable @@ -739,8 +679,8 @@ explanation of why you would want to use this see the documentation for {Transpa -- [.contract-item] -[[ProxyAdmin-getProxyImplementation-contract-TransparentUpgradeableProxy-]] -==== `[.contract-item-name]#++getProxyImplementation++#++(contract TransparentUpgradeableProxy proxy) → address++` [.item-kind]#public# +[[ProxyAdmin-getProxyImplementation-contract-ITransparentUpgradeableProxy-]] +==== `[.contract-item-name]#++getProxyImplementation++#++(contract ITransparentUpgradeableProxy proxy) → address++` [.item-kind]#public# Returns the current implementation of `proxy`. @@ -749,8 +689,8 @@ Requirements: - This contract must be the admin of `proxy`. [.contract-item] -[[ProxyAdmin-getProxyAdmin-contract-TransparentUpgradeableProxy-]] -==== `[.contract-item-name]#++getProxyAdmin++#++(contract TransparentUpgradeableProxy proxy) → address++` [.item-kind]#public# +[[ProxyAdmin-getProxyAdmin-contract-ITransparentUpgradeableProxy-]] +==== `[.contract-item-name]#++getProxyAdmin++#++(contract ITransparentUpgradeableProxy proxy) → address++` [.item-kind]#public# Returns the current admin of `proxy`. @@ -759,8 +699,8 @@ Requirements: - This contract must be the admin of `proxy`. [.contract-item] -[[ProxyAdmin-changeProxyAdmin-contract-TransparentUpgradeableProxy-address-]] -==== `[.contract-item-name]#++changeProxyAdmin++#++(contract TransparentUpgradeableProxy proxy, address newAdmin)++` [.item-kind]#public# +[[ProxyAdmin-changeProxyAdmin-contract-ITransparentUpgradeableProxy-address-]] +==== `[.contract-item-name]#++changeProxyAdmin++#++(contract ITransparentUpgradeableProxy proxy, address newAdmin)++` [.item-kind]#public# Changes the admin of `proxy` to `newAdmin`. @@ -769,8 +709,8 @@ Requirements: - This contract must be the current admin of `proxy`. [.contract-item] -[[ProxyAdmin-upgrade-contract-TransparentUpgradeableProxy-address-]] -==== `[.contract-item-name]#++upgrade++#++(contract TransparentUpgradeableProxy proxy, address implementation)++` [.item-kind]#public# +[[ProxyAdmin-upgrade-contract-ITransparentUpgradeableProxy-address-]] +==== `[.contract-item-name]#++upgrade++#++(contract ITransparentUpgradeableProxy proxy, address implementation)++` [.item-kind]#public# Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. @@ -779,8 +719,8 @@ Requirements: - This contract must be the admin of `proxy`. [.contract-item] -[[ProxyAdmin-upgradeAndCall-contract-TransparentUpgradeableProxy-address-bytes-]] -==== `[.contract-item-name]#++upgradeAndCall++#++(contract TransparentUpgradeableProxy proxy, address implementation, bytes data)++` [.item-kind]#public# +[[ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-]] +==== `[.contract-item-name]#++upgradeAndCall++#++(contract ITransparentUpgradeableProxy proxy, address implementation, bytes data)++` [.item-kind]#public# Upgrades `proxy` to `implementation` and calls a function on the new implementation. See {TransparentUpgradeableProxy-upgradeToAndCall}. @@ -831,6 +771,9 @@ _Available since v3.4._ * {xref-ERC1967Upgrade-_getBeacon--}[`++_getBeacon()++`] * {xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-}[`++_upgradeBeaconToAndCall(newBeacon, data, forceCall)++`] +[.contract-subindex-inherited] +.IERC1967 + [.contract-subindex-inherited] .Proxy * {xref-Proxy-_delegate-address-}[`++_delegate(implementation)++`] @@ -847,9 +790,12 @@ _Available since v3.4._ [.contract-subindex-inherited] .ERC1967Upgrade -* {xref-ERC1967Upgrade-Upgraded-address-}[`++Upgraded(implementation)++`] -* {xref-ERC1967Upgrade-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] -* {xref-ERC1967Upgrade-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] + +[.contract-subindex-inherited] +.IERC1967 +* {xref-IERC1967-Upgraded-address-}[`++Upgraded(implementation)++`] +* {xref-IERC1967-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] +* {xref-IERC1967-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] [.contract-subindex-inherited] .Proxy @@ -1294,6 +1240,9 @@ _Available since v4.1._ * {xref-ERC1967Upgrade-_getBeacon--}[`++_getBeacon()++`] * {xref-ERC1967Upgrade-_upgradeBeaconToAndCall-address-bytes-bool-}[`++_upgradeBeaconToAndCall(newBeacon, data, forceCall)++`] +[.contract-subindex-inherited] +.IERC1967 + [.contract-subindex-inherited] .IERC1822Proxiable @@ -1305,9 +1254,12 @@ _Available since v4.1._ [.contract-subindex-inherited] .ERC1967Upgrade -* {xref-ERC1967Upgrade-Upgraded-address-}[`++Upgraded(implementation)++`] -* {xref-ERC1967Upgrade-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] -* {xref-ERC1967Upgrade-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] + +[.contract-subindex-inherited] +.IERC1967 +* {xref-IERC1967-Upgraded-address-}[`++Upgraded(implementation)++`] +* {xref-IERC1967-AdminChanged-address-address-}[`++AdminChanged(previousAdmin, newAdmin)++`] +* {xref-IERC1967-BeaconUpgraded-address-}[`++BeaconUpgraded(beacon)++`] [.contract-subindex-inherited] .IERC1822Proxiable diff --git a/test/proxy/transparent/ProxyAdmin.test.js b/test/proxy/transparent/ProxyAdmin.test.js index 07adba6ad..5187fb2a2 100644 --- a/test/proxy/transparent/ProxyAdmin.test.js +++ b/test/proxy/transparent/ProxyAdmin.test.js @@ -6,6 +6,7 @@ const ImplV1 = artifacts.require('DummyImplementation'); const ImplV2 = artifacts.require('DummyImplementationV2'); const ProxyAdmin = artifacts.require('ProxyAdmin'); const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); +const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy'); contract('ProxyAdmin', function (accounts) { const [proxyAdminOwner, newAdmin, anotherAccount] = accounts; @@ -18,12 +19,13 @@ contract('ProxyAdmin', function (accounts) { beforeEach(async function () { const initializeData = Buffer.from(''); this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner }); - this.proxy = await TransparentUpgradeableProxy.new( + const proxy = await TransparentUpgradeableProxy.new( this.implementationV1.address, this.proxyAdmin.address, initializeData, { from: proxyAdminOwner }, ); + this.proxy = await ITransparentUpgradeableProxy.at(proxy.address); }); it('has an owner', async function () { diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js index 33fef6f41..114b93887 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -34,7 +34,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro describe('implementation', function () { it('returns the current implementation address', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.implementationV0); }); @@ -55,7 +55,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro it('upgrades to the requested implementation', async function () { await this.proxy.upgradeTo(this.implementationV1, { from }); - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.implementationV1); }); @@ -108,7 +108,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro }); it('upgrades to the requested implementation', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behavior.address); }); @@ -173,7 +173,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV1.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); }); @@ -199,7 +199,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV2.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); }); @@ -228,7 +228,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV3.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); }); @@ -274,7 +274,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro }); it('assigns new proxy admin', async function () { - const newProxyAdmin = await this.proxy.admin.call({ from: newAdmin }); + const newProxyAdmin = await this.proxy.admin({ from: newAdmin }); expect(newProxyAdmin).to.be.equal(anotherAccount); }); @@ -333,14 +333,23 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro ); }); - context('when function names clash', function () { + describe('when function names clash', function () { it('when sender is proxy admin should run the proxy function', async function () { - const value = await this.proxy.admin.call({ from: proxyAdminAddress }); + const value = await this.proxy.admin({ from: proxyAdminAddress, value: 0 }); expect(value).to.be.equal(proxyAdminAddress); }); it('when sender is other should delegate to implementation', async function () { - const value = await this.proxy.admin.call({ from: anotherAccount }); + const value = await this.proxy.admin({ from: anotherAccount, value: 0 }); + expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); + }); + + it('when sender is proxy admin value should not be accepted', async function () { + await expectRevert.unspecified(this.proxy.admin({ from: proxyAdminAddress, value: 1 })); + }); + + it('when sender is other value should be accepted', async function () { + const value = await this.proxy.admin({ from: anotherAccount, value: 1 }); expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); }); }); diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/test/proxy/transparent/TransparentUpgradeableProxy.test.js index 86dd55d32..d60a31a21 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.test.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -2,12 +2,14 @@ const shouldBehaveLikeProxy = require('../Proxy.behaviour'); const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); +const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy'); contract('TransparentUpgradeableProxy', function (accounts) { const [proxyAdminAddress, proxyAdminOwner] = accounts; const createProxy = async function (logic, admin, initData, opts) { - return TransparentUpgradeableProxy.new(logic, admin, initData, opts); + const { address } = await TransparentUpgradeableProxy.new(logic, admin, initData, opts); + return ITransparentUpgradeableProxy.at(address); }; shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyAdminOwner);