Last active
November 1, 2024 10:46
-
-
Save Aboudjem/3ae8cc89ebff8c086e9b9111b1d06e6d to your computer and use it in GitHub Desktop.
Create, Create2, Create3
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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
contract Template { | |
uint256 variable1; | |
} | |
contract Create { | |
event Deployed(address deployedAddress); | |
function deployContract() public returns (address deployedAddress) { | |
bytes memory bytecode = abi.encodePacked(type(Template).creationCode, abi.encode(msg.sender)); | |
assembly { | |
deployedAddress := create(0, add(bytecode, 0x20), mload(bytecode)) | |
if iszero(extcodesize(deployedAddress)) { | |
revert(0, 0) | |
} | |
} | |
emit Deployed(deployedAddress); | |
} | |
} |
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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
contract Template { | |
uint256 variable1; | |
} | |
contract Create2 { | |
event Deployed(address preAddr, address actuallyAddr); | |
function testDeploy() public payable { | |
uint256 _salt = 1; | |
bytes32 hash = keccak256( | |
abi.encodePacked( | |
bytes1(0xff), | |
address(this), | |
_salt, | |
keccak256(type(Template).creationCode) | |
) | |
); | |
address preAddr = address(uint160(uint(hash))); | |
address actuallyAddr = deploy(type(Template).creationCode, _salt); | |
assert(preAddr == actuallyAddr); | |
emit Deployed(preAddr, actuallyAddr); | |
} | |
function deploy( | |
bytes memory bytecode, | |
uint _salt | |
) internal returns (address) { | |
address addr; | |
assembly { | |
addr := create2( | |
callvalue(), // wei sent with current call | |
// Actual code starts after skipping the first 32 bytes | |
add(bytecode, 0x20), | |
mload(bytecode), // Load the size of code contained in the first 32 bytes | |
_salt // Salt from function arguments | |
) | |
if iszero(extcodesize(addr)) { | |
revert(0, 0) | |
} | |
} | |
return addr; | |
} | |
} |
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
//SPDX-License-Identifier: Unlicense | |
pragma solidity ^0.8.0; | |
/** | |
@title A library for deploying contracts EIP-3171 style. | |
@author Agustin Aguilar <aa@horizon.io> | |
*/ | |
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" | |
) | |
) | |
) | |
) | |
); | |
} | |
} | |
contract Child { | |
function hola() external view returns (string memory) { | |
return "mundo"; | |
} | |
} | |
contract Deployer { | |
function deployChild() external { | |
Create3.create3(keccak256(bytes("<my salt>")), type(Child).creationCode); | |
} | |
} | |
contract Child2 { | |
uint256 meaningOfLife; | |
address owner; | |
constructor(uint256 _meaning, address _owner) { | |
meaningOfLife = _meaning; | |
owner = _owner; | |
} | |
} | |
contract Deployer2 { | |
function deployChild() external { | |
Create3.create3( | |
keccak256(bytes("<my salt>")), | |
abi.encodePacked( | |
type(Child2).creationCode, | |
abi.encode( | |
42, | |
msg.sender | |
) | |
) | |
); | |
} | |
} |
Shouldn't Line 150 be:
type(Child2).creationCode,
?
good catch ! thanks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Shouldn't Line 150 be:
type(Child2).creationCode,
?