FIP-0055 Source

TitleSupporting Ethereum Accounts, Addresses, and Transactions
AuthorRaúl Kripalani, Steven Allen
Discussions-Tohttps://github.com/filecoin-project/FIPs/discussions/388 https://github.com/filecoin-project/FIPs/discussions/490 https://github.com/filecoin-project/FIPs/discussions/287
StatusAccepted
TypeTechnical Core
CategoryCore
Created2022-12-02

Spec Sections

FIP-0055: Supporting Ethereum Accounts, Addresses, and Transactions

Table of Contents generated with DocToc

Simple Summary

In order to enable existing Ethereum tools to seamlessly interact with the Filecoin network, it is necessary for Filecoin to:

  1. Recognize and deal with Ethereum addresses.
  2. Fulfill Ethereum address expectations, both for accounts (secp256k1 public key derived) and contracts.
  3. Model Ethereum’s Externally-Owned Accounts (EOAs).
  4. Support and validate native transactions issued by (EOAs) from Ethereum wallets.

This FIP delivers these requirements by leveraging the f4 extensible address class (newly introduced in FIP-0048) to model Ethereum Addresses, managed by the Ethereum Address Manager (EAM) built-in actor introduced herein.

It also introduces the Ethereum Account built-in actor to represent Ethereum Externally Owned accounts, capable of acting as message senders, and a new Delegated signature type, which enables validating native EIP-1559 Ethereum transactions carrying a secp256k1 ECDSA signatures over their RLP encoding.

Both these elements act as extension points for an eventual fully-fledged Account Abstraction framework.

Abstract

This FIP introduces three technical elements:

  1. It formally defines the f410 Ethereum address space, nested under decimal namespace 10 within the f4 address class as defined in FIP-0048. This address space is managed by the Ethereum Address Manager (EAM) built-in actor, which also offers public methods to act as a factory for EVM smart contracts. The subaddress of an f410 address is the original Ethereum address. Ethereum addresses can be cast as f410 addresses, and viceversa.

  2. The Ethereum Account built-in actor, representing an Externally-Owned Ethereum account, backed by a secp256k1 key, and capable of acting as a sender of native EIP-1559 Ethereum transactions. This actor will become an Abstract Account (AA) actor, if and when such framework is eventually introduced in the protocol.

  3. The Delegated signature type, carrying a signature eventually verified by actor code through Account Abstraction (AA). At this time, Delegated signatures are special-cased secp256k1 ECDSA signatures over the RLP encoding of native EIP-1559 Ethereum transactions.

Finally, it extends the existing Account actor (f1/f3) to align it with the Ethereum Account actor and the Placeholder actor by making it accept all methods greater than or equal to the minimum FRC-0042 method number (2^24).

Change Motivation

The FVM is a multi-runtime execution environment, designed to accommodate various runtimes atop a Wasm-based foundation. Supporting foreign addressing schemes, account models, and transaction formats is important to achieve full portability of programs, tools, libraries, and know-how to Filecoin.

In the case of the EVM runtime introduced in FIP-0054, the runtime itself, as well as EVM smart contracts and tools, make various assumptions about addresses. Concretely about their data type (uint160), derivation (from public key for accounts), and/or generation. Fulfilling these assumptions is essential to avoid (a) breakage of original smart contracts and (b) long-ranged codebase forks with patches that would result in maintenance hell for Core Devs. In addition, we’d like to refrain from baking these assumptions into the core protocol to avoid external coupling and unsustainable bespoke specialization.

We reconcile these requirements and constraints by modelling Ethereum addresses over the brand new f4 delegated address class, under a dedicated namespace, managed by the Ethereum Address Manager actor introduced herein.

Furthermore, when porting foreign runtimes to Filecoin, it is highly desirable to retain full tool and ecosystem stack compatibility with Filecoin. This involves supporting transactions issued from existing wallets without modifications, verifying their native signature and authentication schemes. The Delegated signature type and the Ethereum Account actor enable this. They also serve as cornerstones for a future fully-fledged Account Abstraction (AA) framework in Filecoin.

Specification

Ethereum Address Manager (EAM)

