Facet V2 Transaction Structure

The Basics

To create a Facet transaction you send a successful (receipt status = 1) Ethereum transaction to the Facet inbox address (0x00000000000000000000000000000000000face7) with an encoded Facet transaction in its calldata.

Facet transactions are encoded as EIP-2718 transactions, but as they have different fields than existing Ethereum transactions they have their own tx type which is 0x46 (70 in decimal). 0x46 is the ASCII code for the letter F.

The Facet payload format is:

0x46 ++ rlp_encode([chain_id, to, value, max_fee_per_gas, gas_limit, data])

Where ++ denotes binary concatenation. For Facet mainnet chain_id will be 0x0face7, for testnet 0x0face7a. The other fields should be familiar:

  • To: The recipient's address. Can be an EOA or smart contract address, or, when left empty, this field signifies you are creating a new Facet smart contract.

  • Value: The amount of Facet Compute Token that you are sending with the transaction.

  • Max Fee Per Gas: This behaves the same as the corresponding EIP-1559 transaction field, specifying the max amount in FCT wei you are willing to pay per gas unit. Note:

    • On Facet there is no mempool. This means that if your transaction is underpriced (i.e., max fee per gas is less than the block's base fee) it will fail immediately and you will have to send a fresh transaction to replace it.

    • There is no max_priority_fee_per_gas field. Facet transaction priority / ordering is completely determined by L1 transaction ordering.

  • Gas Limit: the maximum number of gas units you're willing to spend. Works like the corresponding field in normal Ethereum transactions.

  • Data: your calldata

Creating Multiple Facet Transactions per Ethereum Transaction

For simplicity we have treated Facet transactions as 1-to-1 with Ethereum transactions. However it is actually possible to create an unlimited number of Facet transactions in a single Ethereum transaction! This is because Facet transactions are actually 1-to-1 with Ethereum transaction calls and an Ethereum transaction can have multiple calls.

What is a call? An Ethereum transaction as a whole is a call, and also whenever a smart contract calls another address that constitutes a call.

For example, if I send a transaction to smart contract A and smart contract A calls (say) balanceOf on smart contract B, then that overall transaction will have two calls: one for the transaction itself and one for the call from A to B.

You can view a transaction's calls in Etherscan here:

Formally, a transaction's calls are what is returned by the debug_traceTransaction RPC endpoint.

The protocol looks at these calls and creates a Facet transaction for each successful call that is sent to the Facet inbox address and has the correct Facet payload in its data field.

What about Ethscriptions?

In Facet V1 payloads were Ethscriptions, not EIP-2718 transactions. There were some advantages to this approach, but Ethscriptions were not the best choice for this specific use-case. There are a few reasons for this. First, the Ethscriptions protocol lacks some important features for the Facet use-case:

  • Ethscriptions are a text-based format which is inefficient for expressing binary data

  • Ethscriptions don't support batching (multiple Ethscriptions per Ethereum transaction)

  • Ethscription creations are event-based which makes it challenging for smart contract wallets

Even if we could upgrade the Ethscriptions protocol to fix these, we would still have the most significant hurdle which is that developers don't want to add a dependency and learn a new protocol unless it adds significant value.

Though the Facet Protocol itself is now separate from Ethscriptions, this is the only change. The creators of the Facet Protocol remain devoted to the growth of the Ethscriptions Protocol.

Last updated