-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: transparent proxy and proxy admin base
- Loading branch information
1 parent
45e4b91
commit b82d587
Showing
2 changed files
with
145 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol) | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
|
||
import { IEcoOwnable, EcoOwnable } from "../access/EcoOwnable.sol"; | ||
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | ||
|
||
interface IEcoProxyAdmin { | ||
function initEcoProxyAdmin(address initialOwner) external ; | ||
} | ||
|
||
/** | ||
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an | ||
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. | ||
*/ | ||
contract EcoProxyAdmin is IEcoProxyAdmin, EcoOwnable { | ||
/** | ||
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)` | ||
* and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, | ||
* while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string. | ||
* If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must | ||
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function | ||
* during an upgrade. | ||
*/ | ||
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; | ||
|
||
/** | ||
* @dev Sets the initial owner who can perform upgrades. | ||
*/ | ||
constructor(address initialOwner) { | ||
initEcoProxyAdmin(initialOwner); | ||
} | ||
|
||
function initEcoProxyAdmin(address initialOwner) public override initializer { | ||
initEcoOwnable(initialOwner); | ||
} | ||
|
||
/** | ||
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. | ||
* See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}. | ||
* | ||
* Requirements: | ||
* | ||
* - This contract must be the admin of `proxy`. | ||
* - If `data` is empty, `msg.value` must be zero. | ||
*/ | ||
function upgradeAndCall( | ||
ITransparentUpgradeableProxy proxy, | ||
address implementation, | ||
bytes memory data | ||
) public payable virtual onlyOwner { | ||
proxy.upgradeToAndCall{value: msg.value}(implementation, data); | ||
} | ||
} | ||
|
||
contract EcoProxyForProxyAdmin is ERC1967Proxy { | ||
constructor(address proxyAdminLogic, address initialOwner) | ||
ERC1967Proxy( | ||
proxyAdminLogic, | ||
abi.encodeWithSelector(IEcoProxyAdmin.initEcoProxyAdmin.selector, initialOwner) | ||
) | ||
{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import { ERC1967Utils } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; | ||
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | ||
import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
|
||
import { EcoProxyForProxyAdmin } from "./admin.sol"; | ||
|
||
// EcoTransparentUpgradeableProxy | ||
contract EcoTUPWithAdmin is ERC1967Proxy { | ||
// An immutable address for the admin to avoid unnecessary SLOADs before each call | ||
// at the expense of removing the ability to change the admin once it's set. | ||
// This is acceptable if the admin is always a ProxyAdmin instance or similar contract | ||
// with its own ability to transfer the permissions to another account. | ||
address private immutable _admin; | ||
|
||
/** | ||
* @dev The proxy caller is the current admin, and can't fallback to the proxy target. | ||
*/ | ||
error ProxyDeniedAdminAccess(); | ||
|
||
/** | ||
* @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`, | ||
* backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in | ||
* {ERC1967Proxy-constructor}. | ||
*/ | ||
constructor(address proxyAdmin, address _logic, bytes memory _data) payable | ||
ERC1967Proxy(_logic, _data) { | ||
_admin = proxyAdmin; | ||
// Set the storage value and emit an event for ERC-1967 compatibility | ||
ERC1967Utils.changeAdmin(_proxyAdmin()); | ||
} | ||
|
||
/** | ||
* @dev Returns the admin of this proxy. | ||
*/ | ||
function _proxyAdmin() internal virtual returns (address) { | ||
return _admin; | ||
} | ||
|
||
/** | ||
* @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 == _proxyAdmin()) { | ||
if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) { | ||
revert ProxyDeniedAdminAccess(); | ||
} else { | ||
_dispatchUpgradeToAndCall(); | ||
} | ||
} else { | ||
super._fallback(); | ||
} | ||
} | ||
|
||
/** | ||
* @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}. | ||
* | ||
* Requirements: | ||
* | ||
* - If `data` is empty, `msg.value` must be zero. | ||
*/ | ||
function _dispatchUpgradeToAndCall() private { | ||
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); | ||
ERC1967Utils.upgradeToAndCall(newImplementation, data); | ||
} | ||
} | ||
|
||
contract EcoTUPWithAdminLogic is EcoTUPWithAdmin { | ||
constructor(address proxyAdminLogic, address _logic, bytes memory _data) payable | ||
EcoTUPWithAdmin( | ||
address(new EcoProxyForProxyAdmin(proxyAdminLogic, msg.sender)), | ||
_logic, | ||
_data | ||
) {} | ||
} |