> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/getting-started/architecture.md).

# Architecture

How Rome's components fit together — EVM execution inside a Solana program.

Rome embeds an EVM bytecode interpreter inside a Solana on-chain program. In the EVM-key lane, users send signed EVM transactions to the Rome Proxy over standard Ethereum JSON-RPC. The proxy submits them to the Rome EVM program on Solana. One EVM transaction can require several Solana transactions to write chunks into holder accounts or run iterative execution. In the v1 Solana-key lane, the proxy composes the transaction. The Solana wallet signs it and sends it directly to Solana RPC. There is no separate execution layer to keep in sync — EVM state *is* Solana state.

## System overview

<figure><img src="https://2654533989-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F671PKS8ZQSNqtoC8PGvz%2Fuploads%2Fgit-blob-4d7d386c95b500079204f3dea2103d9759c5de8f%2Farchitecture.svg?alt=media" alt="EVM wallet and Solana wallet connected to Rome Proxy with its emulator. The Solana cluster holds the Rome EVM program, per-chain state, external-authority PDA, token accounts, Solana programs and holder accounts. Hercules feeds blocks, receipts and logs back to the proxy."><figcaption></figcaption></figure>

## Components

### Rome EVM Program (on-chain)

The core of Rome — a Solana BPF program containing a full EVM bytecode interpreter (a fork of SputnikVM). It:

* Receives signed EVM transactions and unsigned EIP-1559 bodies as Solana instructions. A Solana key authorizes an unsigned body through the Solana fee payer's signature or an Ed25519 verifier instruction
* Executes Solidity bytecode inside the Solana runtime
* Maps each Ethereum address (H160) to a balance PDA per chain containing its nonce, native balance and code. Separate storage PDAs are associated with the balance PDA. Each address also has a program-derived address for authority over Solana calls, called its **external-authority PDA**. This PDA is shared by every chain on the program. It owns the address's SPL token accounts and signs its cross-program invocations (CPIs)
* Exposes precompiles for calling into Solana (CPI, System, Helper, Withdraw) alongside Ethereum precompiles. The cached family adds SystemCached (`0xff…04`), SplCached (`0xff…05`), ASplCached (`0xff…06`) and WithdrawCached (`0xff…0b`). The factory deploys wrappers on this cached track
* Stores EVM state (balances, nonce, code, storage) as Solana account data
* One Rome EVM program hosts many chain IDs. The chain ID is part of the balance and storage PDA addresses, not of the external-authority PDA

### Rome Proxy (JSON-RPC server)

The Rome Proxy is a standard Ethereum JSON-RPC server. Users connect to `https://hadrian.testnet.romeprotocol.xyz/` for Hadrian (testnet) and `https://rubicon.mainnet.romeprotocol.xyz/` for Rubicon (mainnet). It translates Ethereum API calls into Solana activity:

* `eth_sendRawTransaction` → submit one or more Solana v1 transactions: atomic `DoTx`, holder chunks (`TransmitTx`) plus `DoTxHolder`, or iterative legs. A pooled payer signs and pays SOL. A pooled fee recipient collects the user's gas
* `eth_call` → run the EVM interpreter natively in the emulator on live Solana accounts read over RPC. Mollusk runs the Solana programs reached by CPI. It also runs the Rome EVM program when the proxy measures compute units
* `eth_estimateGas` → simulate for gas estimation. A gas unit is one lamport of Solana cost. The estimate is never below 21,000
* `eth_getBalance`, `eth_getCode`, `eth_getTransactionCount`, `eth_getStorageAt` → read live Solana accounts through the emulator. `eth_getBlockByNumber`, receipts and logs come from Hercules

It also exposes Rome extensions: `rome_emulateTx`, `rome_emulateRegRollup`, `rome_mintId`, `rome_buildInfo` and `rome_getResources`. Solana-wallet methods include `rome_emulateCallAccounts`, `rome_composeUnsignedAtomicV1`, `rome_composeUnsignedIterativeV1`, `rome_submitSignedV1Plan`, `rome_relayUnsignedV1`, `rome_composeExternalDepositV1` and `rome_sendUnsignedTransaction`. The proxy also exposes `rome_solanaTxForEvmTx`.

### Hercules (indexer)

Hercules watches the Rome EVM program on Solana and reconstructs Ethereum-compatible blocks in PostgreSQL. These contain transactions, receipts, logs and state changes. On the public chains it runs in slot-aligned mode, so a block number maps to a Solana slot and the same slot yields the same block on any indexer. The proxy serves these blocks to wallets and explorers.

Hercules indexes confirmed blocks. It re-checks each block at finalized and reloads it if the blockhash changed. The [Via explorer](/apps-on-rome/via.md) reads the Hercules data.

### Precompiles

Rome implements ecrecover, SHA-256, RIPEMD-160, identity, the BN254 curve operations and blake2f with Ethereum semantics, except for failure data from BN254 and blake2f. A failed BN254 or blake2f call returns Rome's `Error(string)` revert data instead of an empty buffer. Modexp (`0x05`) is disabled and reverts with `"big_mod_exp call is disabled"`. blake2f refuses more than 1,000,000 rounds, which Ethereum allows.

