Skip to content

Commit a9ba742

Browse files
committed
update create code
Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>
1 parent 02544b7 commit a9ba742

File tree

3 files changed

+114
-64
lines changed

3 files changed

+114
-64
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021 Pascal Marco Caversaccio
3+
Copyright (c) 2022 Pascal Marco Caversaccio
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

contracts/Create.sol

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.14;
3+
4+
/**
5+
* @dev Error that occurs when the contract creation failed.
6+
* @param emitter The contract that emits the error.
7+
*/
8+
error Failed(address emitter);
9+
10+
/**
11+
* @dev Error that occurs when the factory contract has insufficient balance.
12+
* @param emitter The contract that emits the error.
13+
*/
14+
error InsufficientBalance(address emitter);
15+
16+
/**
17+
* @dev Error that occurs when the bytecode length is zero.
18+
* @param emitter The contract that emits the error.
19+
*/
20+
error ZeroBytecodeLength(address emitter);
21+
22+
/**
23+
* @title CREATE Deployer Smart Contract
24+
* @author Pascal Marco Caversaccio, pascal.caversaccio@hotmail.ch
25+
* @notice Helper smart contract to make easier and safer usage of the `CREATE` EVM opcode.
26+
* @dev Adjusted from here: https://github.com/safe-global/safe-contracts/blob/main/contracts/libraries/CreateCall.sol.
27+
*/
28+
29+
contract Create {
30+
/**
31+
* @dev Event that is emitted when a contract is successfully created.
32+
* @param newContract The address of the new contract.
33+
*/
34+
event ContractCreation(address newContract);
35+
36+
/**
37+
* @dev The function `deploy` deploys a new contract via calling
38+
* the `CREATE` opcode and using the creation bytecode as input.
39+
* @param amount The value in wei to send to the new account. If `amount` is non-zero,
40+
* `bytecode` must have a `payable` constructor.
41+
* @param bytecode The creation bytecode.
42+
*/
43+
function deploy(uint256 amount, bytes memory bytecode)
44+
public
45+
returns (address newContract)
46+
{
47+
if (address(this).balance < amount) revert InsufficientBalance(address(this));
48+
if (bytecode.length == 0) revert ZeroBytecodeLength(address(this));
49+
// solhint-disable-next-line no-inline-assembly
50+
assembly ("memory-safe") {
51+
/** @dev `CREATE` opcode
52+
*
53+
* Stack input
54+
* ------------
55+
* value: value in wei to send to the new account.
56+
* offset: byte offset in the memory in bytes, the instructions of the new account.
57+
* size: byte size to copy (size of the instructions).
58+
*
59+
* Stack output
60+
* ------------
61+
* address: the address of the deployed contract.
62+
*
63+
* How are bytes stored in Solidity:
64+
* In memory the `bytes` is stored by having first the length of the `bytes` and then the data,
65+
* this results in the following schema: `<32-bytes length><data>` at the location where bytecode points to.
66+
*
67+
* Now if we want to use the data with `CREATE`, we first point to the start of the raw data, which is after the length.
68+
* Therefore, we add 32 (the space required for the length) to the location stored in the bytecode variable.
69+
* This is the first parameter. For the second parameter, we read the length from memory using `mload`.
70+
* As the length is the first 32 bytes at the location of `bytecode`, we can read the length by calling `mload(bytecode)`.
71+
*/
72+
newContract := create(amount, add(bytecode, 0x20), mload(bytecode))
73+
}
74+
if (newContract == address(0)) revert Failed(address(this));
75+
emit ContractCreation(newContract);
76+
return newContract;
77+
}
78+
79+
/**
80+
* @dev Returns the address where a contract will be stored if deployed via {deploy}.
81+
* For the specification of the Recursive Length Prefix (RLP) encoding scheme, please
82+
* refer to p. 19 of the Ethereum Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf)
83+
* and the Ethereum Wiki (https://eth.wiki/fundamentals/rlp). For further insights also, see the
84+
* following issue: https://github.com/Rari-Capital/solmate/issues/207.
85+
*
86+
* Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md) specification,
87+
* all contract accounts on the Ethereum mainnet are initiated with `nonce = 1`.
88+
* Thus, the first contract address created by another contract is calculated with a non-zero nonce.
89+
*/
90+
// prettier-ignore
91+
function computeAddress(address addr, uint256 nonce) internal pure returns (address) {
92+
bytes memory data;
93+
bytes1 len = bytes1(0x94);
94+
95+
if (nonce == 0x00) data = abi.encodePacked(bytes1(0xd6), len, addr, bytes1(0x80));
96+
else if (nonce <= 0x7f) data = abi.encodePacked(bytes1(0xd6), len, addr, uint8(nonce));
97+
else if (nonce <= type(uint8).max) data = abi.encodePacked(bytes1(0xd7), len, addr, bytes1(0x81), uint8(nonce));
98+
else if (nonce <= type(uint16).max)
99+
data = abi.encodePacked(bytes1(0xd8), len, addr, bytes1(0x82), uint16(nonce));
100+
else if (nonce <= type(uint24).max)
101+
data = abi.encodePacked(bytes1(0xd9), len, addr, bytes1(0x83), uint24(nonce));
102+
103+
/**
104+
* @dev In the case of `nonce > type(uint24).max`, we have the following encoding scheme:
105+
* 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ address ++ 0x84 ++ nonce)
106+
* 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
107+
* 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex)
108+
*/
109+
else data = abi.encodePacked(bytes1(0xda), len, addr, bytes1(0x84), uint32(nonce));
110+
111+
return address(uint160(uint256(keccak256(data))));
112+
}
113+
}

contracts/DeployBytecode.sol

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)