From 2ca08f0e89426468a4297be3dfa967ec90a814f3 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Wed, 24 Aug 2022 17:25:52 +0800 Subject: [PATCH] Optimize Clones assembly (#3640) --- CHANGELOG.md | 1 + contracts/proxy/Clones.sol | 36 +++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e18691c7d60..29afc2a335d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * `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)) + * `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use lesser operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640)) ### Deprecations diff --git a/contracts/proxy/Clones.sol b/contracts/proxy/Clones.sol index 8d8dc13173e..505fd613ad3 100644 --- a/contracts/proxy/Clones.sol +++ b/contracts/proxy/Clones.sol @@ -25,11 +25,12 @@ library Clones { function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { - let ptr := mload(0x40) - mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(ptr, 0x14), shl(0x60, implementation)) - mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create(0, ptr, 0x37) + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } @@ -44,11 +45,12 @@ library Clones { function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { - let ptr := mload(0x40) - mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(ptr, 0x14), shl(0x60, implementation)) - mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create2(0, ptr, 0x37, salt) + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } @@ -64,13 +66,13 @@ library Clones { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - 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) + mstore(add(ptr, 0x38), deployer) + mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) + mstore(add(ptr, 0x14), implementation) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) + mstore(add(ptr, 0x58), salt) + mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) + predicted := keccak256(add(ptr, 0x43), 0x55) } }