Files
2023-09-11 21:48:11 +07:00

142 lines
5.1 KiB
Solidity

//SPDX-License-Identifier: Unlicense
pragma solidity 0.8.17;
/**
@title A library for deploying contracts EIP-3171 style.
@author Agustin Aguilar <[email protected]>
*/
library Create3 {
/**
@notice The bytecode for a contract that proxies the creation of another contract
@dev If deployed via CREATE2, decouple creationCode from 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 internal constant PROXY_CHILD_BYTECODE =
hex"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3";
// KECCAK256_PROXY_CHILD_BYTECODE = keccak256(PROXY_CHILD_BYTECODE);
bytes32 internal constant KECCAK256_PROXY_CHILD_BYTECODE =
0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;
error ErrorCreatingProxy();
error ErrorCreatingContract();
error TargetAlreadyExists();
/**
@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 Constructor code for contract to be deployed; it doesn't affect the resulting address.
@return addr of the deployed contract, reverts on error
*/
function create3(
bytes32 _salt,
bytes memory _creationCode
) internal returns (address addr) {
return create3(_salt, _creationCode, 0);
}
/**
@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 Constructor code for contract to be deployed; it doesn't affect the resulting address.
@param _value In WEI of ETH to be forwarded to child contract
@return addr of the deployed contract, reverts on error
*/
function create3(
bytes32 _salt,
bytes memory _creationCode,
uint256 _value
) internal returns (address addr) {
// Creation code
bytes memory creationCode = PROXY_CHILD_BYTECODE;
// Get target final address
addr = addressOf(_salt);
if (codeSize(addr) != 0) revert TargetAlreadyExists();
// Create CREATE2 proxy
address proxy;
assembly {
proxy := create2(
0,
add(creationCode, 32),
mload(creationCode),
_salt
)
}
if (proxy == address(0)) revert ErrorCreatingProxy();
// Call proxy with final init code
(bool success, ) = proxy.call{value: _value}(_creationCode);
if (!success || codeSize(addr) == 0) revert ErrorCreatingContract();
}
function addressOfProxy(bytes32 _salt) internal view returns (address) {
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
address(this),
_salt,
KECCAK256_PROXY_CHILD_BYTECODE
)
)
)
)
);
}
/**
* @notice Computes the resulting address of a contract deployed using address(this) and the given `_salt`
*
* @dev Address creation formula:
* keccak256(rlp([keccak256(0xff+address(this)+_salt+keccak256(childBytecode))[12:],0x01]))
*
* @param _salt Salt of the contract creation, resulting address will be derived from this value only
* @return addr of the deployed contract, reverts on error
*/
function addressOf(bytes32 _salt) internal view returns (address) {
address proxy = addressOfProxy(_salt);
return
address(
uint160(
uint256(
keccak256(abi.encodePacked(hex"d6_94", proxy, hex"01"))
)
)
);
}
/**
@notice Returns the size of the code on a given address
@param _addr Address that may or may not contain code
@return size of the code on the given `_addr`
*/
function codeSize(address _addr) internal view returns (uint256 size) {
assembly {
size := extcodesize(_addr)
}
}
}