From 26e8148843d64cd47fed28c972393cd07f92ffb9 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 19 Jan 2025 09:53:33 +0100 Subject: [PATCH 1/2] fix: backport 5.1 fix --- src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol b/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol index a7c97dc..0cbb87c 100644 --- a/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol +++ b/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol @@ -92,7 +92,7 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Returns the admin of this proxy. */ - function _proxyAdmin() internal virtual returns (address) { + function _proxyAdmin() internal view virtual returns (address) { return _admin; } From bf06dcb53e9b95dddbb25930a5d4c60b0a32b52e Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 19 Jan 2025 10:30:58 +0100 Subject: [PATCH 2/2] feat: allow both variants --- .../TransparentProxyFactoryBase.sol | 64 +++++++++++++++++-- .../TransparentUpgradeableProxy.sol | 11 +++- .../interfaces/ITransparentProxyFactory.sol | 51 +++++++++++++++ 3 files changed, 119 insertions(+), 7 deletions(-) diff --git a/src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol b/src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol index 68ec22d..599696e 100644 --- a/src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol +++ b/src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol @@ -16,7 +16,25 @@ import {ProxyAdmin} from './ProxyAdmin.sol'; abstract contract TransparentProxyFactoryBase is ITransparentProxyFactory { /// @inheritdoc ITransparentProxyFactory function create(address logic, ProxyAdmin admin, bytes calldata data) external returns (address) { - address proxy = address(new TransparentUpgradeableProxy(logic, admin, data)); + return _create(logic, address(admin), data, true); + } + + /// @inheritdoc ITransparentProxyFactory + function createAndDeployNewAdmin( + address logic, + address initialOwner, + bytes calldata data + ) external returns (address) { + return _create(logic, initialOwner, data, false); + } + + function _create( + address logic, + address admin, + bytes calldata data, + bool reuseAdmin + ) internal returns (address) { + address proxy = address(new TransparentUpgradeableProxy(logic, admin, data, reuseAdmin)); emit ProxyCreated(proxy, logic, address(admin)); return proxy; @@ -37,9 +55,31 @@ abstract contract TransparentProxyFactoryBase is ITransparentProxyFactory { bytes calldata data, bytes32 salt ) external returns (address) { - address proxy = address(new TransparentUpgradeableProxy{salt: salt}(logic, admin, data)); + return _createDeterministic(logic, address(admin), data, true, salt); + } + + /// @inheritdoc ITransparentProxyFactory + function createDeterministicAndDeployNewAdmin( + address logic, + address initialOwner, + bytes calldata data, + bytes32 salt + ) external returns (address) { + return _createDeterministic(logic, initialOwner, data, false, salt); + } - emit ProxyDeterministicCreated(proxy, logic, address(admin), salt); + function _createDeterministic( + address logic, + address ownerOrAdmin, + bytes calldata data, + bool reuseAdmin, + bytes32 salt + ) internal returns (address) { + address proxy = address( + new TransparentUpgradeableProxy{salt: salt}(logic, ownerOrAdmin, data, reuseAdmin) + ); + + emit ProxyDeterministicCreated(proxy, logic, address(ownerOrAdmin), salt); return proxy; } @@ -66,7 +106,23 @@ abstract contract TransparentProxyFactoryBase is ITransparentProxyFactory { address(this), salt, type(TransparentUpgradeableProxy).creationCode, - abi.encode(logic, address(admin), data) + abi.encode(logic, address(admin), data, true) + ); + } + + /// @inheritdoc ITransparentProxyFactory + function predictCreateDeterministicAndDeployNewAdmin( + address logic, + address initialOwner, + bytes calldata data, + bytes32 salt + ) public view returns (address) { + return + _predictCreate2Address( + address(this), + salt, + type(TransparentUpgradeableProxy).creationCode, + abi.encode(logic, address(initialOwner), data, false) ); } diff --git a/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol b/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol index 0cbb87c..fe6289c 100644 --- a/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol +++ b/src/contracts/transparent-proxy/TransparentUpgradeableProxy.sol @@ -81,10 +81,15 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { */ constructor( address _logic, - ProxyAdmin initialOwner, - bytes memory _data + address ownerOrAdmin, + bytes memory _data, + bool useExistingAdmin ) payable ERC1967Proxy(_logic, _data) { - _admin = address(initialOwner); + if (useExistingAdmin) { + _admin = ownerOrAdmin; + } else { + _admin = address(new ProxyAdmin(ownerOrAdmin)); + } // Set the storage value and emit an event for ERC-1967 compatibility ERC1967Utils.changeAdmin(_proxyAdmin()); } diff --git a/src/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol b/src/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol index 52fe49c..65a5c6e 100644 --- a/src/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol +++ b/src/contracts/transparent-proxy/interfaces/ITransparentProxyFactory.sol @@ -30,6 +30,22 @@ interface ITransparentProxyFactory { **/ function create(address logic, ProxyAdmin admin, bytes memory data) external returns (address); + /** + * @notice Creates a transparent proxy instance, doing the first initialization in construction + * @dev Version using CREATE + * @param logic The address of the implementation contract + * @param initialOwner The initial owner of the admin deployed by the proxy. + * @param data abi encoded call to the function with `initializer` (or `reinitializer`) modifier. + * E.g. `abi.encodeWithSelector(mockImpl.initialize.selector, 2)` + * for an `initialize` function being `function initialize(uint256 foo) external initializer;` + * @return address The address of the proxy deployed + **/ + function createAndDeployNewAdmin( + address logic, + address initialOwner, + bytes memory data + ) external returns (address); + /** * @notice Creates a proxyAdmin instance, and transfers ownership to provided owner * @dev Version using CREATE @@ -56,6 +72,24 @@ interface ITransparentProxyFactory { bytes32 salt ) external returns (address); + /** + * @notice Creates a transparent proxy instance, doing the first initialization in construction + * @dev Version using CREATE2, so deterministic + * @param logic The address of the implementation contract + * @param initialOwner The initial owner of the admin deployed by the proxy. + * @param data abi encoded call to the function with `initializer` (or `reinitializer`) modifier. + * E.g. `abi.encodeWithSelector(mockImpl.initialize.selector, 2)` + * for an `initialize` function being `function initialize(uint256 foo) external initializer;` + * @param salt Value to be used in the address calculation, to be chosen by the account calling this function + * @return address The address of the proxy deployed + **/ + function createDeterministicAndDeployNewAdmin( + address logic, + address initialOwner, + bytes memory data, + bytes32 salt + ) external returns (address); + /** * @notice Deterministically create a proxy admin instance and transfers ownership to provided owner. * @dev Version using CREATE2, so deterministic @@ -85,6 +119,23 @@ interface ITransparentProxyFactory { bytes32 salt ) external view returns (address); + /** + * @notice Pre-calculates and return the address on which `createDeterministic` will deploy a proxy + * @param logic The address of the implementation contract + * @param initialOwner The initial owner of the admin deployed by the proxy + * @param data abi encoded call to the function with `initializer` (or `reinitializer`) modifier. + * E.g. `abi.encodeWithSelector(mockImpl.initialize.selector, 2)` + * for an `initialize` function being `function initialize(uint256 foo) external initializer;` + * @param salt Value to be used in the address calculation, to be chosen by the account calling this function + * @return address The pre-calculated address + **/ + function predictCreateDeterministicAndDeployNewAdmin( + address logic, + address initialOwner, + bytes calldata data, + bytes32 salt + ) external view returns (address); + /** * @notice Pre-calculates and return the address on which `createDeterministic` will deploy the proxyAdmin * @param salt Value to be used in the address calculation, to be chosen by the account calling this function