/// @title Create3
/// @notice SPDX-License-Identifier: MIT
/// @author Maddiaa <https://github.com/cheethas>
/// @author asnared <https://github.com/abigger87>
/// @notice Deploy to deterministic addresses without an initcode factor
/// @notice Adapted from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol)
#include "./CommonErrors.huff"
// Proxy Constants
#define constant PROXY_BYTECODE = 0x67363d3d37363d34f03d5260086018f3
#define constant PROXY_BYTECODE_HASH = 0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f
//--------------------------------------------------------------------------------//
// Opcode | Opcode + Arguments | Description | Stack View //
//--------------------------------------------------------------------------------//
// 0x36 | 0x36 | CALLDATASIZE | size //
// 0x3d | 0x3d | RETURNDATASIZE | 0 size //
// 0x3d | 0x3d | RETURNDATASIZE | 0 0 size //
// 0x37 | 0x37 | CALLDATACOPY | //
// 0x36 | 0x36 | CALLDATASIZE | size //
// 0x3d | 0x3d | RETURNDATASIZE | 0 size //
// 0x34 | 0x34 | CALLVALUE | value 0 size //
// 0xf0 | 0xf0 | CREATE | newContract //
//--------------------------------------------------------------------------------//
// Opcode | Opcode + Arguments | Description | Stack View //
//--------------------------------------------------------------------------------//
// 0x67 | 0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode | bytecode //
// 0x3d | 0x3d | RETURNDATASIZE | 0 bytecode //
// 0x52 | 0x52 | MSTORE | //
// 0x60 | 0x6008 | PUSH1 08 | 8 //
// 0x60 | 0x6018 | PUSH1 18 | 24 8 //
// 0xf3 | 0xf3 | RETURN | //
//--------------------------------------------------------------------------------//
/// @notice Deploy a new contract with our pre-made bytecode via CREATE2
#define macro CREATE_3_DEPLOY() = takes (3) returns (1) {
// Input Stack: [salt, &creationCode, value]
// Output Stack: [deployed]
// Create the proxy
dup1 0x10 // [size, salt, salt, &creationCode, value]
// Shift the proxy bytecode left
[PROXY_BYTECODE] // [bytecode, size, salt, salt, &creationCode, value, bytecode]
0x80 shl // [RIGHTPAD(bytecode), size, salt, salt, &creationCode, value, bytecode]
0x00 mstore // [size, salt, salt, &creationCode, value]
0x00 // [offset, size, salt, salt, &creationCode, value]
0x00 // [value, offset, size, salt, salt, &creationCode, value]
create2 // [address, salt, &creationCode, value]
// Check the address of of the proxy is not null
dup1 iszero // [address == 0, address, salt, &creationCode, value]
deployment_failed jumpi // [address, salt, &creationCode, value]
// Load the length of the creation code
dup3 0x04 add calldataload // [creationCode.length, address, salt, &creationCode, value]
// Copy the code from calldata to memory at memory position 0x20
dup1 0x05 shl // [size, creationCode.length, address, salt, &creationCode, value]
dup5 0x24 add // [calldataOffset, size, creationCode.length, address, salt, &creationCode, value]
0x20 // [destOffset, calldataOffset, size, creationCode.length, address, salt, &creationCode, value]
calldatacopy // [creationCode.length, address, salt, &creationCode, value]
// Call the proxy with the creation code
0x20 // [retSize, creationCode.length, address, salt, &creationCode, value]
0x00 // [retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
dup3 // [argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
0x20 // [argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
dup9 // [value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
dup7 // [to, value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
gas // [gas, to, value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
call // [success, creationCode.length, address, salt, &creationCode, value]
iszero // [success == 0, creationCode.length, address, salt, &creationCode, value]
init_failed jumpi // [creationCode.length, address, salt, &creationCode, value]
// Get the deployed contract using the salt and make sure it has code at the address
dup3 CREATE_3_GET_DEPLOYED() // [deployed, creationCode.length, address, salt, &creationCode, value]
dup1 extcodesize // [deployed == 0, deployed, creationCode.length, address, salt, &creationCode, value]
iszero init_failed jumpi // [deployed, creationCode.length, address, salt, &creationCode, value]
// Clean up stack and return
swap5 pop pop pop pop pop // [deployed]
done jump
deployment_failed:
DEPLOYMENT_FAILED(0x00)
init_failed:
INITIALIZATION_FAILED(0x00)
done:
}
#define macro CREATE_3_GET_DEPLOYED() = takes (1) returns (1) {
// Input Stack : [salt]
// Output Stack: [deployed_address]
// Store 0xff | (right_padded_address >> 1) in memory
__RIGHTPAD(0xff) // [rightpad(0xff), salt]
address 0x58 shl // [rightpad(address), rightpad(0xff), salt]
or // [[0xff][address], salt]
0x00 mstore // [salt]
// Store the salt in memory at position 0x15
0x15 mstore // []
// Store the hash in memory at 0x35
[PROXY_BYTECODE_HASH] // [hash]
0x35 mstore // []
// Hash the memory from 0x00:0x55
0x55 0x00 sha3 // [keccak]
// ---------------------------------------- //
// Memory Layout //
// ---------------------------------------- //
// prefix | address | nonce | empty //
// 0xd694 | <proxy_address> | 01 | 000..000 //
// ---------------------------------------- //
// 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01)
// 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
// Clear the top 10 bytes of the hash
0x60 shl 0x10 shr // [proxy_address]
// return rpl encoded
__RIGHTPAD(0xd694) // [0xd694, proxy_address]
or // [ [0xd694][proxy_address] ]
// Append a 0x01 to the end of the address
0x01 0x48 shl // [0x01 << 9, [0xd694][proxy_address]]
or // [ [0xd694][proxy_address][01] ]
// Hash the packed encoding in memory position 0x00
0x00 mstore // []
0x17 0x00 sha3 // [hash]
// Clear the top 12 bytes using shifts
0x60 shl 0x60 shr // [proxy_address]
}