Skip to content

Instantly share code, notes, and snippets.

@Aboudjem
Last active March 25, 2024 19:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aboudjem/3ae8cc89ebff8c086e9b9111b1d06e6d to your computer and use it in GitHub Desktop.
Save Aboudjem/3ae8cc89ebff8c086e9b9111b1d06e6d to your computer and use it in GitHub Desktop.
Create, Create2, Create3
// 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);
}
}
// 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;
}
}
//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
)
)
);
}
}
@hiddentao
Copy link

Shouldn't Line 150 be:

type(Child2).creationCode,

?

@Aboudjem
Copy link
Author

Aboudjem commented Feb 5, 2024

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