We introduce the Ethereum Address Manager (EAM) built-in actor as a singleton built-in actor, sitting at ID address f010.

This actor manages the Ethereum address space, anchored at the f4 address namespace equalling its actor ID (10 in decimal). For more information on the f4 address class, refer to FIP-0048.

The subaddress is the literal Ethereum address in binary form.

#
# Ethereum address in Filecoin as an f4 address
#

0x04 || 0x10 || <binary Ethereum address>
|       |       |
A       B       C

# A: address class, also termed "protocol"
# B: leb128-encoded actor ID of address manager (termed "namespace")
# C: subaddress within the namespace

In textual form, this is represented as follows:

#
# Textual form of the above address
#

"f4" || "10" || <eth address || checksum>
|       |       |
A       B       C

# A: address class, also termed "protocol"
# B: namespace as a decimal number with no padding
# C: subaddress (in this case the Ethereum address) with checksum appended, base32 encoded

The EAM also acts like an EVM smart contract factory, offering methods that respect the Ethereum address generation rules and semantics for the original CREATE and CREATE2 mechanisms.

Installation and wiring

During migration:

  1. The Wasm bytecode of the EAM (referred by its CodeCID) is linked under the System actor’s registry under the key "eam".
  2. A single copy of the EAM is deployed as a singleton actor under ID address f010.
  3. A new version of the Init actor that recognized the EAM as an authorized delegated address manager is deployed, by loading its Wasm bytecode to the blockstore, linking its CodeCID in the System actor, and updating f01’s CodeCID to it in the state tree.
  4. An Ethereum Account actor is created in the state tree with balance zero, nonce zero, and delegated address f410faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaonc6iji (as per FIP-0048), corresponding to the Ethereum Null Address (0x0).

Relationship with the Init actor

The Init actor statically recognizes the EAM as an authorized delegated address manager, and allows it to call its InitActor#Exec4 method. Note that address managers like the EAM use the InitActor#Exec4 method to deploy new actors with a delegated f4 address under the namespace matching their actor ID (10 in this case). The caller provides the subaddress as an argument to such method. For more details, refer to FIP-0048.

State

This actor has no state. The actor’s Head field in the state tree is the EMPTY_ARR_CID static value, defined as the CID of an empty CBOR byte string.

Constructor (method number 1)

The Constructor has no functional relevance. It is merely a safeguard to prevent accidental instantiation by users by asserting that:

  1. It is being called by the System actor (f00).
  2. It has been deployed on address f10.

The Constructor takes no input parameters and produces no return value. It returns the USR_FORBIDDEN (18) exit code when the above assumptions are unmet.

Contract factory methods

To act like an EVM smart contract factory, the EAM offers three Filecoin methods:

  1. Create (method number 2).
  2. Create2 (method number 3).
  3. CreateExternal (method number 4).

All these methods create new EVM actors but have slightly different semantics, parameters, and permissions.

In general:

  1. The contract deployment message is directed to one of the Create, Create2, or CreateExternal methods of the EAM, containing the EVM init bytecode and further arguments (see below).
  2. The EAM determines the caller’s Ethereum address by:
    1. First attempting to extract it from the caller’s f4 address.
    2. Otherwise, the EAM creates an “embedded ID address” from the caller’s ID.
  3. The EAM computes the would-be Ethereum address, respecting the original Ethereum semantics where applicable, thus retaining tool compatibility.
  4. The EAM exits with USR_FORBIDDEN if said address is a reserved precompile address or an embedded ID address:
    1. Is in the range 0x00-0xff.
    2. Is in the range 0xfe000...000-0xfe000...0ff.
    3. Is in the range 0xff000...00000000000000000-0xff000-0ffffffffffffffff.
  5. If an EVM contract has already been deployed to the target address, the EAM attempts to resurrect the contract.
    1. It calls the Resurrect method (see [FIP-0055]) with the given initcode and the caller’s address.
    2. If successful, the EAM returns the actor’s ID and Ethereum address (see Return below).
    3. Otherwise, the EAM propagates the exit code from Resurrect.
  6. Otherwise, the EAM invokes the Init actor’s Exec4 method (see FIP-0048), supplying:
    • The CodeCID of the EVM runtime actor (introduced in FIP-0054).
    • The EVM runtime actor’s constructor parameters, concretely the EVM init code and the address of the original creator.
    • The computed Ethereum address, which the Init actor uses as the subaddress to form the f410 address for binding it in its address registry.
  7. The EAM returns the new actor’s ID, f2 address, and the Ethereum address (see Return below).
