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 EIP: Migration Transaction #7377

Merged
merged 16 commits into from
Jul 26, 2023
121 changes: 121 additions & 0 deletions EIPS/eip-7377.md
lightclient marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
eip: 7377
title: Migration Transaction
description: Allow EOAs to send a one-time transaction which deploys code at their account.
author: lightclient (@lightclient), Sam Wilson (@samwilsn), Ansgar Dietrichs (@adietrichs)
discussions-to: https://ethereum-magicians.org/t/eip-xxxx-migration-transaction/15144
status: Draft
type: Standards Track
category: Core
created: 2023-07-21
requires: 170, 1559, 2718
lightclient marked this conversation as resolved.
Show resolved Hide resolved
---

## Abstract

Introduce a new [EIP-2718](./eip-2718.md) transaction type with the format `0x04 || rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storage, data, value, accessList, yParity, r, s])` which sets the sending account's `code` field in the state trie to the `code` value at `codeAddr` and applies the storage tuples to the sender's storage trie.

## Motivation

Smart contract wallets have long been touted as the solution to Ethereum's user experience woes. As early as 2015, there were proposals for allowing smart contracts to originate transactions in hopes that new users would flock to smart contract wallets to store their assets. So far, only a fraction of users have elected to do so.

Today, account abstraction is still an important goal in Ethereum and there are many efforts attempting to realize it. We're getting closer to succeeding at this, but unfortunately the years of failure have caused many users to simply rely on EOA.

After a user as accumulated enough assets in an EOA, it is not tenable to migrate each individual asset to a new address. This is due both to the cost and to needing to manually sign and verify potentially hundreds of transactions.

This is an overlooked piece of the problem. Converting *existing* users to smart contract wallets efficiently, will expedite adoption and push forward better support and integrations for smart contract wallets. They will no longer be dismissed as a niche use case.

Therefore, we must provide a mechanism, embedded in the protocol, to migrate EOAs to smart contracts. This EIP proposes such mechanism.

## Specification

At the fork block `X`, introduce the migration transaction type.

### Migration Transaction

#### Definition

| field | type |
|------------------------|-----------|
| `chainId` | `int256` |
| `nonce` | `uint64` |
| `maxFeePerGas` | `int256` |
| `maxPriorityFeePerGas` | `int256` |
| `gasLimit` | `uint64` |
| `codeAddr` | `address` |
| `storage` | `List[Tuple[uint256, uint256]]` |
| `data` | `bytes` |
| `value` | `int256` |
| `accessList` | `List[Tuple[address, List[uint256]]]` |
| `yParity` | `uint8` |
| `v` | `uint256` |
| `r` | `uint256` |

The EIP-2718 `TransactionType` is `0x04` and the `TransactionPayload` is `rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storageTuples, data, value, accessList, yParity, r, s])`.

The transaction's signature hash is `keccak256(0x04 || rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storageTuples, data, value, accessList])`

#### Validation

A migration transaction is considered valid if the follow properties hold:

* all [EIP-1559](./eip-1559.md) properties, unless specified otherwise
* the code at `codeAddr` is less than the [EIP-170](./eip-170.md) limit of `24576`
* the code at `codeAddr` must not have size `0`

The intrinsic gas calculation modified from [EIP-1559](./eip-1559.md) to be `21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes + 1900 * access list storage key count + 2400 * access list address count + 15000 * length of storage`.

#### Processing

Executing a migration transaction transaction has two parts.

##### Contract Deployment

Unlike standard contract deployment, a migration transaction directly specifies what `code` value the sender's account should be set to.

As the first step of processing the transaction, set the sender's `code` to `state[tx.codeAddr].code`. Next, for each tuple in `tx.storage` and the sender's storage trie, set `storage[t.first] = t.second`.

##### Transaction Execution

Now instantiate an EVM call into the sender's account using the same rules as [EIP-1559](./eip-1559.md) and set the transaction's origin to be `keccak256(sender)[0..20]`.

## Rationale

### No `to` address field

This transaction is only good for one-time use to migrate an EOA to a smart contract. It is designed to immediately call the deployed contract, which is at the sender's address, after deployment to allow the sender to do any kind of further processing.

### Code pointer for deployment

Naively, one could design the migration transaction to have a field `code` of type `bytes`. However, there would be substantial duplication of code calldata, since many users will want to deploy the exact same thing (often a wallet). Using a pointer instead acknowledges this overwhelming use case for the transaction type, and exploits it as an optimization.

### Cheaper storage

Allowing cheaper storage in this instance acts as a reward to users who migrate their EOAs to smart contract wallets.

### Intrinsic does not account for contract deployment

This takes advantage of the fact that clients tend to store a single, unique copy of code; no matter the number of deployments. Therefore, the only operation here is changing a pointer in the state trie to the desired code.

Additionally, the EOA already exists because it has enough balance for the migration transaction to be considered valid. Therefore, we don't need to pay a premium for adding a new account into the state trie.

### Manipulating transaction origin

Many applications have a security check `caller == origin` to verify the caller is an EOA. This is done to "protect" assets. While it is usually more of a bandage than an actual fix, we attempt to placate these projects by modifying the origin of the transaction so the check will continue performing it's duty.
lightclient marked this conversation as resolved.
Show resolved Hide resolved

### One-time migration

There is no technical reason we couldn't allow EOAs to change their code at any time with this transaction type. The only inhibitor at the moment is [EIP-3607](./eip-3607.md) which will cause migration transactions to be considered invalid if they come from an account with code already deployed. A functional reason for retaining this behavior though is that it makes it simpler to reason about contracts and their upgradability.

## Backwards Compatibility

No backward compatibility issues found.

Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved
## Security Considerations

As with all sufficiently sophisticated account designs, if a user can be convinced to sign an arbitrary message, that message could be MigrationTransaction which is owned by a malicious actor instead of the user. This can generally be avoided if wallets treat these transactions with *extreme* care and create as much friction and verification as possible before completing the signature.
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
As with all sufficiently sophisticated account designs, if a user can be convinced to sign an arbitrary message, that message could be MigrationTransaction which is owned by a malicious actor instead of the user. This can generally be avoided if wallets treat these transactions with *extreme* care and create as much friction and verification as possible before completing the signature.
If a user can be convinced to sign an arbitrary message by a malicious actor, that message could now set the account code of the victim. This can generally be avoided if wallets treat these transactions with *extreme* care and create a reasonable amount of friction to sign such a signature.

Copy link
Member Author

Choose a reason for hiding this comment

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

this is important

Copy link
Member

Choose a reason for hiding this comment

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

What is important? If you're talking about the "reasonable amount of friction" bit, I would be fine if that part is unchanged:

Suggested change
As with all sufficiently sophisticated account designs, if a user can be convinced to sign an arbitrary message, that message could be MigrationTransaction which is owned by a malicious actor instead of the user. This can generally be avoided if wallets treat these transactions with *extreme* care and create as much friction and verification as possible before completing the signature.
If a user can be convinced to sign an arbitrary message by a malicious actor, that message could now set the account code of the victim. This can generally be avoided if wallets treat these transactions with *extreme* care and create as much friction and verification as possible before completing the signature.

I would still argue "as much friction as possible" is NOT what you mean here - this is an EIP, and so hyperbole should not be used.

Copy link
Member Author

Choose a reason for hiding this comment

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

I am alluding to the fact that all complex account designs have this issue. That is an important part of the statement and must not be omitted.

Copy link
Member

Choose a reason for hiding this comment

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

Why is that an important part of the statement? Isn't a "sufficiently sophisticated account design" implied by a "sign an arbitrary message"?


## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).