Skip to content
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

Closed
wants to merge 11 commits into from
148 changes: 148 additions & 0 deletions EIPS/eip-3171.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
eip: 3171
title: CREATE3
author: Moody Salem <moody@uniswap.org>
category: Core
type: Standards Track
status: Draft
created: 2020-12-22
---

Copy link
Contributor

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?

Copy link
Member

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.

Copy link
Member

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.

## Simple Summary

This EIP is a fork of [EIP-1014](./eip-1014.md) (`CREATE2`) which adds an account creation opcode (`CREATE3`) that does
Copy link
Member

Choose a reason for hiding this comment

The 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This opcode allows users to create accounts at an address independent of the bytecode deployed to the address.
`CREATE3 (0xf6)` allows users to create accounts at an address independent of the bytecode deployed to the address.


## 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
Copy link
Member

Choose a reason for hiding this comment

The 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:

interface F {
  function provideX() external returns (uint) {
  }

contract A {
   uint x;
   constructor() {
      x = F(msg.sender).provideX();
   }
}

contract Factory {
   uint x;
   function provideX() public returns (uint) {
      return x;
   }
   function deployA(uint initArg) public {
       x = initArg;
       new A();
       x = 0;
   }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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( 0xfe ++ address ++ salt )[12:]`,
which does not include the hash of the init code and uses a different byte prefix.

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`.

- `0xfe` 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

* As with CREATE2, ensures that addresses created with this scheme cannot collide with addresses created using the traditional
`keccak256(rlp([sender, nonce]))` formula, as `0xfe` 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`, as `0xfe` will never collide with `0xff`.
* 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

Example 0
* address `0x0000000000000000000000000000000000000000`
* salt `0x0000000000000000000000000000000000000000000000000000000000000000`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 1
* address `0xdeadbeef00000000000000000000000000000000`
* salt `0x0000000000000000000000000000000000000000000000000000000000000000`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 2
* address `0xdeadbeef00000000000000000000000000000000`
* salt `0x000000000000000000000000feed000000000000000000000000000000000000`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 3
* address `0x0000000000000000000000000000000000000000`
* salt `0x0000000000000000000000000000000000000000000000000000000000000000`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 4
* address `0x00000000000000000000000000000000deadbeef`
* salt `0x00000000000000000000000000000000000000000000000000000000cafebabe`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 5
* address `0x00000000000000000000000000000000deadbeef`
* salt `0x00000000000000000000000000000000000000000000000000000000cafebabe`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

Example 6
* address `0x0000000000000000000000000000000000000000`
* salt `0x0000000000000000000000000000000000000000000000000000000000000000`
* gas (assuming no mem expansion): *TBD*
* result: *TBD*

## Backwards Compatibility

This EIP makes collisions possible. The behaviour at collisions is specified by [EIP-684](https://github.com/ethereum/EIPs/issues/684):

> If a contract creation is attempted, due to either a creation transaction or the `CREATE`, `CREATE2`, (or future `CREATE3`) opcode,
> and the destination address already has either nonzero nonce, or nonempty code, then the creation throws immediately, with exactly
> the same behavior as would arise if the first byte in the init code were an invalid opcode. This applies retroactively starting from genesis.

Specifically, if `nonce` or `code` is nonzero, then the create-operation fails.

With [EIP-161](./eip-161.md)

> Account creation transactions and the `CREATE` operation SHALL, prior to the execution of the initialisation code,
> increment the nonce over and above its normal starting value by one

This means that if a contract is created in a transaction, the `nonce` is immediately non-zero, with the side-effect
that a collision within the same transaction will always fail -- even if it's carried out from the `init_code` itself.

It should also be noted that `SELFDESTRUCT` (`0xff`) has no immediate effect on `nonce` or `code`, thus a contract cannot
be destroyed and recreated within one transaction.

## Security Considerations

This new opcode allows the contract address to be independent of the bytecode.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).