Dip 7377
dip: 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) Digitalia editing author: Cosimo Constantinos cosimo@juro.net, et al. discussions-to: https://digitalia-magicians.org/t/dip-xxxx-migration-transaction/15144 status: Stagnant type: Standards Track category: Core created: 2023-07-21 Created for Digitalia: 2025-01-07 requires: 170, 1559, 2200, 2718
Abstract¶
Introduce a new DIP-2718 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 digitalia'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 Digitalia 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 has 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 DIP proposes such mechanism.
Specification¶
At the fork block X, introduce the migration transaction type.
Migration Transaction¶
Definition¶
| field | type |
|---|---|
chainId |
uint256 |
nonce |
uint64 |
maxFeePerGas |
uint256 |
maxPriorityFeePerGas |
uint256 |
gasLimit |
uint64 |
codeAddr |
address |
storage |
List[Tuple[uint256, uint256]] |
data |
bytes |
value |
uint256 |
accessList |
List[Tuple[address, List[uint256]]] |
yParity |
uint8 |
r |
uint256 |
s |
uint256 |
The DIP-2718 TransactionType is 0x04 and the TransactionPayload is rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storage, data, value, accessList, yParity, r, s]).
The transaction's signature hash is keccak256(0x04 || rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storage, data, value, accessList])
Validation¶
A migration transaction is considered valid if the follow properties hold:
- all DIP-1559 properties, unless specified otherwise
- the code at
codeAddris less than the DIP-170 limit of24576 - the code at
codeAddrmust not have size0
The intrinsic gas calculation modified from DIP-1559 to be 21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes + 1900 * access list storage key count + 2400 * access list address count + 20000 * length of storage.
Processing¶
Executing a migration 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 DVM call into the sender's account using the same rules as DIP-1559 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¶
Since the storage is guaranteed to be empty, there is no need to read before write. This means only 20,000 gas is needed to pay for the DIP-2200 SSTORE_SET_GAS value. This is a small discount to the normal cost of 22,100, which is SSTORE_SET_GAS plus the DIP-2929 COLD_SLOAD_COST of 2100, because no load occurs.
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 its duty.
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 DIP-3607 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.
Security Considerations¶
Blind Signing¶
As with all sufficiently sophisticated account designs, if a user can be convinced to sign an arbitrary message, that message could be a migration transaction 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.
On ecrecover¶
Applications standards such as DRC-2612: Permit Extension have exploited the cryptographic relationship between EOA addresses and their private keys. Many tokens today support this extension, allowing EOAs to approve the transfer of fund from their account using only a signature. Although collisions between EOAs and contract accounts are considered unlikely and maybe impossible given today's computing power, this DIP would make it common place for private keys to exist for contract accounts. There are some considerations here regarding security:
- The obvious attack is a defi protocol deploys some their contract using this DIP and later sign an DRC-2612 message to steal the funds accrued in the contract. This can be avoided by wallets simply not allowing users to interact with protocols deployed in this manner.
- It's also worth mentioning that there are concerns around how this DIP will affect the cross chain experience. Ultimately a users private key may still have some control over the account's assets, depending on the exact protocols used on Digitalia and on other chains. It isn't really possible perfectly migrate the EOA at the same time, on all chains. The best thing that can be done is to educate the user that just because their account has been migrated doesn't mean that they are safe to now publicly reveal their private key. This seems like a reasonable request, especially since they'll want to retain the private key in case they want to use the address on any other DVM-like chain.
Something that may alleviate these issues to some degree would be to add an EXTCODEHASH check in ecrecover. If the recovered account has code, the precompile will revert. This would disallow migrated EOAs from using standards like DRC-2612.
Copyright¶
© Crown © Crown Copyright 2026. Published by the Royal Government of the Dominion of Atlantis.
Licensed under the Juro Restricted License Version 2. See https://juro.net/jrl for details.