// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
pragma solidity ^0.8.0;
/**
* @title A library for deploying contracts EIP-3171 style.
* @author Agustin Aguilar
*/
contract Create3Factory {
/**
* @notice The bytecode for a contract that proxies the creation of another contract
* @dev If this code is deployed using CREATE2 it can be used to decouple `creationCode` from the child contract
* address 0x67363d3d37363d34f03d5260086018f3:
*
* 0x00 0x67 0x67XXXXXXXXXXXXXXXX PUSH8 bytecode 0x363d3d37363d34f0
* 0x01 0x3d 0x3d RETURNDATASIZE 0 0x363d3d37363d34f0
* 0x02 0x52 0x52 MSTORE
* 0x03 0x60 0x6008 PUSH1 08 8
* 0x04 0x60 0x6018 PUSH1 18 24 8
* 0x05 0xf3 0xf3 RETURN
*
* 0x363d3d37363d34f0:
*
* 0x00 0x36 0x36 CALLDATASIZE cds
* 0x01 0x3d 0x3d RETURNDATASIZE 0 cds
* 0x02 0x3d 0x3d RETURNDATASIZE 0 0 cds
* 0x03 0x37 0x37 CALLDATACOPY
* 0x04 0x36 0x36 CALLDATASIZE cds
* 0x05 0x3d 0x3d RETURNDATASIZE 0 cds
* 0x06 0x34 0x34 CALLVALUE val 0 cds
* 0x07 0xf0 0xf0 CREATE addr
*/
bytes public constant PROXY_BYTECODE = hex'67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3';
// KECCAK_PROXY_BYTECODE = keccak256(PROXY_BYTECODE);
bytes32 public constant KECCAK_PROXY_BYTECODE = 0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;
/**
* @notice Computes the resulting address of a contract deployed using address(this) and the given `_salt`
* @param salt Salt of the contract creation, resulting address will be derivated from this value only
* @return Address of the deployed contract, reverts on error
* @dev The address creation formula is: keccak256(rlp([keccak256(0xff ++ address(this) ++ _salt ++ keccak256(childBytecode))[12:], 0x01]))
*/
function addressOf(bytes32 salt) public view returns (address) {
bytes32 addr = keccak256(abi.encodePacked(hex'ff', address(this), salt, KECCAK_PROXY_BYTECODE));
address proxy = address(uint160(uint256(addr)));
return address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', proxy, hex'01')))));
}
/**
* @notice Creates a new contract with given `creationCode` and `salt`
* @param salt Salt of the contract creation, resulting address will be derivated from this value only
* @param creationCode Creation code (constructor) of the contract to be deployed, this value doesn't affect the resulting address
* @return instance Address of the deployed contract, reverts on error
*/
function create(bytes32 salt, bytes memory creationCode) external payable returns (address instance) {
// Get target final address
instance = addressOf(salt);
require(_codeSize(instance) == 0, 'CREATE3_TARGET_ALREADY_EXISTS');
// Create proxy using CREATE2
address proxy;
bytes memory proxyCreationCode = PROXY_BYTECODE;
assembly {
proxy := create2(0, add(proxyCreationCode, 32), mload(proxyCreationCode), salt)
}
require(proxy != address(0), 'CREATE3_ERROR_CREATING_PROXY');
// Call proxy with final creation code
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = proxy.call{ value: msg.value }(creationCode);
require(success && _codeSize(instance) > 0, 'CREATE3_ERROR_CREATING_CONTRACT');
}
/**
* @notice Returns the size of the code on a given address
* @param contractAddress Address that may or may not contain code
* @return size of the code on the given `contractAddress`
*/
function _codeSize(address contractAddress) internal view returns (uint256 size) {
assembly {
size := extcodesize(contractAddress)
}
}
}