# 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`   | <p>Distinguishes the payload as being relevant only to Facet<br>• Mainnet: <code>1027303</code> (<code>0xface7</code> in hex)<br>• Sepolia testnet: <code>16436858</code> (<code>0xface7a</code> in hex)</p> |
| `to`         | L2 recipient's address (EOA or L2 contract). Blank for contract creations                                                                                                                                    |
| `value`      | Amount of FCT being transferred in the transaction                                                                                                                                                           |
| `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])
```

## Fee Model

Facet uses a base-fee-only pricing model on L2. There is no per-transaction priority fee and no `max_fee_per_gas` field in Facet transactions. All transactions pay the current L2 base fee computed by the protocol.

## Execution on L2 (Deposit Type 0x7D)

Facet payloads are executed on L2 as deposit transactions of type `0x7D` (125 decimal). The execution-layer transaction includes fields like `sourceHash`, `from`, optional `mint`, `value` (FCT), `gas`, `isSystemTransaction`, and `data`. For hashing, the typed-transaction hash treats `mint` as zero/nil so the mint amount does not affect the transaction hash. See Reference → Chain State Derivation for full field definitions and hashing rules.

## 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.

Note on ETH value: The L1 envelope transaction to the inbox address must set `value = 0`. Never send ETH to `0xface7`. Any L2 transfer amount should be expressed via the Facet payload’s `value` field, which is denominated in FCT and applied on L2 during execution.

#### Implementation Example (TypeScript/Viem)

```typescript
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 with the following specification:

#### Event Format Requirements

**Topic Requirements:**

* **Exactly one topic**: The event MUST have exactly one topic
* **Topic value**: `0x00000000000000000000000000000000000000000000000000000000000face7`. This is `bytes32(uint256(0xface7))` - the number `0xface7` cast to uint256, then to bytes32.

**Data Requirements:**

* **Payload location**: The entire Facet transaction payload MUST be in the event's `data` field
* **Payload format**: Same RLP-encoded transaction format as calldata method (`0x46` + RLP)
* **No indexed parameters**: The event MUST NOT have any indexed parameters beyond the single topic

**One Transaction Per Ethereum Transaction Rule:**

* **Single Facet transaction**: Each Ethereum transaction can contain at most ONE valid Facet transaction
* **Multiple candidates**: If an Ethereum transaction contains multiple events with the Facet signature, only the first valid Facet transaction is processed
* **Processing order**: Calldata is checked before events. Within events, they are processed in log index order
* **Failure semantics**: Subsequent Facet transaction candidates in the same Ethereum transaction are silently ignored, not treated as errors

#### Implementation Example (Solidity)

```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    | The [aliased address](https://docs.facet.org/reference/chain-state-derivation#address-aliasing) of the 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.facet.org/immutable-sequencing/transaction-spec.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
