-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CREATE3 opcode - no init_code hash #3171
Changes from all commits
ab202fa
b13cdcb
c888bba
6a96c12
2374131
a33e8a6
83e8dc8
fc53d36
944d983
3f9d491
46350bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,148 @@ | ||||||
--- | ||||||
eip: 3171 | ||||||
title: CREATE3 | ||||||
author: Moody Salem (@moodysalem) | ||||||
category: Core | ||||||
type: Standards Track | ||||||
status: Draft | ||||||
created: 2020-12-22 | ||||||
--- | ||||||
|
||||||
## Simple Summary | ||||||
|
||||||
This EIP is a fork of [EIP-1014](./eip-1014.md) (`CREATE2`) which adds an account creation opcode (`CREATE3`) that does | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this sentence makes more sense in the abstract, and the simple summary can just be sentence below. |
||||||
not involve the init code hash. It is otherwise identical to `CREATE2` opcode. | ||||||
|
||||||
This opcode allows users to create accounts at an address independent of the bytecode deployed to the address. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Abstract | ||||||
|
||||||
TBD | ||||||
|
||||||
## Motivation | ||||||
|
||||||
The core motivations of the `CREATE3` opcode are the same as [EIP-1014](./eip-1014.md), i.e. deploying a smart contract at a | ||||||
deterministic address. | ||||||
|
||||||
This variation removes the hash of the init code from the preimage. This enables the address of contract created via `CREATE3` | ||||||
to be computed on-chain knowing only the deployer address and salt. | ||||||
|
||||||
It is possible to compute the address of a contract created with `CREATE2` without making any external calls. For example, | ||||||
Uniswap V2 [uses this](https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L18) | ||||||
to save gas in computing the pair address from the Uniswap V2 Router. The gas cost of the `pairFor` method which | ||||||
computes the pair address for a given pair of tokens is only ~649 gas, while an external call + an SLOAD from mapping | ||||||
may cost upwards of 3k gas. A swap that is routed through multiple pairs requires multiple calls of this method. | ||||||
|
||||||
This is feasible only because the Uniswap V2 Pair does not have any constructor arguments, which means the init code hash | ||||||
can be hard coded in the library. However, the init code hash cannot be hard coded when the deployed smart contract has | ||||||
constructor arguments. In order to compute the init code hash, one must append the constructor arguments to the init code | ||||||
before computing the init code hash. Thus, in order to compute the address of an account created via `CREATE2`, it is | ||||||
necessary to include the entire init code without the constructor arguments, and hash | ||||||
`ceil(len(init_code_base + constructor_arguments) / 32)` words on-chain. | ||||||
Comment on lines
+36
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not particularly pretty, but I believe another workaround to this problem is to have the init code pull the arguments from the creator:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, I heard about this in the #allcoredevs channel of Discord and I will add it as a workaround |
||||||
|
||||||
Later versions of solidity introduced immutables, which allow for further gas savings but must be initialized in the | ||||||
constructor. | ||||||
|
||||||
## Specification | ||||||
|
||||||
Adds a new opcode (`CREATE3`) at `0xf6`, which takes 4 stack arguments: endowment, memory_start, memory_length, salt. | ||||||
Behaves identically to `CREATE2` (`0xf5`), except using `keccak256( 0xff ++ address ++ salt )[12:]`, | ||||||
which does not include the hash of the init code. | ||||||
|
||||||
The `CREATE3` opcode has the same `gas` schema as `CREATE2`, but with one fewer `GSHA3WORD` opcode, to account for the difference | ||||||
in lengths of the preimages (`53` bytes instead of `85` in `CREATE2`). | ||||||
The `hashcost` is deducted at the same time as memory-expansion gas and `CreateGas` is deducted: _before_ evaluation | ||||||
of the resulting address and the execution of `init_code`. | ||||||
|
||||||
- `0xff` is a single byte, | ||||||
- `address` is always `20` bytes, | ||||||
- `salt` is always `32` bytes (a stack item). | ||||||
|
||||||
The preimage for the final hashing round is thus always exactly `53` bytes long (does not include hash of the init code). | ||||||
|
||||||
## Rationale | ||||||
|
||||||
### Address formula | ||||||
moodysalem marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
* As with CREATE2, ensures that addresses created with this scheme cannot collide with addresses created using the traditional | ||||||
`keccak256(rlp([sender, nonce]))` formula, as `0xff` can only be a starting byte for RLP for data many petabytes long. | ||||||
* The addresses created with this scheme cannot collide with addresses created using the `CREATE2`, since the lengths | ||||||
of the preimage differ | ||||||
* Ensures that the hash preimage has a fixed size. | ||||||
|
||||||
### Gas cost | ||||||
|
||||||
The concerns for `CREATE2` gas cost in regard to init code preimage length do not apply, as the init code hash is not used | ||||||
in computing the account address. | ||||||
|
||||||
## Test Cases | ||||||
|
||||||
The addresses computed using the following example typescript code: | ||||||
|
||||||
```typescript | ||||||
import {utils} from 'ethers' | ||||||
|
||||||
function getCreate3Address(address: string, salt: string) { | ||||||
const create3Inputs = ['0xff', address, salt] | ||||||
// remove the 0x prefixes | ||||||
const sanitizedInputs = `0x${create3Inputs.map((i) => i.slice(2)).join('')}` | ||||||
return utils.getAddress(`0x${utils.keccak256(sanitizedInputs).slice(-40)}`) | ||||||
} | ||||||
``` | ||||||
|
||||||
Example 0 | ||||||
* address `0x0000000000000000000000000000000000000000` | ||||||
* salt `0x0000000000000000000000000000000000000000000000000000000000000000` | ||||||
* gas (assuming no mem expansion): *TBD* | ||||||
* result: `0x69aC1DB8a84821a964E54c0FE42E0E7C3B9b87D6` | ||||||
|
||||||
Example 1 | ||||||
* address `0xdeadbeef00000000000000000000000000000000` | ||||||
* salt `0x0000000000000000000000000000000000000000000000000000000000000000` | ||||||
* gas (assuming no mem expansion): *TBD* | ||||||
* result: `0x2D758dBc3E8C5476fE9a3CB92D1594ea7Efbe7A2` | ||||||
|
||||||
Example 2 | ||||||
* address `0xdeadbeef00000000000000000000000000000000` | ||||||
* salt `0x000000000000000000000000feed000000000000000000000000000000000000` | ||||||
* gas (assuming no mem expansion): *TBD* | ||||||
* result: `0x44339B41C67b140523a407dBf60b8394d9f3A67C` | ||||||
|
||||||
Example 3 | ||||||
* address `0x00000000000000000000000000000000deadbeef` | ||||||
* salt `0x00000000000000000000000000000000000000000000000000000000cafebabe` | ||||||
* gas (assuming no mem expansion): *TBD* | ||||||
* result: `0x53647a8Cc98B0f82e2D1d27c8352025d09640b81` | ||||||
|
||||||
Example 4 | ||||||
* address `0x00000000000000000000000000000000deadbeef` | ||||||
* salt `0x00000000000000000000000000000000000000000000000000000000cafebabe` | ||||||
* gas (assuming no mem expansion): *TBD* | ||||||
* result: `0x53647a8Cc98B0f82e2D1d27c8352025d09640b81` | ||||||
|
||||||
## Backwards Compatibility | ||||||
|
||||||
As in `CREATE2`, `CREATE3` makes collisions possible. | ||||||
|
||||||
`CREATE3` is not expected to have address collisions with `CREATE2`, as the preimage length differs by the `32` bytes | ||||||
of the init code hash. | ||||||
|
||||||
TODO: are there any existing protections in place that prevent contracts from self destructing and being recreated with `CREATE2`? | ||||||
|
||||||
## Security Considerations | ||||||
|
||||||
This new opcode allows the deterministic contract address to be independent of the bytecode. Users may not depend on the deterministic | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure it's fair to say this opcode "allows" this behaviour as it's possible to deploy arbitrary contracts to deterministic addresses with |
||||||
deployment address being created using a fixed init code. The deterministic deployment address computed from CREATE3 | ||||||
can contain any code. | ||||||
|
||||||
However, static init code does not protect the user from smart contract defects. The code must be audited in either case, | ||||||
and a factory code can be verified to determine that it may only deploy bytecode to specific `CREATE3` addresses with | ||||||
specific resulting bytecode. | ||||||
|
||||||
For further discussion, consider | ||||||
[this discussion](https://ethereum-magicians.org/t/potential-security-implications-of-create2-eip-1014/2614) | ||||||
of security implications of `CREATE2`. | ||||||
|
||||||
## Copyright | ||||||
|
||||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where should discussions for this EIP go?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moodysalem please update with a
discussions-to
section.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moodysalem still missing a
discussions-to
section. Merging is blocked until this is resolved.