123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- // SPDX-License-Identifier: MIT
- // OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)
- pragma solidity ^0.8.20;
- import {Create2} from "../utils/Create2.sol";
- import {Errors} from "../utils/Errors.sol";
- /**
- * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
- * deploying minimal proxy contracts, also known as "clones".
- *
- * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
- * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
- *
- * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
- * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
- * deterministic method.
- */
- library Clones {
- error CloneArgumentsTooLong();
- /**
- * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
- *
- * This function uses the create opcode, which should never revert.
- */
- function clone(address implementation) internal returns (address instance) {
- return clone(implementation, 0);
- }
- /**
- * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
- * to the new contract.
- *
- * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
- * to always have enough balance for new deployments. Consider exposing this function under a payable method.
- */
- function clone(address implementation, uint256 value) internal returns (address instance) {
- if (address(this).balance < value) {
- revert Errors.InsufficientBalance(address(this).balance, value);
- }
- assembly ("memory-safe") {
- // 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(value, 0x09, 0x37)
- }
- if (instance == address(0)) {
- revert Errors.FailedDeployment();
- }
- }
- /**
- * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
- *
- * This function uses the create2 opcode and a `salt` to deterministically deploy
- * the clone. Using the same `implementation` and `salt` multiple times will revert, since
- * the clones cannot be deployed twice at the same address.
- */
- function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
- return cloneDeterministic(implementation, salt, 0);
- }
- /**
- * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
- * a `value` parameter to send native currency to the new contract.
- *
- * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
- * to always have enough balance for new deployments. Consider exposing this function under a payable method.
- */
- function cloneDeterministic(
- address implementation,
- bytes32 salt,
- uint256 value
- ) internal returns (address instance) {
- if (address(this).balance < value) {
- revert Errors.InsufficientBalance(address(this).balance, value);
- }
- assembly ("memory-safe") {
- // 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(value, 0x09, 0x37, salt)
- }
- if (instance == address(0)) {
- revert Errors.FailedDeployment();
- }
- }
- /**
- * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
- */
- function predictDeterministicAddress(
- address implementation,
- bytes32 salt,
- address deployer
- ) internal pure returns (address predicted) {
- assembly ("memory-safe") {
- let ptr := mload(0x40)
- 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 := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
- }
- }
- /**
- * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
- */
- function predictDeterministicAddress(
- address implementation,
- bytes32 salt
- ) internal view returns (address predicted) {
- return predictDeterministicAddress(implementation, salt, address(this));
- }
- /**
- * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
- * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
- * access the arguments within the implementation, use {fetchCloneArgs}.
- *
- * This function uses the create opcode, which should never revert.
- */
- function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
- return cloneWithImmutableArgs(implementation, args, 0);
- }
- /**
- * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
- * parameter to send native currency to the new contract.
- *
- * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
- * to always have enough balance for new deployments. Consider exposing this function under a payable method.
- */
- function cloneWithImmutableArgs(
- address implementation,
- bytes memory args,
- uint256 value
- ) internal returns (address instance) {
- if (address(this).balance < value) {
- revert Errors.InsufficientBalance(address(this).balance, value);
- }
- bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
- assembly ("memory-safe") {
- instance := create(value, add(bytecode, 0x20), mload(bytecode))
- }
- if (instance == address(0)) {
- revert Errors.FailedDeployment();
- }
- }
- /**
- * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
- * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
- * access the arguments within the implementation, use {fetchCloneArgs}.
- *
- * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
- * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
- * at the same address.
- */
- function cloneDeterministicWithImmutableArgs(
- address implementation,
- bytes memory args,
- bytes32 salt
- ) internal returns (address instance) {
- return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
- }
- /**
- * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
- * but with a `value` parameter to send native currency to the new contract.
- *
- * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
- * to always have enough balance for new deployments. Consider exposing this function under a payable method.
- */
- function cloneDeterministicWithImmutableArgs(
- address implementation,
- bytes memory args,
- bytes32 salt,
- uint256 value
- ) internal returns (address instance) {
- bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
- return Create2.deploy(value, salt, bytecode);
- }
- /**
- * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
- */
- function predictDeterministicAddressWithImmutableArgs(
- address implementation,
- bytes memory args,
- bytes32 salt,
- address deployer
- ) internal pure returns (address predicted) {
- bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
- return Create2.computeAddress(salt, keccak256(bytecode), deployer);
- }
- /**
- * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
- */
- function predictDeterministicAddressWithImmutableArgs(
- address implementation,
- bytes memory args,
- bytes32 salt
- ) internal view returns (address predicted) {
- return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
- }
- /**
- * @dev Get the immutable args attached to a clone.
- *
- * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
- * function will return an empty array.
- * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
- * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
- * creation.
- * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
- * function should only be used to check addresses that are known to be clones.
- */
- function fetchCloneArgs(address instance) internal view returns (bytes memory) {
- bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
- assembly ("memory-safe") {
- extcodecopy(instance, add(result, 32), 45, mload(result))
- }
- return result;
- }
- /**
- * @dev Helper that prepares the initcode of the proxy with immutable args.
- *
- * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
- * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
- * abi.encodePacked is more expensive but also more portable and easier to review.
- *
- * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
- * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
- */
- function _cloneCodeWithImmutableArgs(
- address implementation,
- bytes memory args
- ) private pure returns (bytes memory) {
- if (args.length > 24531) revert CloneArgumentsTooLong();
- return
- abi.encodePacked(
- hex"61",
- uint16(args.length + 45),
- hex"3d81600a3d39f3363d3d373d3d3d363d73",
- implementation,
- hex"5af43d82803e903d91602b57fd5bf3",
- args
- );
- }
- }
|