|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol) |
| 3 | + |
| 4 | +pragma solidity ^0.8.0; |
| 5 | + |
| 6 | +/** |
| 7 | + * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for |
| 8 | + * deploying minimal proxy contracts, also known as "clones". |
| 9 | + * |
| 10 | + * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies |
| 11 | + * > a minimal bytecode implementation that delegates all calls to a known, fixed address. |
| 12 | + * |
| 13 | + * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` |
| 14 | + * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the |
| 15 | + * deterministic method. |
| 16 | + * |
| 17 | + * _Available since v3.4._ |
| 18 | + */ |
| 19 | +library Clones { |
| 20 | + /** |
| 21 | + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. |
| 22 | + * |
| 23 | + * This function uses the create opcode, which should never revert. |
| 24 | + */ |
| 25 | + function clone(address implementation) internal returns (address instance) { |
| 26 | + /// @solidity memory-safe-assembly |
| 27 | + assembly { |
| 28 | + let ptr := mload(0x40) |
| 29 | + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) |
| 30 | + mstore(add(ptr, 0x14), shl(0x60, implementation)) |
| 31 | + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) |
| 32 | + instance := create(0, ptr, 0x37) |
| 33 | + } |
| 34 | + require(instance != address(0), "ERC1167: create failed"); |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. |
| 39 | + * |
| 40 | + * This function uses the create2 opcode and a `salt` to deterministically deploy |
| 41 | + * the clone. Using the same `implementation` and `salt` multiple time will revert, since |
| 42 | + * the clones cannot be deployed twice at the same address. |
| 43 | + */ |
| 44 | + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { |
| 45 | + /// @solidity memory-safe-assembly |
| 46 | + assembly { |
| 47 | + let ptr := mload(0x40) |
| 48 | + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) |
| 49 | + mstore(add(ptr, 0x14), shl(0x60, implementation)) |
| 50 | + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) |
| 51 | + instance := create2(0, ptr, 0x37, salt) |
| 52 | + } |
| 53 | + require(instance != address(0), "ERC1167: create2 failed"); |
| 54 | + } |
| 55 | + |
| 56 | + /** |
| 57 | + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. |
| 58 | + */ |
| 59 | + function predictDeterministicAddress( |
| 60 | + address implementation, |
| 61 | + bytes32 salt, |
| 62 | + address deployer |
| 63 | + ) internal pure returns (address predicted) { |
| 64 | + /// @solidity memory-safe-assembly |
| 65 | + assembly { |
| 66 | + let ptr := mload(0x40) |
| 67 | + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) |
| 68 | + mstore(add(ptr, 0x14), shl(0x60, implementation)) |
| 69 | + mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) |
| 70 | + mstore(add(ptr, 0x38), shl(0x60, deployer)) |
| 71 | + mstore(add(ptr, 0x4c), salt) |
| 72 | + mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) |
| 73 | + predicted := keccak256(add(ptr, 0x37), 0x55) |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. |
| 79 | + */ |
| 80 | + function predictDeterministicAddress(address implementation, bytes32 salt) |
| 81 | + internal |
| 82 | + view |
| 83 | + returns (address predicted) |
| 84 | + { |
| 85 | + return predictDeterministicAddress(implementation, salt, address(this)); |
| 86 | + } |
| 87 | +} |
0 commit comments