Facet Transaction Spec

Overview

Facet transactions are the primary mechanism for interacting with the Facet protocol. They follow a format similar to EIP-1559 Ethereum transactions and Optimism's Deposit transactions, with specific adaptations for the Facet ecosystem.

Transaction Format

Facet transactions use the EIP-2718 transaction type 0x46 (70 in base 10) and contain the following fields:

Field
Description

chain_id

Distinguishes the payload as being relevant only to Facet • Mainnet: 1027303 (0xface7 in hex) • Sepolia testnet: 16436858 (0xface7a in hex)

to

L2 recipient's address (EOA or L2 contract). Blank for contract creations

value

Amount of FCT being transferred in the transaction

max_fee_per_gas

Maximum fee user is willing to pay per unit of gas for transaction inclusion

gas_limit

The gas limit of the L2 transaction

data

EVM input data (ABI encoded contract call or contract creation code)

mine_boost

Optional appended data that increases payload size to increase FCT mining (see below)

Important: Facet transactions have no signature field. The "from" address is inferred from the properties of the Ethereum transaction in which they are delivered.

Serialization Format

Facet transactions must be serialized in this specific format for Facet nodes to process them:

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

Transaction Submission Methods

There are two methods to submit Facet transactions to the network:

Method 1: From EOA via Calldata

EOAs (Externally Owned Accounts) can create Facet transactions by sending a successful Ethereum transaction (receipt status = 1) to the Facet inbox address:

0x00000000000000000000000000000000000face7

This L1 transaction acts as an "envelope" that carries the RLP-encoded Facet transaction as a payload within its calldata. The signer of the Ethereum envelope transaction determines the "from" address on the Facet transaction.

Implementation Example (TypeScript/Viem)

const transactionData = [
  toHex(l2ChainId),
  to ?? "0x",
  value ? toHex(value) : "0x",
  gasLimit ? toHex(gasLimit) : "0x",
  data ?? "0x",
  mineBoost ?? "0x"
];

const encodedTransaction = concatHex([toHex(70), toRlp(transactionData)]);

const l1Transaction = {
  account: l1WalletClient.account,
  to: "0x00000000000000000000000000000000000face7",
  value: 0n,
  data: encodedTransaction,
  chain: l1WalletClient.chain,
};

await l1WalletClient.sendTransaction(l1Transaction);

Method 2: From L1 Smart Contract via Event Logs

L1 Smart Contracts can create Facet transactions by emitting events identified by the Facet event signature:

0x00000000000000000000000000000000000000000000000000000000000face7

The event's data payload contains the same RLP-encoded transaction that would be used in the calldata of an EOA-originated Facet transaction.

Implementation Example (Solidity)

import { LibRLP } from "lib/solady/src/utils/LibRLP.sol";

contract FacetSender {
    using LibRLP for LibRLP.List;

    bytes32 constant facetEventSignature = 0x00000000000000000000000000000000000000000000000000000000000face7;
    uint8 constant facetTxType = 0x46;

    function sendFacetTransaction(
        uint256 chainId,
        bytes memory to,
        uint256 value,
        uint256 gasLimit,
        bytes memory data,
        bytes memory mineBoost
    ) internal {
        LibRLP.List memory list;

        list.p(chainId);
        list.p(to);
        list.p(value);
        list.p(gasLimit);
        list.p(data);
        list.p(mineBoost);

        bytes memory payload = abi.encodePacked(facetTxType, list.encode());
        
        assembly {
            log1(add(payload, 32), mload(payload), facetEventSignature)
        }
    }
}

Key Differences Between Methods

Aspect
EOA (Calldata)
Smart Contract (Event Log)

Sender Type

Externally Owned Account

L1 Smart Contract

Delivery Method

Transaction calldata to inbox address

Event emission with Facet signature

From Address

EOA that signed the L1 transaction

Smart contract that emitted the event

Use Case

Direct user interactions

Programmatic/bridged transactions

Best Practices

  1. Chain ID Verification: Always ensure you're using the correct chain ID for your target network (mainnet vs testnet)

  2. Gas Estimation: Properly estimate gas limits to ensure transaction success

  3. Error Handling: Verify that L1 transactions have a successful receipt status before considering the Facet transaction submitted

  4. Mine Boost: Use the optional mine_boost field strategically to increase FCT mining rewards when needed

Security Considerations

  • The Facet inbox address (0x00000000000000000000000000000000000face7) has no known private key, ensuring it cannot be controlled by any party

  • Always validate transaction parameters before submission

  • Monitor L1 transaction success to ensure proper Facet transaction delivery

Last updated