Non-EVM precompiles reach into Solana: **CpiProgram** (`0xFF…08`, arbitrary CPI), **System** (`0xFF…07`, PDA derivation and base58 helpers), **HelperProgram** (`0xFF…09`, ATA/PDA creation, SPL transfers, gas↔lamports), and **Withdraw** (`0x42…16`). The cached family is **SystemCached** (`0xff…04`), **SplCached** (`0xff…05`), **ASplCached** (`0xff…06`) and **WithdrawCached** (`0xff…0b`). Legacy CPIs run immediately and only in atomic transactions. Cached CPIs are recorded during execution and sent at commit. They revert with the EVM. They can run in iterative transactions. See the [Contract Addresses](/reference/contract-addresses.md) reference for the full table.

## Execution modes

Rome executes an EVM transaction in one of two ways:

### Atomic (VmAt)

A single Solana transaction. The whole EVM transaction executes within one Solana transaction's compute budget (\~1.4M compute units). Used for most operations — transfers, ordinary contract calls, swaps.

### Iterative (VmIt)

For work that exceeds a single transaction's budget. Execution is split across multiple Solana transactions:

1. Each step (a Solana transaction) runs as many EVM opcodes as fit in its compute budget — the step size is adaptive, not fixed
2. VM state is Borsh-serialized into a `StateHolder` account between steps
3. Accounts are TTL-locked for a few seconds during execution

The proxy falls back to iterative execution when compute units, heap or instruction count do not fit in one Solana transaction. A session is capped at 160 iterations. A legacy-track CPI is refused in an iterative transaction, because it cannot be split across legs. Cached-track CPIs are allowed.

## Account mapping

Every Ethereum address maps deterministically to a Solana balance PDA derived from the chain ID and the address under the Rome EVM program. Its native gas balance is a field in that PDA, alongside the nonce and contract code. Storage slots live in separate storage PDAs. SPL balances live in token accounts owned by the separate external-authority PDA. That authority is shared across every chain on the same program.

## Two ways in

* **EVM key lane:** a wallet sends a secp256k1-signed EVM transaction to the Rome Proxy. The proxy submits the Solana transactions.
* **Solana key lane:** a wallet authorizes an unsigned EIP-1559 body with its Solana key. For the direct v1 route, the proxy composes the Solana transaction. The wallet signs it and submits it directly to Solana RPC. The relay route uses the proxy to submit instead. The older legacy route has the wallet build, sign and pay for a `DoTxUnsigned` Solana transaction, and the program derives the sender from the Solana signer.

A Solana public key maps to the synthetic address `keccak256(pubkey)[12:]`, the last 20 bytes of the hash. See [How Solana and the EVM meet on Rome](/core-concepts/how-solana-and-evm-meet.md).

## Who signs a call into Solana

The Rome EVM program signs a CPI with the external-authority PDA of the immediate caller of the precompile. A contract signs as itself. To spend a user's SPL tokens, the contract needs an SPL delegation from that user. The user grants it with `HelperProgram.approve_spl(spender, amount, mint)`. A direct call from the user's EVM or synthetic address to the precompile uses the user's external-authority PDA.

## Holder accounts

Solana (v1) transactions are capped at 4 KB, but EVM transactions (especially contract deployments) can be much larger. Rome splits large transactions into 3,600-byte chunks and writes them sequentially into **holder accounts** (up to 80 KB). It then assembles each transaction and executes it on-chain. The Rome SDK manages this transparently. Each chunk's signature fee is billed to the sender's gas.

## Gas and pricing

Each chain has its own gas token: SOL or an SPL token. The price source is Hermes API, a Meteora DAMM v1 pool, a Meteora DAMM v2 pool or a fixed price. It provides the conversion between the gas token and SOL for the underlying Solana transaction fees.

* A gas unit is one lamport of Solana cost
* `eth_gasPrice` is gas-token wei per lamport
* The sender pays the fee recipient from its native gas balance. The proxy payer pays SOL
* With no fee recipient, as in the Solana-wallet atomic lane, no EVM gas is charged. The wallet pays SOL directly
* The native balance has 18 decimals. It is backed by gas-token SPL held in a per-chain program wallet

## Finality

Rome uses Solana's finality. The SDK waits for `confirmed`. Hercules re-checks each indexed block at `finalized` and reloads it if the blockhash changed.

## What's next

* [Networks](/networks/networks.md) — connect to Hadrian (testnet) and Rubicon (mainnet)
* [Quickstart](/getting-started/quickstart.md) — deploy your first contract
* [Execution Model](/core-concepts/execution-model.md) — atomic vs iterative execution in depth
* [Token Interop](/core-concepts/token-interop.md)
* [Constraints](/core-concepts/constraints.md)
* [Call Solana from EVM](/developer-guides/call-solana-from-evm.md)
* [Call EVM from Solana](/developer-guides/call-evm-from-solana.md)
* [Precompile reference](/reference/precompiles.md)
* [How Solana and the EVM meet on Rome](/core-concepts/how-solana-and-evm-meet.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/getting-started/architecture.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
