diff --git a/contracts/src/proxy/Initializable.sol b/contracts/src/proxy/Initializable.sol index cdf8c7345..dc475b082 100644 --- a/contracts/src/proxy/Initializable.sol +++ b/contracts/src/proxy/Initializable.sol @@ -70,9 +70,9 @@ abstract contract Initializable { bool _initializing; } - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant _INITIALIZABLE_STORAGE = - 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0e; + 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. diff --git a/contracts/src/proxy/UUPSProxiable.sol b/contracts/src/proxy/UUPSProxiable.sol index 258a7a622..42cea2d2f 100644 --- a/contracts/src/proxy/UUPSProxiable.sol +++ b/contracts/src/proxy/UUPSProxiable.sol @@ -64,9 +64,9 @@ abstract contract UUPSProxiable { * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. - * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) + * NOTE: keccak256(abi.encode(uint256(keccak256("eip1967.proxy.implementation")) - 1)) & ~bytes32(uint256(0xff)) */ - bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + bytes32 private constant IMPLEMENTATION_SLOT = 0x75b20eef8615de99c108b05f0dbda081c91897128caa336d75dffb97c4132b00; /** * @dev Storage variable of the proxiable contract address. diff --git a/contracts/src/proxy/UUPSProxy.sol b/contracts/src/proxy/UUPSProxy.sol index f04f814e9..f52570a12 100644 --- a/contracts/src/proxy/UUPSProxy.sol +++ b/contracts/src/proxy/UUPSProxy.sol @@ -22,9 +22,9 @@ contract UUPSProxy { * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. - * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) + * NOTE: keccak256(abi.encode(uint256(keccak256("eip1967.proxy.implementation")) - 1)) & ~bytes32(uint256(0xff)) */ - bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + bytes32 private constant IMPLEMENTATION_SLOT = 0x75b20eef8615de99c108b05f0dbda081c91897128caa336d75dffb97c4132b00; // ************************************* // // * Constructor * // diff --git a/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol b/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol index 8133dd5c5..518660d42 100644 --- a/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol +++ b/contracts/src/proxy/mock/UUPSUpgradeableMocks.sol @@ -7,44 +7,76 @@ import "../UUPSProxiable.sol"; import "../Initializable.sol"; contract NonUpgradeableMock { - uint256 public _counter; + /// @custom:storage-location erc7201:kleros.storage.NonUpgradeableMockStorage + struct NonUpgradeableMockStorage { + uint256 counter; + } + // keccak256(abi.encode(uint256(keccak256("kleros.storage.NonUpgradeableMockStorage")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0x203890a1e96eaf39c35df205fbcedb580d4552ae7ac40780014dc281a7acd500; function counter() external view returns (uint256) { - return _counter; + NonUpgradeableMockStorage storage $ = _getNonUpgradeableMockStorage(); + return $.counter; } function increment() external { - _counter++; + NonUpgradeableMockStorage storage $ = _getNonUpgradeableMockStorage(); + $.counter++; } function version() external pure virtual returns (string memory) { return "NonUpgradeableMock 0.0.0"; } + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getNonUpgradeableMockStorage() private pure returns (NonUpgradeableMockStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } } contract UUPSUpgradeableMock is UUPSProxiable, NonUpgradeableMock { - bool public initialized; - address public governor; + /// @custom:storage-location erc7201:kleros.storage.UUPSUpgradeableMock + struct UUPSUpgradeableMockStorage { + bool initialized; + address governor; + } - uint256[50] __gap; + // keccak256(abi.encode(uint256(keccak256("kleros.storage.UUPSUpgradeableMock")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0x30d370aa3c43b12c906d59e729739fe781988b5aeb55fa9fb184b45129d6f900; constructor() { - initialized = true; + UUPSUpgradeableMockStorage storage $ = _getInitializableStorage(); + $.initialized = true; } function initialize(address _governor) external { - require(!initialized, "Contract instance has already been initialized"); - governor = _governor; - initialized = true; + UUPSUpgradeableMockStorage storage $ = _getInitializableStorage(); + require(!$.initialized, "Contract instance has already been initialized"); + $.governor = _governor; + $.initialized = true; } function _authorizeUpgrade(address) internal view override { - require(governor == msg.sender, "No privilege to upgrade"); + UUPSUpgradeableMockStorage storage $ = _getInitializableStorage(); + require($.governor == msg.sender, "No privilege to upgrade"); } function version() external pure virtual override returns (string memory) { return "UUPSUpgradeableMock 1.0.0"; } + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (UUPSUpgradeableMockStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } } contract UUPSUpgradeableMockV2 is UUPSUpgradeableMock { diff --git a/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol b/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol index 361b1e391..053f75619 100644 --- a/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol +++ b/contracts/src/proxy/mock/by-inheritance/UpgradedByInheritance.sol @@ -7,48 +7,86 @@ import "../../UUPSProxiable.sol"; import "../../Initializable.sol"; contract UpgradedByInheritanceV1 is UUPSProxiable, Initializable { - address public governor; - uint256 public counter; - uint256[50] __gap; + /// @custom:storage-location erc7201:kleros.storage.UpgradedByInheritance + struct UpgradedByInheritanceV1Storage { + address governor; + uint256 counter; + } + + // keccak256(abi.encode(uint256(keccak256("kleros.storage.UpgradedByInheritance")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 internal constant INITIALIZABLE_STORAGE = + 0xc17f29fd370bc39e93d9cb5467cf50e6788d12416f3c204ddea24c4b47412a00; constructor() { _disableInitializers(); } function initialize(address _governor) external virtual reinitializer(1) { - governor = _governor; - counter = 1; + UpgradedByInheritanceV1Storage storage $ = _getInheritanceV1Storage(); + $.governor = _governor; + $.counter = 1; } function _authorizeUpgrade(address) internal view override { - require(governor == msg.sender, "No privilege to upgrade"); + UpgradedByInheritanceV1Storage storage $ = _getInheritanceV1Storage(); + require($.governor == msg.sender, "No privilege to upgrade"); } function increment() external { - ++counter; + UpgradedByInheritanceV1Storage storage $ = _getInheritanceV1Storage(); + ++$.counter; } function version() external pure virtual returns (string memory) { return "V1"; } + function _getInheritanceV1Storage() private pure returns (UpgradedByInheritanceV1Storage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } + function governor() external view virtual returns (address) { + return _getInheritanceV1Storage().governor; + } + function counter() external view virtual returns (uint256) { + return _getInheritanceV1Storage().counter; + } } contract UpgradedByInheritanceV2 is UpgradedByInheritanceV1 { - string public newVariable; - uint256[50] __gap2; - + /// @custom:storage-location erc7201:kleros.storage.UpgradedByInheritance + struct UpgradedByInheritanceV2Storage { + address governor; + uint256 counter; + string newVariable; + } constructor() { _disableInitializers(); } function initializeV2(string memory _newVariable) external reinitializer(2) { - newVariable = _newVariable; + UpgradedByInheritanceV2Storage storage $ = _getInheritanceV2Storage(); + $.newVariable = _newVariable; this.increment(); } function version() external pure virtual override returns (string memory) { return "V2"; } + function _getInheritanceV2Storage() private pure returns (UpgradedByInheritanceV2Storage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } + function governor() external view virtual override returns (address) { + return _getInheritanceV2Storage().governor; + } + function counter() external view virtual override returns (uint256) { + return _getInheritanceV2Storage().counter; + } + function newVariable() external view returns (string memory) { + return _getInheritanceV2Storage().newVariable; + } } contract UpgradedByInheritanceV3Bad is UpgradedByInheritanceV2 { diff --git a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol index 91c75e0dc..aae329891 100644 --- a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol +++ b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewrite.sol @@ -7,31 +7,48 @@ import "../../UUPSProxiable.sol"; import "../../Initializable.sol"; contract UpgradedByRewrite is UUPSProxiable, Initializable { - //------------------------ - // V1 State - //------------------------ - address public governor; - uint256 public counter; - uint256[50] __gap; + /// @custom:storage-location erc7201:kleros.storage.UpgradedByRewriteStorage + struct UpgradedByRewriteStorage { + address governor; + uint256 counter; + } + + // keccak256(abi.encode(uint256(keccak256("kleros.storage.UpgradedByRewriteStorage")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xbe8e07ee0d0f4fb183890b4b70057ae173e7270304bf720861e275e28be01e00; constructor() { _disableInitializers(); } function initialize(address _governor) external virtual reinitializer(1) { - governor = _governor; - counter = 1; + UpgradedByRewriteStorage storage $ = _getUpgradedByRewriteStorage(); + $.governor = _governor; + $.counter = 1; } function _authorizeUpgrade(address) internal view override { - require(governor == msg.sender, "No privilege to upgrade"); + UpgradedByRewriteStorage storage $ = _getUpgradedByRewriteStorage(); + require($.governor == msg.sender, "No privilege to upgrade"); } function increment() external { - ++counter; + UpgradedByRewriteStorage storage $ = _getUpgradedByRewriteStorage(); + ++$.counter; } function version() external pure virtual returns (string memory) { return "V1"; } + function _getUpgradedByRewriteStorage() private pure returns (UpgradedByRewriteStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } + + function governor() external view returns (address) { + return _getUpgradedByRewriteStorage().governor; + } + function counter() external view returns (uint256) { + return _getUpgradedByRewriteStorage().counter; + } } diff --git a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol index 334a29fdf..0a6a468a0 100644 --- a/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol +++ b/contracts/src/proxy/mock/by-rewrite/UpgradedByRewriteV2.sol @@ -7,36 +7,52 @@ import "../../UUPSProxiable.sol"; import "../../Initializable.sol"; contract UpgradedByRewrite is UUPSProxiable, Initializable { - //------------------------ - // V1 State - //------------------------ - address public governor; - uint256 public counter; - uint256[50] __gap; - - //------------------------ - // V2 State - //------------------------ - string public newVariable; + /// @custom:storage-location erc7201:kleros.storage.UpgradedByRewriteStorage + struct UpgradedByRewriteV2 { + address governor; + uint256 counter; + string newVariable; + } + + // keccak256(abi.encode(uint256(keccak256("kleros.storage.UpgradedByRewriteStorage")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xbe8e07ee0d0f4fb183890b4b70057ae173e7270304bf720861e275e28be01e00; constructor() { _disableInitializers(); } function initialize(string memory _newVariable) external reinitializer(2) { - newVariable = _newVariable; + UpgradedByRewriteV2 storage $ = _getStorageUpgradedByRewrite(); + $.newVariable = _newVariable; this.increment(); } function _authorizeUpgrade(address) internal view override { - require(governor == msg.sender, "No privilege to upgrade"); + UpgradedByRewriteV2 storage $ = _getStorageUpgradedByRewrite(); + require($.governor == msg.sender, "No privilege to upgrade"); } function increment() external { - ++counter; + UpgradedByRewriteV2 storage $ = _getStorageUpgradedByRewrite(); + ++$.counter; } function version() external pure virtual returns (string memory) { return "V2"; } + + function _getStorageUpgradedByRewrite() private pure returns (UpgradedByRewriteV2 storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } + function governor() external view returns (address) { + return _getStorageUpgradedByRewrite().governor; + } + function counter() external view returns (uint256) { + return _getStorageUpgradedByRewrite().counter; + } + function newVariable() external view returns (string memory) { + return _getStorageUpgradedByRewrite().newVariable; + } }