@@ -5,6 +5,24 @@ pragma solidity ^0.8.0;
55
66import "../ERC1967/ERC1967Proxy.sol " ;
77
8+ /**
9+ * @dev Interface for the {TransparentUpgradeableProxy}. This is useful because {TransparentUpgradeableProxy} uses a
10+ * custom call-routing mechanism, the compiler is unaware of the functions being exposed, and cannot list them. Also
11+ * {TransparentUpgradeableProxy} does not inherit from this interface because it's implemented in a way that the
12+ * compiler doesn't understand and cannot verify.
13+ */
14+ interface ITransparentUpgradeableProxy is IERC1967 {
15+ function admin () external view returns (address );
16+
17+ function implementation () external view returns (address );
18+
19+ function changeAdmin (address ) external ;
20+
21+ function upgradeTo (address ) external ;
22+
23+ function upgradeToAndCall (address , bytes memory ) external payable ;
24+ }
25+
826/**
927 * @dev This contract implements a proxy that is upgradeable by an admin.
1028 *
@@ -25,6 +43,13 @@ import "../ERC1967/ERC1967Proxy.sol";
2543 *
2644 * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
2745 * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
46+ *
47+ * WARNING: This contract does not inherit from {ITransparentUpgradeableProxy}, and the admin function is implicitly
48+ * implemented using a custom call-routing mechanism in `_fallback`. Consequently, the compiler will not produce an
49+ * ABI for this contract. Also, if you inherit from this contract and add additional functions, the compiler will not
50+ * check that there are no selector conflicts. A selector clash between any new function and the functions declared in
51+ * {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could render the admin operations
52+ * inaccessible, which could prevent upgradeability.
2853 */
2954contract TransparentUpgradeableProxy is ERC1967Proxy {
3055 /**
@@ -41,6 +66,9 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
4166
4267 /**
4368 * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
69+ *
70+ * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the
71+ * implementation provides a function with the same selector.
4472 */
4573 modifier ifAdmin () {
4674 if (msg .sender == _getAdmin ()) {
@@ -50,65 +78,98 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
5078 }
5179 }
5280
81+ /**
82+ * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior
83+ */
84+ function _fallback () internal virtual override {
85+ if (msg .sender == _getAdmin ()) {
86+ bytes memory ret;
87+ bytes4 selector = msg .sig ;
88+ if (selector == ITransparentUpgradeableProxy.upgradeTo.selector ) {
89+ ret = _dispatchUpgradeTo ();
90+ } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector ) {
91+ ret = _dispatchUpgradeToAndCall ();
92+ } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector ) {
93+ ret = _dispatchChangeAdmin ();
94+ } else if (selector == ITransparentUpgradeableProxy.admin.selector ) {
95+ ret = _dispatchAdmin ();
96+ } else if (selector == ITransparentUpgradeableProxy.implementation.selector ) {
97+ ret = _dispatchImplementation ();
98+ } else {
99+ revert ("TransparentUpgradeableProxy: admin cannot fallback to proxy target " );
100+ }
101+ assembly {
102+ return (add (ret, 0x20 ), mload (ret))
103+ }
104+ } else {
105+ super ._fallback ();
106+ }
107+ }
108+
53109 /**
54110 * @dev Returns the current admin.
55111 *
56- * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
57- *
58112 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
59113 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
60114 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
61115 */
62- function admin () external payable ifAdmin returns (address admin_ ) {
116+ function _dispatchAdmin () private returns (bytes memory ) {
63117 _requireZeroValue ();
64- admin_ = _getAdmin ();
118+
119+ address admin = _getAdmin ();
120+ return abi.encode (admin);
65121 }
66122
67123 /**
68124 * @dev Returns the current implementation.
69125 *
70- * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
71- *
72126 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
73127 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
74128 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
75129 */
76- function implementation () external payable ifAdmin returns (address implementation_ ) {
130+ function _dispatchImplementation () private returns (bytes memory ) {
77131 _requireZeroValue ();
78- implementation_ = _implementation ();
132+
133+ address implementation = _implementation ();
134+ return abi.encode (implementation);
79135 }
80136
81137 /**
82138 * @dev Changes the admin of the proxy.
83139 *
84140 * Emits an {AdminChanged} event.
85- *
86- * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
87141 */
88- function changeAdmin ( address newAdmin ) external payable virtual ifAdmin {
142+ function _dispatchChangeAdmin () private returns ( bytes memory ) {
89143 _requireZeroValue ();
144+
145+ address newAdmin = abi.decode (msg .data [4 :], (address ));
90146 _changeAdmin (newAdmin);
147+
148+ return "" ;
91149 }
92150
93151 /**
94152 * @dev Upgrade the implementation of the proxy.
95- *
96- * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
97153 */
98- function upgradeTo ( address newImplementation ) external payable ifAdmin {
154+ function _dispatchUpgradeTo () private returns ( bytes memory ) {
99155 _requireZeroValue ();
156+
157+ address newImplementation = abi.decode (msg .data [4 :], (address ));
100158 _upgradeToAndCall (newImplementation, bytes ("" ), false );
159+
160+ return "" ;
101161 }
102162
103163 /**
104164 * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
105165 * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
106166 * proxied contract.
107- *
108- * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
109167 */
110- function upgradeToAndCall (address newImplementation , bytes calldata data ) external payable ifAdmin {
168+ function _dispatchUpgradeToAndCall () private returns (bytes memory ) {
169+ (address newImplementation , bytes memory data ) = abi.decode (msg .data [4 :], (address , bytes ));
111170 _upgradeToAndCall (newImplementation, data, true );
171+
172+ return "" ;
112173 }
113174
114175 /**
@@ -118,14 +179,6 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
118179 return _getAdmin ();
119180 }
120181
121- /**
122- * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
123- */
124- function _beforeFallback () internal virtual override {
125- require (msg .sender != _getAdmin (), "TransparentUpgradeableProxy: admin cannot fallback to proxy target " );
126- super ._beforeFallback ();
127- }
128-
129182 /**
130183 * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to
131184 * emulate some proxy functions being non-payable while still allowing value to pass through.
0 commit comments