// Source: contracts/deploy/Create3.sol pragma solidity ^0.8.0; // SPDX-License-Identifier: MIT // File contracts/deploy/CreateDeploy.sol /** * @title CreateDeploy Contract * @notice This contract deploys new contracts using the `CREATE` opcode and is used as part of * the `CREATE3` deployment method. */ contract CreateDeploy { /** * @dev Deploys a new contract with the specified bytecode using the `CREATE` opcode. * @param bytecode The bytecode of the contract to be deployed */ // slither-disable-next-line locked-ether function deploy(bytes memory bytecode) external payable { assembly { if iszero(create(0, add(bytecode, 32), mload(bytecode))) { revert(0, 0) } } } } // File contracts/deploy/Create3Address.sol /** * @title Create3Address contract * @notice This contract can be used to predict the deterministic deployment address of a contract deployed with the `CREATE3` technique. */ contract Create3Address { /// @dev bytecode hash of the CreateDeploy helper contract bytes32 internal immutable createDeployBytecodeHash; constructor() { createDeployBytecodeHash = keccak256(type(CreateDeploy).creationCode); } /** * @notice Compute the deployed address that will result from the `CREATE3` method. * @param deploySalt A salt to influence the contract address * @return deployed The deterministic contract address if it was deployed */ function _create3Address(bytes32 deploySalt) internal view returns (address deployed) { address deployer = address( uint160(uint256(keccak256(abi.encodePacked(hex'ff', address(this), deploySalt, createDeployBytecodeHash)))) ); deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); } } // File contracts/interfaces/IDeploy.sol /** * @title IDeploy Interface * @notice This interface defines the errors for a contract that is responsible for deploying new contracts. */ interface IDeploy { error EmptyBytecode(); error AlreadyDeployed(); error DeployFailed(); } // File contracts/libs/ContractAddress.sol library ContractAddress { function isContract(address contractAddress) internal view returns (bool) { bytes32 existingCodeHash = contractAddress.codehash; // https://eips.ethereum.org/EIPS/eip-1052 // keccak256('') == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 return existingCodeHash != bytes32(0) && existingCodeHash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; } } // File contracts/deploy/Create3.sol /** * @title Create3 contract * @notice This contract can be used to deploy a contract with a deterministic address that depends only on * the deployer address and deployment salt, not the contract bytecode and constructor parameters. */ contract Create3 is Create3Address, IDeploy { using ContractAddress for address; /** * @notice Deploys a new contract using the `CREATE3` method. * @dev This function first deploys the CreateDeploy contract using * the `CREATE2` opcode and then utilizes the CreateDeploy to deploy the * new contract with the `CREATE` opcode. * @param bytecode The bytecode of the contract to be deployed * @param deploySalt A salt to influence the contract address * @return deployed The address of the deployed contract */ function _create3(bytes memory bytecode, bytes32 deploySalt) internal returns (address deployed) { deployed = _create3Address(deploySalt); if (bytecode.length == 0) revert EmptyBytecode(); if (deployed.isContract()) revert AlreadyDeployed(); // Deploy using create2 CreateDeploy create = new CreateDeploy{ salt: deploySalt }(); if (address(create) == address(0)) revert DeployFailed(); // Deploy using create create.deploy(bytecode); } }