-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #49 from pentagonxyz/feat/mechanisms/huff-clones
feat: Huff clones
- Loading branch information
Showing
8 changed files
with
558 additions
and
0 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,75 @@ | ||
/// @title ExampleClone | ||
/// @notice Clones with Immutable Args Library | ||
/// Original implementation: | ||
/// https://github.com/wighawag/clones-with-immutable-args/blob/master/src/ExampleClone.sol | ||
/// @author wighawag <https://github.com/wighawag> | ||
/// @author zefram <https://github.com/boredGenius> | ||
/// @author hari <https://github.com/hrkrshnn> | ||
/// @author z0r0z <https://github.com/z0r0z> | ||
/// @author clabby <https://github.com/clabby> | ||
|
||
#include "./HuffClone.huff" | ||
|
||
#define function param1() view returns (address) | ||
#define function param2() view returns (uint256) | ||
#define function param3() view returns (uint64) | ||
#define function param4() view returns (uint8) | ||
#define function param5(uint256) view returns (uint256[] memory) | ||
|
||
#define macro PARAM_1() = takes (0) returns (0) { | ||
0x00 GET_ARG_ADDRESS() // [arg_addr] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro PARAM_2() = takes (0) returns (0) { | ||
0x14 GET_ARG_UINT_256() // [arg_uint] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro PARAM_3() = takes (0) returns (0) { | ||
0x34 GET_ARG_UINT_64() // [arg_uint] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro PARAM_4() = takes (0) returns (0) { | ||
0x3C GET_ARG_UINT_8() // [arg_uint] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro PARAM_5() = takes (0) returns (0) { | ||
0x04 calldataload // [arr_len] | ||
|
||
// Store pointer in word before array | ||
0x20 0x00 mstore // [arr_len] | ||
|
||
dup1 0x00 // [0x00, arr_len, arr_len] | ||
GET_ARG_UINT_256_ARR(0x20) // [ptr, arr_len] | ||
swap1 // [arr_len, ptr] | ||
0x05 shl // [arr_len * 0x20, ptr] | ||
0x40 add // [arr_len * 0x20 + 0x40, ptr] | ||
0x00 return // [ptr] | ||
} | ||
|
||
#define macro MAIN() = takes (0) returns (0) { | ||
pc calldataload 0xE0 shr | ||
dup1 __FUNC_SIG(param1) eq param1 jumpi | ||
dup1 __FUNC_SIG(param2) eq param2 jumpi | ||
dup1 __FUNC_SIG(param3) eq param3 jumpi | ||
dup1 __FUNC_SIG(param4) eq param4 jumpi | ||
dup1 __FUNC_SIG(param5) eq param5 jumpi | ||
|
||
param1: | ||
PARAM_1() | ||
param2: | ||
PARAM_2() | ||
param3: | ||
PARAM_3() | ||
param4: | ||
PARAM_4() | ||
param5: | ||
PARAM_5() | ||
} |
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,100 @@ | ||
/// @title ExampleCloneFactory | ||
/// @notice Clones with Immutable Args Library | ||
/// Original implementation: | ||
/// https://github.com/wighawag/clones-with-immutable-args/blob/master/src/ExampleCloneFactory.sol | ||
/// @author wighawag <https://github.com/wighawag> | ||
/// @author zefram <https://github.com/boredGenius> | ||
/// @author hari <https://github.com/hrkrshnn> | ||
/// @author z0r0z <https://github.com/z0r0z> | ||
/// @author clabby <https://github.com/clabby> | ||
|
||
#include "./HuffCloneLib.huff" | ||
|
||
#define function createClone(address,uint256,uint64,uint8) nonpayable returns (address) | ||
#define function createArrClone(uint256[] calldata) nonpayable returns (address) | ||
|
||
#define constant IMPL_SLOT = FREE_STORAGE_POINTER() | ||
|
||
/// @notice Creates an `ExampleClone` contract | ||
#define macro CREATE_CLONE() = takes (0) returns (0) { | ||
0x64 calldataload // [uint8] | ||
0x44 calldataload // [uint64, uint8] | ||
0x24 calldataload // [uint256, uint64, uint8] | ||
0x04 calldataload // [address, uint256, uint64, uint8] | ||
|
||
// data len = 61 (0x3D) | ||
0x3D 0x40 mstore // [address, uint256, uint64, uint8] | ||
|
||
// Store address << 0x60 @ 0x60 | ||
0x60 shl // [address << 0x60, uint256, uint64, uint8] | ||
0x60 mstore // [uint256, uint64, uint8] | ||
|
||
// Store uint256 @ 0x74 | ||
0x74 mstore // [uint64, uint8] | ||
|
||
// Store uint64 << 0xC0 @ 0x94 | ||
0xC0 shl // [uint64 << 0xC0, uint8] | ||
0x94 mstore // [uint8] | ||
|
||
// Store uint8 << 0xF8 @ 0x9C | ||
0xF8 shl // [uint8 << 0xF8] | ||
0x9C mstore // [] | ||
|
||
0x40 // [data_ptr] | ||
[IMPL_SLOT] sload // [impl_addr, data_ptr] | ||
|
||
CLONE(err, 0x00) // [instance] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
|
||
err: | ||
0x00 0x00 revert | ||
} | ||
|
||
/// @notice Creates an `ExampleClone` contract that has an immutable | ||
/// uint256 array | ||
#define macro CREATE_ARRAY_CLONE() = takes (0) returns (0) { | ||
0x24 calldataload // [arr_len] | ||
0x05 shl // [arr_len * 0x20] | ||
0x20 add // [arr_len * 0x20 + 0x20] | ||
0x24 // [0x24, arr_len * 0x20 + 0x20] | ||
0x40 // [0x40, 0x24, arr_len * 0x20 + 0x20] | ||
calldatacopy // [] | ||
|
||
// Set data length in bytes | ||
0x40 dup1 // [0x40, 0x40] | ||
mload // [arr_len, 0x40] | ||
0x05 shl // [arr_len * 0x20, 0x40] | ||
0x40 mstore // [0x40 (data_ptr)] | ||
|
||
[IMPL_SLOT] sload // [impl_addr, data_ptr] | ||
|
||
CLONE(err, 0x00) // [instance] | ||
0x00 mstore // [] | ||
0x20 0x00 return | ||
|
||
err: | ||
0x00 0x00 revert | ||
} | ||
|
||
#define macro MAIN() = takes (0) returns (0) { | ||
pc calldataload 0xE0 shr | ||
dup1 __FUNC_SIG(createClone) eq clone jumpi | ||
dup1 __FUNC_SIG(createArrClone) eq arr_clone jumpi | ||
|
||
clone: | ||
CREATE_CLONE() | ||
arr_clone: | ||
CREATE_ARRAY_CLONE() | ||
} | ||
|
||
#define macro CONSTRUCTOR() = takes (0) returns (0) { | ||
0x20 // [size] - byte size to copy | ||
0x20 codesize sub // [offset, size] - offset in the code to copy from | ||
0x00 // [mem, offset, size] - offset in memory to copy to | ||
codecopy // [] | ||
|
||
0x00 mload | ||
[IMPL_SLOT] // [impl_ptr, impl_addr] | ||
sstore // [] | ||
} |
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,91 @@ | ||
/// @title HuffClone | ||
/// @notice Clones with Immutable Args Library | ||
/// Original implementation: | ||
/// https://github.com/wighawag/clones-with-immutable-args/blob/master/src/Clone.sol | ||
/// @author wighawag <https://github.com/wighawag> | ||
/// @author zefram <https://github.com/boredGenius> | ||
/// @author hari <https://github.com/hrkrshnn> | ||
/// @author z0r0z <https://github.com/z0r0z> | ||
/// @author clabby <https://github.com/clabby> | ||
|
||
/// @notice Reads an immutable arg with type address | ||
/// @param argOffset The offset of the arg in the packed data | ||
/// @return arg The arg value | ||
#define macro GET_ARG_ADDRESS() = takes (1) returns (1) { | ||
// Initial Stack: // [argOffset] | ||
GET_IMMUTABLE_ARGS_OFFSET() // [offset, argOffset] | ||
add // [offset + argOffset] | ||
calldataload // [cd] | ||
0x60 // [0x60, cd] | ||
shr // [cd >> 0x60] | ||
} | ||
|
||
/// @notice Reads an immutable arg with type uint256 | ||
/// @param argOffset The offset of the arg in the packed data | ||
/// @return arg The arg value | ||
#define macro GET_ARG_UINT_256() = takes (1) returns (1) { | ||
// Initial Stack: // [argOffset] | ||
GET_IMMUTABLE_ARGS_OFFSET() // [offset, argOffset] | ||
add // [offset + argOffset] | ||
calldataload // [cd] | ||
} | ||
|
||
/// @notice Reads a uint256 array stored in the immutable args. | ||
/// @param argOffset The offset of the arg in the packed data | ||
/// @param arrLen Number of elements in the array | ||
/// @return arr The beginning location of the array in memory | ||
#define macro GET_ARG_UINT_256_ARR(mem_ptr) = takes (2) returns (1) { | ||
// Initial Stack: [argOffset, arrLen] | ||
GET_IMMUTABLE_ARGS_OFFSET() // [offset, argOffset, arrLen] | ||
add // [offset + argOffset, arrLen] | ||
|
||
dup2 <mem_ptr> // [mem_ptr, arrLen, offset + argOffset, arrLen] | ||
mstore // [offset + argOffset, arrLen] | ||
swap1 0x05 shl swap1 // [offset + argOffset, arrLen * 0x20] | ||
<mem_ptr> 0x20 add // [mem_ptr + 0x20, offset + argOffset, arrLen * 0x20] | ||
calldatacopy // [] | ||
|
||
// Return the memory pointer of the array | ||
<mem_ptr> // [mem_ptr] | ||
} | ||
|
||
/// @notice Reads an immutable arg with type uint64 | ||
/// @param argOffset The offset of the arg in the packed data | ||
/// @return arg The arg value | ||
#define macro GET_ARG_UINT_64() = takes (1) returns (1) { | ||
// Initial Stack: // [argOffset] | ||
GET_IMMUTABLE_ARGS_OFFSET() // [offset, argOffset] | ||
add // [offset + argOffset] | ||
calldataload // [cd] | ||
0xC0 // [0xC0, cd] | ||
shr // [cd >> 0xC0] | ||
} | ||
|
||
/// @notice Reads an immutable arg with type uint8 | ||
/// @param argOffset The offset of the arg in the packed data | ||
/// @return The arg value | ||
#define macro GET_ARG_UINT_8() = takes (1) returns (1) { | ||
// Initial Stack: // [argOffset] | ||
GET_IMMUTABLE_ARGS_OFFSET() // [offset, argOffset] | ||
add // [offset + argOffset] | ||
calldataload // [cd] | ||
0xF8 // [0xF8, cd] | ||
shr // [cd >> 0xF8] | ||
} | ||
|
||
/// @return The offset of the packed immutable args in calldata | ||
#define macro GET_IMMUTABLE_ARGS_OFFSET() = takes (0) returns (1) { | ||
0x02 // [0x02] | ||
calldatasize // [calldatasize, 0x02] | ||
sub // [calldatasize - 0x02] | ||
|
||
calldataload // [cd] | ||
0xF0 // [0xF0, cd] | ||
shr // [cd >> 0xF0] | ||
|
||
0x02 // [0x02, cd >> 0xF0] | ||
add // [0x02 + cd >> 0xF0] | ||
|
||
calldatasize // [calldatasize, 0x02 + cd >> 0xF0] | ||
sub // [calldatasize - (0x02 + cd >> 0xF0)] | ||
} |
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,112 @@ | ||
/// @title HuffCloneLib | ||
/// @notice Clones with Immutable Args Library | ||
/// Original implementation: | ||
/// https://github.com/wighawag/clones-with-immutable-args/blob/master/src/ClonesWithImmutableArgs.sol | ||
/// @author wighawag <https://github.com/wighawag> | ||
/// @author zefram <https://github.com/boredGenius> | ||
/// @author hari <https://github.com/hrkrshnn> | ||
/// @author z0r0z <https://github.com/z0r0z> | ||
/// @author clabby <https://github.com/clabby> | ||
|
||
/// @notice Creates a clone proxy of the implementation contract, with immutable args | ||
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length | ||
/// @param err The jumpdest to jump to if an error occurs | ||
/// @param dest_ptr The memory pointer to store the creation code of the clone at | ||
/// @param impl_addr The address of the implementation contract to clone | ||
/// @param data_ptr Pointer to beginning of encoded immutable args in memory | ||
/// @return instance The address of the created clone | ||
#define macro CLONE(err, dest_ptr) = takes(2) returns (1) { | ||
// Input Stack: [impl_addr, data_ptr] | ||
dup2 mload // [data_len, impl_addr, data_ptr] | ||
dup1 0x02 add // [extra_len, data_len, impl_addr, data_ptr] | ||
dup1 0x41 add // [creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
0x0A dup2 sub // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
__RIGHTPAD(0x61) // [0x61..., run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
<dest_ptr> mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup1 0xF0 shl // [run_size << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
<dest_ptr> 0x01 add // [dest_ptr + 0x01, run_size << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
__RIGHTPAD(0x3d81600a3d39f33d3d3d3d363d3d3761) | ||
<dest_ptr> 0x03 add // [dest_ptr + 0x03, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup3 0xF0 shl // [extra_len << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
<dest_ptr> 0x13 add // [dest_ptr + 0x13, extra_len << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
__RIGHTPAD(0x603736393661) | ||
<dest_ptr> 0x15 add // [dest_ptr + 0x15, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup3 0xF0 shl // [extra_len << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
<dest_ptr> 0x1B add // [dest_ptr + 0x1B, extra_len << 0xF0, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
__RIGHTPAD(0x013d73) | ||
<dest_ptr> 0x1D add // [dest_ptr + 0x1D, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup5 0x60 shl // [impl_addr << 0x60, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
<dest_ptr> 0x20 add // [dest_ptr + 0x20, impl_addr << 0x60, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
__RIGHTPAD(0x5af43d3d93803e603557fd5bf3) | ||
<dest_ptr> 0x34 add // [dest_ptr + 0x34, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
//////////////////////////////// | ||
// APPENDED DATA // | ||
//////////////////////////////// | ||
|
||
// Subtract 0x02 from extra_len | ||
0x02 dup4 sub // [extra_len - 0x02, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
swap3 pop // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
// copy_ptr = data_ptr + 0x41 | ||
<dest_ptr> 0x41 add // [copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
// Increase data_ptr by 0x20 | ||
swap6 0x20 add // [data_ptr + 0x20, run_size, creation_size, extra_len, data_len, impl_addr, copy_ptr] | ||
swap6 // [copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
// counter = extra_len | ||
dup4 // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
memcopy_loop: | ||
dup8 mload // [data, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup3 mstore // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
swap1 0x20 add // [copy_ptr + 0x20, counter, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
swap1 // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
swap7 0x20 add // [data_ptr + 0x20, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, counter] | ||
swap7 // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
0x20 swap1 sub // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
dup1 0x20 gt // [0x20 > counter, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
iszero memcopy_loop jumpi | ||
post_loop: | ||
dup1 // [counter, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
0x01 // [0x01, counter, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
swap1 // [counter, 0x01, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
0x20 sub // [0x20 - counter, 0x01, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
0x100 exp // [0x100 ** (0x20 - counter), 0x01, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
sub not // [mask, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
dup9 mload and // [data & mask, counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup3 mstore // [counter, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
add // [copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
dup4 0xF0 shl // [extra_len << 0xF0, copy_ptr, run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
swap1 mstore // [run_size, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
|
||
pop <dest_ptr> // [dest_ptr, creation_size, extra_len, data_len, impl_addr, data_ptr] | ||
0x00 create // [instance, extra_len, data_len, impl_addr, run_size] | ||
|
||
// Revert if deployment failed | ||
dup1 iszero err jumpi | ||
|
||
// Clean stack: | ||
swap4 // [run_size, extra_len, data_len, impl_addr, instance] | ||
pop pop pop pop // [instance] | ||
|
||
// Return stack: [instance] | ||
} |
Oops, something went wrong.