EIP-2718: Typed Transaction Envelope

Anmol DhimanAnmol Dhiman
2 min read

Before This EIP

Prior to EIP-2718, transactions were simply RLP-encoded data beginning with values in the range [0xc0, 0xfe], as specified in RLP encoding rules. There was no mechanism to distinguish between different transaction types or handle them uniquely, despite a clear need for such functionality. Without a way to differentiate transactions, establishing rules for their identification would have been complex and prone to errors.

How This EIP Works

With EIP-2718, a valid transaction is now structured as TransactionType || TransactionPayload, and a valid transaction receipt is TransactionType || ReceiptPayload.

[ || represents the concatenation operator ]

  • Here,

    • TransactionType is a value in the range [0, 0x7f].

    • TransactionPayload and ReceiptPayload are RLP-encoded byte sequences.

Both the transaction type and its associated payload are specified in future EIPs whenever a new transaction type is introduced.

Now, clients (i.e., nodes) can differentiate transactions based on their starting byte:

  • If a transaction begins with a value in [0, 0x7f], it is recognized as a typed transaction.

  • If it starts with [0xc0, 0xfe] (per RLP encoding rules), it is treated as a legacy transaction.

Inside the Block

  • For Transactions:
    patriciaTrie(rlp(Index) => Transaction)
    Where:

    1. Index is the transaction’s position within the block.

    2. Transaction can be either TransactionType || TransactionPayload (for typed transactions) or LegacyTransaction (for legacy transactions).

    3. LegacyTransaction is an RLP-encoded payload without a transaction type, starting with [0xc0, 0xfe] as per RLP rules, i.e., rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]).

  • For Receipts:
    patriciaTrie(rlp(Index) => Receipt)
    Where:

    1. Index is the receipt’s position in the receipt Merkle tree.

    2. Receipt can be either TransactionType || ReceiptPayload (for typed receipts) or LegacyReceipt (for legacy receipts).

    3. LegacyReceipt is encoded as rlp([status, cumulativeGasUsed, logsBloom, logs]).

Additionally, the TransactionType of a receipt must match the TransactionType of the corresponding transaction with the same Index.

Security Considerations

For any transaction compatible with EIP-2718, users must sign both the type and the payload together. If a user signs only the payload and prepends the type before broadcasting it to the network, the transaction could be interpreted as a legacy transaction. This is a critical requirement—signing both type and payload prevents compatibility with other transaction types, which could otherwise lead to a signature malleability attack.

0
Subscribe to my newsletter

Read articles from Anmol Dhiman directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anmol Dhiman
Anmol Dhiman

Prev - @kleros || ETHBangkok'24 🏆 || ETHIndia'23 🏆 || SSIP AKAMH'22 🏆 || Blockchain Security Researcher