// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol) /// @author Minimal proxy by 0age (https://github.com/0age) /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) /// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy) /// /// @dev Minimal proxy: /// Although the sw0nt pattern saves 5 gas over the ERC1167 pattern during runtime, /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern, /// which saves 4 gas over the ERC1167 pattern during runtime, and has the smallest bytecode. /// - Automatically verified on Etherscan. /// /// @dev Minimal proxy (PUSH0 variant): /// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai. /// It is optimized first for minimal runtime gas, then for minimal bytecode. /// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as /// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai. /// Please use with caution. /// - Automatically verified on Etherscan. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here does NOT append the immutable args into the calldata /// passed into delegatecall. It is simply an ERC1167 minimal proxy with the immutable arguments /// appended to the back of the runtime bytecode. /// - Uses the identity precompile (0x4) to copy args during deployment. /// /// @dev Minimal ERC1967 proxy: /// A minimal ERC1967 proxy, intended to be upgraded with UUPS. /// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// - Automatically verified on Etherscan. /// /// @dev Minimal ERC1967 proxy with immutable args: /// - Uses the identity precompile (0x4) to copy args during deployment. /// - Automatically verified on Etherscan. /// /// @dev ERC1967I proxy: /// A variant of the minimal ERC1967 proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// `implementation` address. The returned implementation is guaranteed to be valid if the /// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`. /// /// @dev ERC1967I proxy with immutable args: /// A variant of the minimal ERC1967 proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// - Uses the identity precompile (0x4) to copy args during deployment. /// /// @dev Minimal ERC1967 beacon proxy: /// A minimal beacon proxy, intended to be upgraded with an upgradable beacon. /// - Automatically verified on Etherscan. /// /// @dev Minimal ERC1967 beacon proxy with immutable args: /// - Uses the identity precompile (0x4) to copy args during deployment. /// - Automatically verified on Etherscan. /// /// @dev ERC1967I beacon proxy: /// A variant of the minimal ERC1967 beacon proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// `implementation` address. The returned implementation is guaranteed to be valid if the /// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`. /// /// @dev ERC1967I proxy with immutable args: /// A variant of the minimal ERC1967 beacon proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// - Uses the identity precompile (0x4) to copy args during deployment. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The keccak256 of deployed code for the clone proxy, /// with the implementation set to `address(0)`. bytes32 internal constant CLONE_CODE_HASH = 0x48db2cfdb2853fce0b464f1f93a1996469459df3ab6c812106074c4106a1eb1f; /// @dev The keccak256 of deployed code for the PUSH0 proxy, /// with the implementation set to `address(0)`. bytes32 internal constant PUSH0_CLONE_CODE_HASH = 0x67bc6bde1b84d66e267c718ba44cf3928a615d29885537955cb43d44b3e789dc; /// @dev The keccak256 of deployed code for the ERC-1167 CWIA proxy, /// with the implementation set to `address(0)`. bytes32 internal constant CWIA_CODE_HASH = 0x3cf92464268225a4513da40a34d967354684c32cd0edd67b5f668dfe3550e940; /// @dev The keccak256 of the deployed code for the ERC1967 proxy. bytes32 internal constant ERC1967_CODE_HASH = 0xaaa52c8cc8a0e3fd27ce756cc6b4e70c51423e9b597b11f32d3e49f8b1fc890d; /// @dev The keccak256 of the deployed code for the ERC1967I proxy. bytes32 internal constant ERC1967I_CODE_HASH = 0xce700223c0d4cea4583409accfc45adac4a093b3519998a9cbbe1504dadba6f7; /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy. bytes32 internal constant ERC1967_BEACON_PROXY_CODE_HASH = 0x14044459af17bc4f0f5aa2f658cb692add77d1302c29fe2aebab005eea9d1162; /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy. bytes32 internal constant ERC1967I_BEACON_PROXY_CODE_HASH = 0xf8c46d2793d5aa984eb827aeaba4b63aedcab80119212fce827309788735519a; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the clone. error DeploymentFailed(); /// @dev The salt must start with either the zero address or `by`. error SaltDoesNotStartWith(); /// @dev The ETH transfer has failed. error ETHTransferFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation`. function clone(address implementation) internal returns (address instance) { instance = clone(0, implementation); } /// @dev Deploys a clone of `implementation`. /// Deposits `value` ETH during deployment. function clone(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (44 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | | * 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create(value, 0x0c, 0x35) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Deploys a deterministic clone of `implementation` with `salt`. function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic(0, implementation, salt); } /// @dev Deploys a deterministic clone of `implementation` with `salt`. /// Deposits `value` ETH during deployment. function cloneDeterministic(uint256 value, address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create2(value, 0x0c, 0x35, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the clone of `implementation`. function initCode(address implementation) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000) mstore(add(c, 0x28), implementation) mstore(add(c, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) mstore(c, 0x35) // Store the length. mstore(0x40, add(c, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation`. function initCodeHash(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) hash := keccak256(0x0c, 0x35) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the clone of `implementation`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a PUSH0 clone of `implementation`. function clone_PUSH0(address implementation) internal returns (address instance) { instance = clone_PUSH0(0, implementation); } /// @dev Deploys a PUSH0 clone of `implementation`. /// Deposits `value` ETH during deployment. function clone_PUSH0(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 5f | PUSH0 | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 5f | PUSH0 | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (45 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 5f | PUSH0 | 0 | | * 5f | PUSH0 | 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | | * 5f | PUSH0 | 0 cds 0 0 | | * 5f | PUSH0 | 0 0 cds 0 0 | | * 37 | CALLDATACOPY | 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | [0..cds): calldata | * 5f | PUSH0 | 0 cds 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success | [0..cds): calldata | * 5f | PUSH0 | 0 rds success | [0..cds): calldata | * 5f | PUSH0 | 0 0 rds success | [0..cds): calldata | * 3e | RETURNDATACOPY | success | [0..rds): returndata | * | * 60 0x29 | PUSH1 0x29 | 0x29 success | [0..rds): returndata | * 57 | JUMPI | | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..rds): returndata | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create(value, 0x0e, 0x36) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`. function cloneDeterministic_PUSH0(address implementation, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic_PUSH0(0, implementation, salt); } /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`. /// Deposits `value` ETH during deployment. function cloneDeterministic_PUSH0(uint256 value, address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create2(value, 0x0e, 0x36, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the PUSH0 clone of `implementation`. function initCode_PUSH0(address implementation) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16 mstore(add(c, 0x26), implementation) // 20 mstore(add(c, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 mstore(c, 0x36) // Store the length. mstore(0x40, add(c, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`. function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 hash := keccak256(0x0e, 0x36) mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the PUSH0 clone of `implementation`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress_PUSH0( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash_PUSH0(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CLONES WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`. function clone(address implementation, bytes memory args) internal returns (address instance) { instance = clone(0, implementation, args); } /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`. /// Deposits `value` ETH during deployment. function clone(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------+ * CREATION (10 bytes) | * ---------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------| * 61 runSize | PUSH2 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------| * RUNTIME (45 bytes + extraLength) | * ---------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 | [0..cds): calldata | * 82 | DUP3 | 0 rds success 0 | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 | [0..rds): returndata | * 90 | SWAP1 | 0 success | [0..rds): returndata | * 3d | RETURNDATASIZE | rds 0 success | [0..rds): returndata | * 91 | SWAP2 | success 0 rds | [0..rds): returndata | * | * 60 0x2b | PUSH1 0x2b | 0x2b success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * ---------------------------------------------------------------------------+ */ let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. instance := create(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. function cloneDeterministic(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic(0, implementation, args, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. function cloneDeterministic( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. instance := create2(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. /// This method does not revert if the clone has already been deployed. function createDeterministicClone(address implementation, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicClone(0, implementation, args, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. /// This method does not revert if the clone has already been deployed. function createDeterministicClone( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. // forgefmt: disable-next-item mstore(add(m, gt(n, 0xffd2)), add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x0c), add(n, 0x37))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x0c), add(n, 0x37), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the clone of `implementation` /// using immutable arguments encoded in `args`. function initCode(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x57), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x37), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(c, 0x28), implementation) mstore(add(c, 0x14), add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) mstore(c, add(0x37, n)) // Store the length. mstore(add(c, add(n, 0x57)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0x77))) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `args`. function initCodeHash(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x43), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) hash := keccak256(add(m, 0x0c), add(n, 0x37)) } } /// @dev Returns the address of the clone of /// `implementation` using immutable arguments encoded in `args`, with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( address implementation, bytes memory data, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation, data); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnClone(instance, 0, 2 ** 256 - 1)`. function argsOnClone(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x2d))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x2d, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnClone(instance, start, 2 ** 256 - 1)`. function argsOnClone(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x2d)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x0d), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the clone with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnClone(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x0d), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x2d) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: The ERC1967 proxy here is intended to be upgraded with UUPS. // This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// @dev Deploys a minimal ERC1967 proxy with `implementation`. function deployERC1967(address implementation) internal returns (address instance) { instance = deployERC1967(0, implementation); } /// @dev Deploys a minimal ERC1967 proxy with `implementation`. /// Deposits `value` ETH during deployment. function deployERC1967(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (61 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata | * 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata | * 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x38 | PUSH1 0x38 | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) instance := create(value, 0x21, 0x5f) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`. function deployDeterministicERC1967(address implementation, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967(0, implementation, salt); } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967(uint256 value, address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) instance := create2(value, 0x21, 0x5f, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967(address implementation, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967(0, implementation, salt); } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967(uint256 value, address implementation, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x21, 0x5f)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, 0x21, 0x5f, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`. function initCodeERC1967(address implementation) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x60), 0x3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f300) mstore(add(c, 0x40), 0x55f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc) mstore(add(c, 0x20), or(shl(24, implementation), 0x600951)) mstore(add(c, 0x09), 0x603d3d8160223d3973) mstore(c, 0x5f) // Store the length. mstore(0x40, add(c, 0x80)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`. function initCodeHashERC1967(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) hash := keccak256(0x21, 0x5f) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the ERC1967 proxy of `implementation`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`. function deployERC1967(address implementation, bytes memory args) internal returns (address instance) { instance = deployERC1967(0, implementation, args); } /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`. /// Deposits `value` ETH during deployment. function deployERC1967(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) instance := create(value, m, add(n, 0x60)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. function deployDeterministicERC1967(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967(0, implementation, args, salt); } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) instance := create2(value, m, add(n, 0x60), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967(address implementation, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967(0, implementation, args, salt); } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(m, add(n, 0x60))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, m, add(n, 0x60), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation` and `args`. function initCodeERC1967(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x80), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x60), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(c, 0x40), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(add(c, 0x20), 0x6009) mstore(add(c, 0x1e), implementation) mstore(add(c, 0x0a), add(0x61003d3d8160233d3973, shl(56, n))) mstore(c, add(n, 0x60)) // Store the length. mstore(add(c, add(n, 0x80)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0xa0))) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation` and `args`. function initCodeHashERC1967(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x60), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) mstore(0x00, add(0x61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) hash := keccak256(m, add(n, 0x60)) } } /// @dev Returns the address of the ERC1967 proxy of `implementation`, `args`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967( address implementation, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967(implementation, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`. function argsOnERC1967(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x3d))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x3d, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`. function argsOnERC1967(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x3d)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x1d), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x1d), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x3d) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This proxy has a special code path that activates if `calldatasize() == 1`. // This code path skips the delegatecall and directly returns the `implementation` address. // The returned implementation is guaranteed to be valid if the keccak256 of the // proxy's code is equal to `ERC1967I_CODE_HASH`. /// @dev Deploys a ERC1967I proxy with `implementation`. function deployERC1967I(address implementation) internal returns (address instance) { instance = deployERC1967I(0, implementation); } /// @dev Deploys a ERC1967I proxy with `implementation`. /// Deposits `value` ETH during deployment. function deployERC1967I(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (82 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: check calldatasize ::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 58 | PC | 1 cds | | * 14 | EQ | eqs | | * 60 0x43 | PUSH1 0x43 | dest eqs | | * 57 | JUMPI | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata | * 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata | * 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x3E | PUSH1 0x3E | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * | * ::: implementation , return :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | | * 60 0x20 | PUSH1 0x20 | 32 | | * 60 0x0F | PUSH1 0x0F | o 32 | | * 3d | RETURNDATASIZE | 0 o 32 | | * 39 | CODECOPY | | [0..32): implementation slot | * 3d | RETURNDATASIZE | 0 | [0..32): implementation slot | * 51 | MLOAD | slot | [0..32): implementation slot | * 54 | SLOAD | impl | [0..32): implementation slot | * 3d | RETURNDATASIZE | 0 impl | [0..32): implementation slot | * 52 | MSTORE | | [0..32): implementation address | * 59 | MSIZE | 32 | [0..32): implementation address | * 3d | RETURNDATASIZE | 0 32 | [0..32): implementation address | * f3 | RETURN | | [0..32): implementation address | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) instance := create(value, 0x0c, 0x74) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`. function deployDeterministicERC1967I(address implementation, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967I(0, implementation, salt); } /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967I(uint256 value, address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I(address implementation, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967I(0, implementation, salt); } /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I(uint256 value, address implementation, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x0c, 0x74)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the ERC1967I proxy of `implementation`. function initCodeERC1967I(address implementation) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x74), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(c, 0x54), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(c, 0x34), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(c, 0x1d), implementation) mstore(add(c, 0x09), 0x60523d8160223d3973) mstore(add(c, 0x94), 0) mstore(c, 0x74) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation`. function initCodeHashERC1967I(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) hash := keccak256(0x0c, 0x74) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the ERC1967I proxy of `implementation`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967I( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967I(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`. function deployERC1967I(address implementation, bytes memory args) internal returns (address) { return deployERC1967I(0, implementation, args); } /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`. /// Deposits `value` ETH during deployment. function deployERC1967I(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe6100523d8160233d3973, shl(56, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. instance := create(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic ERC1967I proxy with `implementation`, `args`, and `salt`. function deployDeterministicERC1967I(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967I(0, implementation, args, salt); } /// @dev Deploys a deterministic ERC1967I proxy with `implementation`, `args`, and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967I( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe6100523d8160233d3973, shl(56, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. instance := create2(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic ERC1967I proxy with `implementation`, `args` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I(address implementation, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967I(0, implementation, args, salt); } /// @dev Creates a deterministic ERC1967I proxy with `implementation`, `args` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x75), n)) mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894) mstore(0x16, 0x600f) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(gt(n, 0xffad), add(0xfe6100523d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(m, add(n, 0x75))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, m, add(0x75, n), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the ERC1967I proxy of `implementation` and `args`. function initCodeERC1967I(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x75), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(c, 0x55), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(c, 0x35), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(c, 0x1e), implementation) mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n))) mstore(add(c, add(n, 0x95)), 0) mstore(c, add(0x75, n)) // Store the length. mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation` and `args. function initCodeHashERC1967I(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x75), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894) mstore(0x16, 0x600f) mstore(0x14, implementation) mstore(0x00, add(0x6100523d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) hash := keccak256(m, add(0x75, n)) } } /// @dev Returns the address of the ERC1967I proxy of `implementation`, `args` with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967I( address implementation, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967I(implementation, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`. function argsOnERC1967I(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x52))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`. function argsOnERC1967I(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x52)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x32), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967I(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x32), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x52) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967 BOOTSTRAP OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A bootstrap is a minimal UUPS implementation that allows an ERC1967 proxy // pointing to it to be upgraded. The ERC1967 proxy can then be deployed to a // deterministic address independent of the implementation: // ``` // address bootstrap = LibClone.erc1967Bootstrap(); // address instance = LibClone.deployDeterministicERC1967(0, bootstrap, salt); // LibClone.bootstrapERC1967(bootstrap, implementation); // ``` /// @dev Deploys the ERC1967 bootstrap if it has not been deployed. function erc1967Bootstrap() internal returns (address) { return erc1967Bootstrap(address(this)); } /// @dev Deploys the ERC1967 bootstrap if it has not been deployed. function erc1967Bootstrap(address authorizedUpgrader) internal returns (address bootstrap) { bytes memory c = initCodeERC1967Bootstrap(authorizedUpgrader); bootstrap = predictDeterministicAddress(keccak256(c), bytes32(0), address(this)); /// @solidity memory-safe-assembly assembly { if iszero(extcodesize(bootstrap)) { if iszero(create2(0, add(c, 0x20), mload(c), 0)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } } /// @dev Replaces the implementation at `instance`. function bootstrapERC1967(address instance, address implementation) internal { /// @solidity memory-safe-assembly assembly { mstore(0x00, implementation) if iszero(call(gas(), instance, 0, 0x0c, 0x14, codesize(), 0x00)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Replaces the implementation at `instance`, and then call it with `data`. function bootstrapERC1967AndCall(address instance, address implementation, bytes memory data) internal { /// @solidity memory-safe-assembly assembly { let n := mload(data) mstore(data, implementation) if iszero(call(gas(), instance, 0, add(data, 0x0c), add(n, 0x14), codesize(), 0x00)) { if iszero(returndatasize()) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } mstore(data, n) // Restore the length of `data`. } } /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract. function predictDeterministicAddressERC1967Bootstrap() internal view returns (address) { return predictDeterministicAddressERC1967Bootstrap(address(this), address(this)); } /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract. function predictDeterministicAddressERC1967Bootstrap( address authorizedUpgrader, address deployer ) internal pure returns (address) { bytes32 hash = initCodeHashERC1967Bootstrap(authorizedUpgrader); return predictDeterministicAddress(hash, bytes32(0), deployer); } /// @dev Returns the initialization code of the ERC1967 bootstrap. function initCodeERC1967Bootstrap(address authorizedUpgrader) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x80), 0x3d3560601c5af46047573d6000383e3d38fd0000000000000000000000000000) mstore(add(c, 0x60), 0xa920a3ca505d382bbc55601436116049575b005b363d3d373d3d601436036014) mstore(add(c, 0x40), 0x0338573d3560601c7f360894a13ba1a3210667c828492db98dca3e2076cc3735) mstore(add(c, 0x20), authorizedUpgrader) mstore(add(c, 0x0c), 0x606880600a3d393df3fe3373) mstore(c, 0x72) mstore(0x40, add(c, 0xa0)) } } /// @dev Returns the initialization code hash of the ERC1967 bootstrap. function initCodeHashERC1967Bootstrap(address authorizedUpgrader) internal pure returns (bytes32) { return keccak256(initCodeERC1967Bootstrap(authorizedUpgrader)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 BEACON PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: If you use this proxy, you MUST make sure that the beacon is a // valid ERC1967 beacon. This means that the beacon must always return a valid // address upon a staticcall to `implementation()`, given sufficient gas. // For performance, the deployment operations and the proxy assumes that the // beacon is always valid and will NOT validate it. /// @dev Deploys a minimal ERC1967 beacon proxy. function deployERC1967BeaconProxy(address beacon) internal returns (address instance) { instance = deployERC1967BeaconProxy(0, beacon); } /// @dev Deploys a minimal ERC1967 beacon proxy. /// Deposits `value` ETH during deployment. function deployERC1967BeaconProxy(uint256 value, address beacon) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 beac | PUSH20 beac | beac 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos beac 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot beac 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (82 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * | * ~~~~~~~ beacon staticcall sub procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 60 0x20 | PUSH1 0x20 | 32 | | * 36 | CALLDATASIZE | cds 32 | | * 60 0x04 | PUSH1 0x04 | 4 cds 32 | | * 36 | CALLDATASIZE | cds 4 cds 32 | | * 63 0x5c60da1b | PUSH4 0x5c60da1b | 0x5c60da1b cds 4 cds 32 | | * 60 0xe0 | PUSH1 0xe0 | 224 0x5c60da1b cds 4 cds 32 | | * 1b | SHL | sel cds 4 cds 32 | | * 36 | CALLDATASIZE | cds sel cds 4 cds 32 | | * 52 | MSTORE | cds 4 cds 32 | sel | * 7f slot | PUSH32 slot | s cds 4 cds 32 | sel | * 54 | SLOAD | beac cds 4 cds 32 | sel | * 5a | GAS | g beac cds 4 cds 32 | sel | * fa | STATICCALL | succ | impl | * 50 | POP | | impl | * 36 | CALLDATASIZE | cds | impl | * 51 | MLOAD | impl | impl | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 5a | GAS | g impl 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x4d | PUSH1 0x4d | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) instance := create(value, 0x0c, 0x74) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`. function deployDeterministicERC1967BeaconProxy(address beacon, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967BeaconProxy(0, beacon, salt); } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967BeaconProxy(uint256 value, address beacon, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy(address beacon, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967BeaconProxy(0, beacon, salt); } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy(uint256 value, address beacon, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x0c, 0x74)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy. function initCodeERC1967BeaconProxy(address beacon) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x74), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(c, 0x54), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(c, 0x34), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(c, 0x1d), beacon) mstore(add(c, 0x09), 0x60523d8160223d3973) mstore(add(c, 0x94), 0) mstore(c, 0x74) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy. function initCodeHashERC1967BeaconProxy(address beacon) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) hash := keccak256(0x0c, 0x74) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the ERC1967 beacon proxy, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967BeaconProxy( address beacon, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967BeaconProxy(beacon); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967 BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967 beacon proxy with `args`. function deployERC1967BeaconProxy(address beacon, bytes memory args) internal returns (address instance) { instance = deployERC1967BeaconProxy(0, beacon, args); } /// @dev Deploys a minimal ERC1967 beacon proxy with `args`. /// Deposits `value` ETH during deployment. function deployERC1967BeaconProxy(uint256 value, address beacon, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) instance := create(value, add(m, 0x16), add(n, 0x75)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. function deployDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967BeaconProxy(0, beacon, args, salt); } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) instance := create2(value, add(m, 0x16), add(n, 0x75), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967BeaconProxy(0, beacon, args, salt); } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x16), add(n, 0x75))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x16), add(n, 0x75), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy. function initCodeERC1967BeaconProxy(address beacon, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x75), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(c, 0x55), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(c, 0x35), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(c, 0x1e), beacon) mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n))) mstore(c, add(n, 0x75)) // Store the length. mstore(add(c, add(n, 0x95)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy with `args`. function initCodeHashERC1967BeaconProxy(address beacon, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x8b), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) mstore(m, add(0x6100523d8160233d3973, shl(56, n))) hash := keccak256(add(m, 0x16), add(n, 0x75)) } } /// @dev Returns the address of the ERC1967 beacon proxy with `args`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967BeaconProxy( address beacon, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967BeaconProxy(beacon, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967BeaconProxy(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x52))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967BeaconProxy(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x52)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x32), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 beacon proxy with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967BeaconProxy(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x32), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x52) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I BEACON PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This proxy has a special code path that activates if `calldatasize() == 1`. // This code path skips the delegatecall and directly returns the `implementation` address. // The returned implementation is guaranteed to be valid if the keccak256 of the // proxy's code is equal to `ERC1967_BEACON_PROXY_CODE_HASH`. // // If you use this proxy, you MUST make sure that the beacon is a // valid ERC1967 beacon. This means that the beacon must always return a valid // address upon a staticcall to `implementation()`, given sufficient gas. // For performance, the deployment operations and the proxy assumes that the // beacon is always valid and will NOT validate it. /// @dev Deploys a ERC1967I beacon proxy. function deployERC1967IBeaconProxy(address beacon) internal returns (address instance) { instance = deployERC1967IBeaconProxy(0, beacon); } /// @dev Deploys a ERC1967I beacon proxy. /// Deposits `value` ETH during deployment. function deployERC1967IBeaconProxy(uint256 value, address beacon) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 beac | PUSH20 beac | beac 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos beac 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot beac 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (87 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * | * ~~~~~~~ beacon staticcall sub procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 60 0x20 | PUSH1 0x20 | 32 | | * 36 | CALLDATASIZE | cds 32 | | * 60 0x04 | PUSH1 0x04 | 4 cds 32 | | * 36 | CALLDATASIZE | cds 4 cds 32 | | * 63 0x5c60da1b | PUSH4 0x5c60da1b | 0x5c60da1b cds 4 cds 32 | | * 60 0xe0 | PUSH1 0xe0 | 224 0x5c60da1b cds 4 cds 32 | | * 1b | SHL | sel cds 4 cds 32 | | * 36 | CALLDATASIZE | cds sel cds 4 cds 32 | | * 52 | MSTORE | cds 4 cds 32 | sel | * 7f slot | PUSH32 slot | s cds 4 cds 32 | sel | * 54 | SLOAD | beac cds 4 cds 32 | sel | * 5a | GAS | g beac cds 4 cds 32 | sel | * fa | STATICCALL | succ | impl | * ~~~~~~ check calldatasize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 36 | CALLDATASIZE | cds succ | | * 14 | EQ | | impl | * 60 0x52 | PUSH1 0x52 | | impl | * 57 | JUMPI | | impl | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 36 | CALLDATASIZE | cds | impl | * 51 | MLOAD | impl | impl | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 5a | GAS | g impl 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 60 0x01 | PUSH1 0x01 | 1 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [1..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x52 | PUSH1 0x52 | dest succ | [1..returndatasize): returndata | * 57 | JUMPI | | [1..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [1..returndatasize): returndata | * 60 0x01 | PUSH1 0x01 | 1 rds | [1..returndatasize): returndata | * fd | REVERT | | [1..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [1..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [1..returndatasize): returndata | * 60 0x01 | PUSH1 0x01 | 1 rds | [1..returndatasize): returndata | * f3 | RETURN | | [1..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) instance := create(value, 0x07, 0x79) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic ERC1967I beacon proxy with `salt`. function deployDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967IBeaconProxy(0, beacon, salt); } /// @dev Deploys a deterministic ERC1967I beacon proxy with `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967IBeaconProxy(uint256 value, address beacon, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) instance := create2(value, 0x07, 0x79, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic ERC1967I beacon proxy with `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967IBeaconProxy(0, beacon, salt); } /// @dev Creates a deterministic ERC1967I beacon proxy with `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967IBeaconProxy(uint256 value, address beacon, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x07, 0x79)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, 0x07, 0x79, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the ERC1967I beacon proxy. function initCodeERC1967IBeaconProxy(address beacon) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x79), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x59), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x39), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x1d), beacon) mstore(add(c, 0x09), 0x60573d8160223d3973) mstore(add(c, 0x99), 0) mstore(c, 0x79) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I beacon proxy. function initCodeHashERC1967IBeaconProxy(address beacon) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) hash := keccak256(0x07, 0x79) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the ERC1967I beacon proxy, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967IBeaconProxy( address beacon, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a ERC1967I beacon proxy with `args. function deployERC1967IBeaconProxy(address beacon, bytes memory args) internal returns (address instance) { instance = deployERC1967IBeaconProxy(0, beacon, args); } /// @dev Deploys a ERC1967I beacon proxy with `args. /// Deposits `value` ETH during deployment. function deployERC1967IBeaconProxy(uint256 value, address beacon, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) instance := create(value, add(m, 0x16), add(n, 0x7a)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`. function deployDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967IBeaconProxy(0, beacon, args, salt); } /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967IBeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) instance := create2(value, add(m, 0x16), add(n, 0x7a), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic ERC1967I beacon proxy with `args` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967IBeaconProxy(0, beacon, args, salt); } /// @dev Creates a deterministic ERC1967I beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967IBeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x16), add(n, 0x7a))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x16), add(n, 0x7a), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the ERC1967I beacon proxy with `args`. function initCodeERC1967IBeaconProxy(address beacon, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x9a), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x7a), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x5a), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x3a), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x1e), beacon) mstore(add(c, 0x0a), add(0x6100573d8160233d3973, shl(56, n))) mstore(add(c, add(n, 0x9a)), 0) mstore(c, add(n, 0x7a)) // Store the length. mstore(0x40, add(c, add(n, 0xba))) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I beacon proxy with `args`. function initCodeHashERC1967IBeaconProxy(address beacon, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let c := mload(0x40) // Cache the free memory pointer. let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x90), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x14), beacon) mstore(c, add(0x6100573d8160233d3973, shl(56, n))) hash := keccak256(add(c, 0x16), add(n, 0x7a)) } } /// @dev Returns the address of the ERC1967I beacon proxy, with `args` and salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967IBeaconProxy( address beacon, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967IBeaconProxy(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x57))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x57, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967IBeaconProxy(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x57)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x37), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967I beacon proxy with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967IBeaconProxy(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x37), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x57) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `address(0)` if the implementation address cannot be determined. function implementationOf(address instance) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { extcodecopy(instance, 0x00, 0x00, 0x57) } 1 {} { if mload(0x2d) { // ERC1967I and ERC1967IBeaconProxy detection. if or( eq(keccak256(0x00, 0x52), ERC1967I_CODE_HASH), eq(keccak256(0x00, 0x57), ERC1967I_BEACON_PROXY_CODE_HASH) ) { pop(staticcall(gas(), instance, 0x00, 0x01, 0x00, 0x20)) result := mload(0x0c) break } } // 0age clone detection. result := mload(0x0b) codecopy(0x0b, codesize(), 0x14) // Zeroize the 20 bytes for the address. if iszero(xor(keccak256(0x00, 0x2c), CLONE_CODE_HASH)) { break } mstore(0x0b, result) // Restore the zeroized memory. // CWIA detection. result := mload(0x0a) codecopy(0x0a, codesize(), 0x14) // Zeroize the 20 bytes for the address. if iszero(xor(keccak256(0x00, 0x2d), CWIA_CODE_HASH)) { break } mstore(0x0a, result) // Restore the zeroized memory. // PUSH0 clone detection. result := mload(0x09) codecopy(0x09, codesize(), 0x14) // Zeroize the 20 bytes for the address. result := shr(xor(keccak256(0x00, 0x2d), PUSH0_CLONE_CODE_HASH), result) break } result := shr(96, result) mstore(0x37, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address when a contract with initialization code hash, /// `hash`, is deployed with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Requires that `salt` starts with either the zero address or `by`. function checkStartsWith(bytes32 salt, address by) internal pure { /// @solidity memory-safe-assembly assembly { // If the salt does not start with the zero address or `by`. if iszero(or(iszero(shr(96, salt)), eq(shr(96, shl(96, by)), shr(96, salt)))) { mstore(0x00, 0x0c4549ef) // `SaltDoesNotStartWith()`. revert(0x1c, 0x04) } } } /// @dev Returns the `bytes32` at `offset` in `args`, without any bounds checks. /// To load an address, you can use `address(bytes20(argLoad(args, offset)))`. function argLoad(bytes memory args, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(add(add(args, 0x20), offset)) } } }