From c60c2d7ab1ebada72d76897c11dc9e5c64528102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20D=C3=ADaz?= Date: Thu, 16 Feb 2023 13:13:35 +0100 Subject: [PATCH] feat: enable proxiable implementations to be clonable as well --- contracts/impls/WitnetProxy.sol | 6 +- contracts/patterns/Clonable.sol | 15 +---- contracts/patterns/Proxiable.sol | 24 ++++++- contracts/patterns/Upgradeable.sol | 2 +- .../requests/WitnetRequestMalleableBase.sol | 62 +++++++++++-------- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/contracts/impls/WitnetProxy.sol b/contracts/impls/WitnetProxy.sol index 281958976..d640592a8 100644 --- a/contracts/impls/WitnetProxy.sol +++ b/contracts/impls/WitnetProxy.sol @@ -9,10 +9,6 @@ import "../patterns/Upgradeable.sol"; /// @author The Witnet Foundation. contract WitnetProxy { - struct WitnetProxySlot { - address implementation; - } - /// Event emitted every time the implementation gets updated. event Upgraded(address indexed implementation); @@ -110,7 +106,7 @@ contract WitnetProxy { } /// @dev Complying with EIP-1967, retrieves storage struct containing proxy's current implementation address. - function __proxySlot() private pure returns (WitnetProxySlot storage _slot) { + function __proxySlot() private pure returns (Proxiable.ProxiableSlot storage _slot) { assembly { // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) _slot.slot := 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc diff --git a/contracts/patterns/Clonable.sol b/contracts/patterns/Clonable.sol index 9776f7384..daa33b0a4 100644 --- a/contracts/patterns/Clonable.sol +++ b/contracts/patterns/Clonable.sol @@ -12,7 +12,7 @@ abstract contract Clonable event Cloned(address indexed by, address indexed self, address indexed clone); - modifier onlyDelegateCalls { + modifier onlyDelegateCalls virtual { require(address(this) != _SELF, "Clonable: not a delegate call"); _; } @@ -32,19 +32,6 @@ abstract contract Clonable ); } - /// Internal virtual function for initializing contract's storage - function _initialize(bytes memory) virtual internal; - - /// @notice Initializes a cloned instance. - /// @dev Every cloned instance can only get initialized once. - function initializeClone(bytes memory _initData) - external - initializer // => ensure a cloned instance can only be initialized once - onlyDelegateCalls // => this method can only be called upon cloned instances - { - _initialize(_initData); - } - /// @notice Tells whether this instance has been initialized. function initialized() virtual public view returns (bool); diff --git a/contracts/patterns/Proxiable.sol b/contracts/patterns/Proxiable.sol index 3b5470746..966c5802d 100644 --- a/contracts/patterns/Proxiable.sol +++ b/contracts/patterns/Proxiable.sol @@ -2,8 +2,28 @@ pragma solidity >=0.6.0 <0.9.0; -interface Proxiable { +abstract contract Proxiable { /// @dev Complying with EIP-1822: Universal Upgradeable Proxy Standard (UUPS) /// @dev See https://eips.ethereum.org/EIPS/eip-1822. - function proxiableUUID() external view returns (bytes32); + function proxiableUUID() virtual external view returns (bytes32); + + struct ProxiableSlot { + address implementation; + address proxy; + } + + function __implementation() internal view returns (address) { + return __proxiable().implementation; + } + + function __proxy() internal view returns (address) { + return __proxiable().proxy; + } + + function __proxiable() internal pure returns (ProxiableSlot storage proxiable) { + assembly { + // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) + proxiable.slot := 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc + } + } } diff --git a/contracts/patterns/Upgradeable.sol b/contracts/patterns/Upgradeable.sol index 7384b9559..74f913462 100644 --- a/contracts/patterns/Upgradeable.sol +++ b/contracts/patterns/Upgradeable.sol @@ -13,7 +13,7 @@ abstract contract Upgradeable is Initializable, Proxiable { bytes32 internal immutable _CODEHASH; bool internal immutable _UPGRADABLE; - modifier onlyDelegateCalls { + modifier onlyDelegateCalls virtual { require( address(this) != _BASE, "Upgradeable: not a delegate call" diff --git a/contracts/requests/WitnetRequestMalleableBase.sol b/contracts/requests/WitnetRequestMalleableBase.sol index 7026c6223..70c9e142a 100644 --- a/contracts/requests/WitnetRequestMalleableBase.sol +++ b/contracts/requests/WitnetRequestMalleableBase.sol @@ -190,6 +190,16 @@ abstract contract WitnetRequestMalleableBase return _afterCloning(_cloneDeterministic(_salt)); } + /// @notice Initializes a cloned instance. + /// @dev Every cloned instance can only get initialized once. + function initializeClone(bytes memory _initData) + virtual external + initializer // => ensure a cloned instance can only be initialized once + onlyDelegateCalls // => this method can only be called upon cloned instances + { + _initialize(_initData); + } + /// @notice Tells whether this instance has been initialized. function initialized() override @@ -199,32 +209,6 @@ abstract contract WitnetRequestMalleableBase return __storage().template.length > 0; } - /// @dev Initializes witnessing params and template bytecode. - function _initialize(bytes memory _template) - virtual override internal - initializer - { - _transferOwnership(_msgSender()); - - assert(_template.length > 0); - __storage().template = _template; - - WitnetRequestWitnessingParams storage _params = __storage().params; - _params.numWitnesses = 2; - _params.minWitnessingConsensus = 51; - _params.witnessingCollateral = 10 ** 9; // 1 WIT - _params.witnessingReward = 5 * 10 ** 5; // 0.5 milliWITs - _params.witnessingUnitaryFee = 25 * 10 ** 4; // 0.25 milliWITs - - _malleateBytecode( - _params.numWitnesses, - _params.minWitnessingConsensus, - _params.witnessingCollateral, - _params.witnessingReward, - _params.witnessingUnitaryFee - ); - } - // ================================================================================================================ // --- 'Ownable' overriden functions ------------------------------------------------------------------------------ @@ -278,6 +262,32 @@ abstract contract WitnetRequestMalleableBase return WitnetRequestMalleableBase(_newInstance); } + /// @dev Initializes witnessing params and template bytecode. + function _initialize(bytes memory _template) + virtual internal + initializer + { + _transferOwnership(_msgSender()); + + assert(_template.length > 0); + __storage().template = _template; + + WitnetRequestWitnessingParams storage _params = __storage().params; + _params.numWitnesses = 2; + _params.minWitnessingConsensus = 51; + _params.witnessingCollateral = 10 ** 9; // 1 WIT + _params.witnessingReward = 5 * 10 ** 5; // 0.5 milliWITs + _params.witnessingUnitaryFee = 25 * 10 ** 4; // 0.25 milliWITs + + _malleateBytecode( + _params.numWitnesses, + _params.minWitnessingConsensus, + _params.witnessingCollateral, + _params.witnessingReward, + _params.witnessingUnitaryFee + ); + } + /// @dev Serializes new `bytecode` by combining immutable template with given parameters. function _malleateBytecode( uint8 _numWitnesses,