diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cfc73cab..f5aa30d8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,6 @@ ## Unreleased - * `Clones`: optimize clone creation ([#3329](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3329)) * `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) * `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380)) * `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327)) diff --git a/contracts/proxy/Clones.sol b/contracts/proxy/Clones.sol index 642cb1f1e..c83ad3144 100644 --- a/contracts/proxy/Clones.sol +++ b/contracts/proxy/Clones.sol @@ -26,10 +26,10 @@ library Clones { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) - mstore(add(ptr, 0x13), shl(0x60, implementation)) - mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create(0, ptr, 0x36) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(ptr, 0x14), shl(0x60, implementation)) + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } @@ -45,10 +45,10 @@ library Clones { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) - mstore(add(ptr, 0x13), shl(0x60, implementation)) - mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create2(0, ptr, 0x36, salt) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(ptr, 0x14), shl(0x60, implementation)) + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } @@ -64,13 +64,13 @@ library Clones { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) - mstore(add(ptr, 0x13), shl(0x60, implementation)) - mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) - mstore(add(ptr, 0x37), shl(0x60, deployer)) - mstore(add(ptr, 0x4b), salt) - mstore(add(ptr, 0x6b), keccak256(ptr, 0x36)) - predicted := keccak256(add(ptr, 0x36), 0x55) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(ptr, 0x14), shl(0x60, implementation)) + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) + mstore(add(ptr, 0x38), shl(0x60, deployer)) + mstore(add(ptr, 0x4c), salt) + mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) + predicted := keccak256(add(ptr, 0x37), 0x55) } } diff --git a/test/helpers/create2.js b/test/helpers/create2.js new file mode 100644 index 000000000..3e57764c8 --- /dev/null +++ b/test/helpers/create2.js @@ -0,0 +1,12 @@ +function computeCreate2Address (saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress(`0x${web3.utils.sha3(`0x${[ + 'ff', + deployer, + saltHex, + web3.utils.soliditySha3(bytecode), + ].map(x => x.replace(/0x/, '')).join('')}`).slice(-40)}`); +} + +module.exports = { + computeCreate2Address, +}; diff --git a/test/proxy/Clones.test.js b/test/proxy/Clones.test.js index 0f6a5de97..65e5ac11b 100644 --- a/test/proxy/Clones.test.js +++ b/test/proxy/Clones.test.js @@ -1,4 +1,6 @@ const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { computeCreate2Address } = require('../helpers/create2'); +const { expect } = require('chai'); const shouldBehaveLikeClone = require('./Clones.behaviour'); @@ -44,6 +46,19 @@ contract('Clones', function (accounts) { const salt = web3.utils.randomHex(32); const factory = await ClonesMock.new(); const predicted = await factory.predictDeterministicAddress(implementation, salt); + + const creationCode = [ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + implementation.replace(/0x/, '').toLowerCase(), + '5af43d82803e903d91602b57fd5bf3', + ].join(''); + + expect(computeCreate2Address( + salt, + creationCode, + factory.address, + )).to.be.equal(predicted); + expectEvent( await factory.cloneDeterministic(implementation, salt, '0x'), 'NewInstance', diff --git a/test/utils/Create2.test.js b/test/utils/Create2.test.js index cfc88c0bf..b57e06366 100644 --- a/test/utils/Create2.test.js +++ b/test/utils/Create2.test.js @@ -1,5 +1,5 @@ const { balance, BN, ether, expectRevert, send } = require('@openzeppelin/test-helpers'); - +const { computeCreate2Address } = require('../helpers/create2'); const { expect } = require('chai'); const Create2Impl = artifacts.require('Create2Impl'); @@ -90,12 +90,3 @@ contract('Create2', function (accounts) { }); }); }); - -function computeCreate2Address (saltHex, bytecode, deployer) { - return web3.utils.toChecksumAddress(`0x${web3.utils.sha3(`0x${[ - 'ff', - deployer, - saltHex, - web3.utils.soliditySha3(bytecode), - ].map(x => x.replace(/0x/, '')).join('')}`).slice(-40)}`); -}