mirror of
https://github.com/luxfi/eoa-contracts.git
synced 2026-10-30 16:58:32 +00:00
142 lines
5.1 KiB
Solidity
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)
|
|
}
|
|
}
|
|
}
|