-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
924 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
//SPDX-License-Identifier: Unlicense | ||
pragma solidity ^0.8.4; | ||
|
||
/** | ||
@title A library for deploying contracts EIP-3171 style. | ||
@author Agustin Aguilar <[email protected]> | ||
*/ | ||
library Create3 { | ||
error ErrorCreatingProxy(); | ||
error ErrorCreatingContract(); | ||
error TargetAlreadyExists(); | ||
|
||
/** | ||
@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 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; | ||
|
||
/** | ||
@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) } | ||
} | ||
|
||
/** | ||
@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 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 Creation code (constructor) of the contract to be deployed, this value 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(); | ||
} | ||
|
||
/** | ||
@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 addr 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) internal view returns (address) { | ||
address proxy = address( | ||
uint160( | ||
uint256( | ||
keccak256( | ||
abi.encodePacked( | ||
hex'ff', | ||
address(this), | ||
_salt, | ||
KECCAK256_PROXY_CHILD_BYTECODE | ||
) | ||
) | ||
) | ||
) | ||
); | ||
|
||
return address( | ||
uint160( | ||
uint256( | ||
keccak256( | ||
abi.encodePacked( | ||
hex"d6_94", | ||
proxy, | ||
hex"01" | ||
) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import "./Create3.sol"; | ||
|
||
contract Create3Deployer { | ||
function deploy(bytes32 _salt, bytes memory _creationCode) external returns (address addr) { | ||
return Create3.create3(_salt, _creationCode); | ||
} | ||
|
||
function deployWithValue(bytes32 _salt, bytes memory _creationCode, uint256 _value) external returns (address addr) { | ||
return Create3.create3(_salt, _creationCode, _value); | ||
} | ||
|
||
function computeAddress(bytes32 _salt) external view returns (address addr) { | ||
return Create3.addressOf(_salt); | ||
} | ||
} |
Oops, something went wrong.