// DAG-CBOR tuple encoded.
pub struct Return {
    /// The ID of the EVM runtime actor that was constructed.
    pub actor_id: ActorID,
    /// Its f2 address.
    pub robust_address: Option<Address>,
    /// Its Ethereum address, translatable to an `f410` address.
    pub eth_address: [u8; 20],
}
Create

The Create method may only be called by the EVM’s CREATE opcode. It’s called with:

// DAG-CBOR tuple encoded.
pub struct CreateParams {
    /// EVM init code.
    pub initcode: Vec<u8>,
    /// Nonce with which to create this smart contract.
    pub nonce: u64,
}

After verifying that the caller is an EVM contract, the Create method computes the address as the last 20 bytes of Keccak-256(rlp_list(caller_eth_address, nonce)) then follows the general contract deployment logic specified above.

Note that this method differs from Ethereum in that we take a user-provided nonce as a parameter. This is necessary for the EAM to learn the nonce of a contract, when the CREATE opcode is used and is secure because:

  1. This method may only be invoked by the EVM runtime (the caller must be an EVM contract, and the call_actor precompile (see [FIP-0055]) cannot invoke methods < 1024.
  2. The system itself prevents deploying over existing actors.
Create2

The Create2 method may only be called by the EVM’s CREATE2 opcode. It’s called with:

// DAG-CBOR tuple encoded.
pub struct CreateParams {
    /// EVM init code.
    pub initcode: Vec<u8>,
    /// Salt from which to derive the new contract's address.
    pub salt: [u8; 32],
}

After verifying that the caller is an EVM contract, the Create2 method computes the address as the last 20 bytes of Keccak-256(concat([0xff], caller_eth_addr, salt, Keccak-256(initcode))) then follows the general contract deployment logic specified above.

CreateExternal

The CreateExternal method may only be called by externally owned accounts (currently EthAccount and native Accounts).

CreateExternal computes the address according to the same logic as Create with two key differences:

  1. The nonce comes from the top-level message, not the method parameters.
  2. If the caller is a native account, the new contract’s address is not derived from the caller’s Ethereum address as the caller’s Ethereum address will be an embedded ID address, which isn’t reorg stable. Instead, the caller_eth_addr input to the Create address computation logic is set to the last 20 bytes of Keccak-256(caller_key_addr).

Delegated signature type

We introduce a new Delegated signature type for Filecoin messages with serialized value 3. Delegated signatures are opaque to the protocol, and are validated by actor logic. Delegated signatures will be used in combination with abstract account senders, once Account Abstraction (AA) is fully realized. However, we establish a transitory period where Delegated signatures are special-cased.

Transitory validation

We establish a transitory period whereby Delegated signatures are assumed to be secp256k1 signatures over the RLP representation of a native EIP-1559 Ethereum transaction sent from an Ethereum Account actor. During this period, all senders of messages with Delegated signatures must have an f410 address, that is, an address under the EAM’s namespace.

Additionally, delegated signatures are restricted to:

  1. Messages to the Ethereum Address Manager (f010), calling its CreateExternal method, and carrying a non-empty, validly CBOR-encoded byte array as its parameters (with no extra bytes)
  2. Messages to ID addresses (f0) other than f010, and messages to f410 addresses (f4 addresses assigned by the EAM) with MethodNum equal to the EVM built-in actor’s InvokeContract method number (frc42_hash("InvokeEVM")), and carrying a validly CBOR-encoded byte array as its parameters (with no extra bytes).

A message carrying a Delegated signature that does not meet one of these criteria is considered to have an invalid signature.

The RLP representation is reconstituted from the Filecoin message as specified below. This effectively couples the Delegated signature type to its only possible use at this stage, but provides an extension point for the future introduction of Account Abstraction (AA).

Such transitory Delegated signatures must be verified by:

  1. Reforming and repacking the native RLP-encoded EIP-1559 Ethereum transaction from the Filecoin message (original signature payload).
  2. Recovering the secp256k1 public key from such payload and the ECDSA signature bytes inside the Delegated signature.
  3. Computing the Ethereum address from the secp256k1 public key by hashing the public key using Keccak-256, and retaining the last 20 bytes (i.e. original Ethereum address derivation logic).
  4. Casting to an f410 address (see conversion rules EAM rules).
  5. Asserting that the message sender’s f410 address matches the computed f410 address.
  6. Forming the inverse of the reformed RLP-encoded message (converting back into a Filecoin message), and ensuring that it matches the original signature payload.

Should any of these steps fail, the signature must be considered invalid.

The client must perform this verification before chain inclusion, and before handing off the message to the FVM for execution.

Payload reconstitution (FilecoinMessage -> RLP-encoding)

To verify the Delegated signature, the unsigned RLP-encoded EIP-1559 Ethereum transaction is reconstituted in the following way from the Filecoin message. The top-level object is an RLP list, and integers are encoded in the RLP way (big endian with no leading zeroes)

Pos Ethereum Field Source
0 Chain ID Static network-specific chain ID, re-encoded as an RLP integer
1 Nonce FilecoinMessage#Nonce, re-encoded as an RLP integer
2 Max priority fee gas FilecoinMessage#GasPremium, re-encoded as an RLP integer
3 Max fee per gas FilecoinMessage#GasFeeCap, re-encoded as an RLP integer
4 Gas limit FilecoinMessage#GasLimit, re-encoded as an RLP integer
5 Recipient Ethereum address extracted from the f410 or f0 address in FilecoinMessage#To, or nil if f010 (EAM), as this denotes a contract deployment, re-encoded as an RLP byte string
6 Value FilecoinMessage#Value, re-encoded as an RLP integer
7 Input data CBOR-deserialization of FilecoinMessage#Params as a CBOR byte string, and re-encoded as an RLP byte string
8 Access list Empty.

Additionally, this conversion asserts that:

  1. The sender address is a valid f410 address with a 20 byte payload.
  2. The recipient is either a valid f410 address or a valid f0 address.
  3. If the recipient is f010 (EAM), FilecoinMessage#Method is EAM#CreateExternal (4). Otherwise, FilecoinMessage#Method is EVM#InvokeContract (3844450837).
  4. The message version is 0.
  5. The parameters contain no additional values or bytes beyond the CBOR encoded byte string.

If these conditions are not met, the signature is considered invalid.

Calculating the inverse (RLP-encoding -> FilecoinMessage)

To fully guarantee fidelity of the signature over the RLP-encoded payload, we re-calculate the Filecoin message, as an inverse of the payload calculated above. If the CBOR-serialization of the inverse does not precisely match that of the original Filecoin message, the signature is considered invalid. We do so as follows:

Pos Filecoin Message Field Source
0 Version 0, the only supported Message version on Filecoin as of this FIP
1 Recipient Filecoin address converted (f410 or ID address) from the EthereumTransaction#To field, or f010 if nil as this denotes a contract deployment
2 Sender The message’s sender (Ethereum address) encoded as an f410 address, extracted from the transaction’s signature through EcRecover
3 Nonce EthereumTransaction#Nonce
4 Value EthereumTransaction#Value
5 Gas Limit EthereumTransaction#GasLimit
6 Gas Fee Cap EthereumTransaction#GasFeeCap
7 Gas Premium EthereumTransaction#MaxPriorityFeeGas
8 Method EAM::CreateExternal, if EthereumTransaction#To is nil. EVM::InvokeContract otherwise
9 Params CBOR-serialization of the byte array EthereumTransaction#Input.

Ethereum Account

We introduce the Ethereum Account, a non-singleton built-in actor representing an external Ethereum identity backed by a secp256k1 key. The Ethereum Account must be recognized by the FVM and by clients as a valid message sender of messages with Delegated signatures, as per the scheme above. Ethereum Accounts can only submit RLP-encoded EIP-1559 Ethereum transactions.

Installation and wiring

During the migration where this FIP goes live, the Wasm bytecode of the Ethereum Account (referred to by its CodeCID) is linked under the System actor’s registry under the key "ethaccount".

Sender account

Filecoin clients and the FVM recognize the Ethereum Account as an authorized message sender. This includes components validating and executing messages, like the message pool, chain syncer, and executor.

Promotion

When the FVM executes the first message fulfilling the following characteristics, it promotes the Placeholder actor into an Ethereum Account by updating its CodeCID in-place, prior to executing the message.

  1. The message carries a valid transitory Delegated signature.
  2. The message carries nonce zero.
  3. The message carries a gas limit sufficient to cover chain inclusion.
  4. The f410 address resolved from the recovered public secp256k1 key corresponds to a Placeholder actor.

The promotion remains effective even if the message itself results in an exit code other than 0, including out of gas.

Failure to meet chain inclusion gas will prevent the inclusion of the message and, therefore, will not promote the Placeholder into an Ethereum Account, even if we technically ascertained that the Placeholder corresponds to an Externally-Owned Account.

Actor interface

This actor implements one method:

  1. A Constructor that:
    1. Takes no parameters and returns no parameters.
    2. Asserts that the caller is the system actor (not the init actor). An EthAccount can only be constructed by promoting a Placeholder on first send.

Additionally, this actor returns success (instead of rejecting the call with an “unhandled message” error) when called with any method numbers greater than or equal to the minimum FRC-0042 method number (2^24).

State

This actor has no state. The actor’s Head field in the state tree is the EMPTY_ARR_CID static value, defined as the CID of an empty CBOR byte string.

Account Changes

The account actor is changed to do nothing and return success for all methods greater than or equal to the minimum FRC-0042 method number to match the Ethereum Account actor.

Design Rationale

AuthenticateMessage (FIP0044)

We chose to not implement AuthenticateMessage for now as there a few troublesome edge-cases and no clear use-cases. Specifically:

  1. AuthenticateMessage will fail for “placeholders”. Specifically, if a user sends to a non-existent f410 address, the placeholder deployed at that address will not implement AuthenticateMessage (until an EthAccount gets deployed to that address on first send).
  2. How AuthenticateMessage should be implemented with respect to the eth_sign JSON-RPC method is unclear. Specifically, whether or not to internally prepends the “Ethereum Signed Message:” prefix as done by eth_sign.

We expect that this method will eventually be implemented on EthAccounts once there’s a guiding use-case (and once the quirks around placeholders can be worked out).

Accepting v. Rejecting Calls on Accounts

As of this FIP, both account types now accept calls to all method numbers greater than or equal to 2^24:

  1. This means all accounts become “universal acceptors” and will automatically accept any funds deposited via FRC-0042 interfaces in the future. Previously, the built-in account explicitly implemented the FRC-0053 universal receiver hook, but this is no longer necessary.
  2. Method numbers less than 2^24 still reject calls by default to be conservative and to mirror the private-use behavior implemented in other built-in actors. This restriction will likely be lifted or altered in the future.

Upgrade path towards Account Abstraction (AA)

We prototyped Account Abstraction solutions extensively before submitting this FIP. This FIP preserves the key extension points that will facilitate a (projected) elegant transition to fully-fledged Account Abstraction (AA).

We forecast these rough steps to conduct the transition:

  1. Remove Delegated signature validation logic from clients, treating the signature as an opaque blob at the client level.
  2. Perform AA-specific gas preflight checks in the client before accepting the message for inclusion, or propagating via the mpool.
  3. Move the Ethereum transaction signature verification logic inside the ethaccount actor, so that it runs on-chain.
  4. Generalise the Placeholder actor promotion path so that the relevant address manager gets to indicate the promotion target. Reconcile with (3).
  5. Trigger the signature validation logic within the FVM when the sender is an Abstract Account.

Backwards Compatibility

On a functional level, backwards compatibility is not affected, as this FIP introduces strictly additive features. However, implementing this FIP will require built-in actor changes. We expect the CodeCIDs of all built-in actors to be altered, as a consequence of the new and adjusted logic. The new actor code will need to be linked in the System actor, and the CodeCID of all existing actors in the state tree will need to be patched to their new counterparts.

Test Cases

The reference implementations will include tests.

This FIP may be enhanced with test vectors covering Delegated signature verification scenarios.

Security Considerations

New signature type

This FIP introduces a new signature type and a new transaction format to the protocol. That is, we introduce new pathways to initiate transactions in the system, and extend the kinds of payloads that are entitled to do so.

It is worthy to note that Filecoin already supports secp256k1 ECDSA signatures under signature type 1. Clients are expected to reuse existing signature verification and key recovery logic. However, what differs is the authentication logic. The original signature payload must be reconstructed by repacking the RLP-encoded EIP-1559 Ethereum transaction. Any flaws in this logic is subject to security events.

Inability to stably address some actors from EVM smart contracts

The current solution only assigns f410 addresses to Ethereum Accounts and EVM smart contracts.

These interactions can benefit from stable f410 addressing:

  1. Cross-contract calls and value transfers (EVM <> EVM).
  2. Ethereum account to contract calls and value transfers, and viceversa (Eth Account <> EVM).

These interactions cannot benefit from stable addressing:

  1. EVM smart contracts calls and transfers to Wasm actors.
  2. EVM smart contract value transfers to non-Ethereum accounts (f1/f3 addresses).

If an EVM smart contract wishes to interact with a Wasm actor, it must use a masked ID address (0xff0000..<id address> style addresses).

Unfortunately, contrary to f410 addresses, ID addresses are not reorg stable. In other words, the ID may be reassigned within the chain’s finality window, hence this security notice. Note that even if the theoretical finality window is 900 epochs, the probability of reorgs decays as the chain progresses from the ID assignment.

The implications of this limitation are as follows:

  1. Not a problem for singleton actors (e.g. power actor, storage market actor, etc.), as their ID addresses are fixed, but may be problematic for non-singleton actors.
  2. As per FIP-0050, the only non-singleton actor callable by EVM smart contracts is the Miner actor. Interactions with recently-created miner actors are subject to reorg sensitivity.
  3. Tranferring value to an f1 or f3 account can only be done via its masked ID address and is thus subject to reorg sensitivity.
  4. Transferring value to Wasm non-singleton non-account actors (e.g. payment channels or multisigs) is also subject to reorg sensitivity.
  5. Transferring value to an inexistent f1 and f3 address from a smart contract is not possible as no ID address exists yet.

Unfortunately the protocol does not offer a built-in way to fetch the creation epoch of an actor, so implementing timing guards to prevent transfers or calls to reorgable ID addresses within contracts is impossible.

Note that we deliberately discarded assigning f410 addresses to non-Ethereum related actors at this stage to favor design simplicity in an already complex feature set, but we may revisit this decision in the future.

Incentive Considerations

No incentive considerations apply.

Product Considerations

Essential for ecosystem compatibility

This FIP is essential to enable the product aspirations of FEVM (Filecoin EVM), concretely the seamless compatibility with existing Ethereum wallets, libraries, and tools.

Explorer adaptation

Explorers will need to adapt to display f410 addresses bound to actors and their respective Ethereum addresses, on actor pages, message pages, and more.

Explorers will need to recognize Ethereum Account actors and Delegated signatures.

Exchange adaptation

Exchanges must support receiving funds from EVM smart contracts.

Exchange may choose to enable sending to f410 addresses, and may support taking in Ethereum addresses and converting them to f410 addresses.

Restrictions on Delegated Signature payload

As specified above, we place several restrictions on messages that carry a delegated signature, limiting them to certain specific Ethereum-related cases. This is because this FIP introduces a transitory period where Delegated signatures are special-cased to meet the product goals of the FEVM. Placing these restrictions allows us to avoid compromising on the longer-term goals of Account Abstraction, while still immediately enabling compatibility with the existing Ethereum ecosystem.

These restrictions will be removed as we upgrade towards Account Abstraction.

Implementation

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Raúl Kripalani, Steven Allen, "FIP-0055: Supporting Ethereum Accounts, Addresses, and Transactions," Filecoin Improvement Proposals, no. 0055, December 2022. [Online serial]. Available: https://fips.filecoin.io/fips/fip-0055.