From 6d8017d07ed88e5ea7063683df3d8d8110da6ba3 Mon Sep 17 00:00:00 2001 From: ToweringTopaz <87142001+ToweringTopaz@users.noreply.github.com> Date: Tue, 23 Aug 2022 15:38:13 -0500 Subject: [PATCH] Optimize Create2.computeAddress (#3600) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco --- CHANGELOG.md | 1 + contracts/utils/Create2.sol | 29 +++++++++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54573795..e18691c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605)) * `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591)) * `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580)) + * `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600)) ### Deprecations diff --git a/contracts/utils/Create2.sol b/contracts/utils/Create2.sol index b1e4ee15c..80acc3e2f 100644 --- a/contracts/utils/Create2.sol +++ b/contracts/utils/Create2.sol @@ -31,8 +31,7 @@ library Create2 { uint256 amount, bytes32 salt, bytes memory bytecode - ) internal returns (address) { - address addr; + ) internal returns (address addr) { require(address(this).balance >= amount, "Create2: insufficient balance"); require(bytecode.length != 0, "Create2: bytecode length is zero"); /// @solidity memory-safe-assembly @@ -40,7 +39,6 @@ library Create2 { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) } require(addr != address(0), "Create2: Failed on deploy"); - return addr; } /** @@ -59,8 +57,27 @@ library Create2 { bytes32 salt, bytes32 bytecodeHash, address deployer - ) internal pure returns (address) { - bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)); - return address(uint160(uint256(_data))); + ) internal pure returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) // Get free memory pointer + + // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | + // |-------------------|---------------------------------------------------------------------------| + // | bytecodeHash | CCCCCCCCCCCCC...CC | + // | salt | BBBBBBBBBBBBB...BB | + // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | + // | 0xFF | FF | + // |-------------------|---------------------------------------------------------------------------| + // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | + // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | + + mstore(add(ptr, 0x40), bytecodeHash) + mstore(add(ptr, 0x20), salt) + mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes + let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff + mstore8(start, 0xff) + addr := keccak256(start, 85) + } } }