> 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/developer-guides/from-home.md).

# From home: reach Rome from another chain

Let users on another chain reach your Rome app without leaving home — bring assets in, act, take them back out.

Your users don't have to move to Rome. From their home chain — an L2 like Arbitrum or Monad, or Solana — they bring assets in, use your Rome app, and take assets back out. The bridge is on-chain and authorized by the user's own signature; you wire your app to it through one API.

## How it works

* **Inbound (home → Rome):** on the gas-token USDC route over CCTP, the `settle_inbound_bridge_v2` instruction of the Rome program credits the user, under a signed **EIP-712** `SettleAuthorization`, so there is no privileged settler. The other inbound routes do not use that instruction or signature. Wrapper USDC, ETH over Wormhole and SOL land directly as the wrapper token in the user's account. Solana USDC on a chain whose gas token is USDC needs one more transaction, signed by the user, to turn the wrapper into gas. The quote tells you which signatures a route needs.
* **Outbound (Rome → home):** `RomeBridgeWithdraw` (in [`rome-solidity`](https://github.com/rome-protocol/rome-solidity)) burns the asset on Rome. The user then claims it on the home chain with their own transaction.
* **Transport:** Circle **CCTP** for USDC and the **Wormhole** token bridge for ETH. Solana home chains use plain SPL transfers in and a Rome withdraw out. Wormhole is the inbound rail for ETH only. A generic Wormhole route exists for outbound only, and each asset on it has to be enabled by the Rome operators first.
* **Orchestration:** the off-chain [`rome-bridge-api`](https://github.com/rome-protocol/rome-bridge-api) quotes a route, verifies the source-chain transaction, and sponsors the settle fee. It holds no funds and no keys. It can only trigger what the user already signed.

## Build it

The API is public on devnet at `https://bridge-api.devnet.romeprotocol.xyz`. `GET /v1/routes` lists every live route (asset, rail, direction, source chain, Rome chain, speeds). The calls below are the same four the SDK wraps in `@rome-protocol/sdk/bridge` (`requestQuote`, `registerTransfer`, `getTransfer`, `reportStep`). The CLI runs the whole flow for you: `rome fund` and `rome bridge` for the transfers and `rome verify --path from-home` for a round trip, as described on the [Rome CLI](/products/rome-cli.md) page.

### Bring assets in

1. **Quote the route.** Send the user's source chain, asset, amount and addresses. Chains go in as CAIP-2 ids such as `eip155:84532`; `romeChainId` is your Rome chain. The older names `ethereum` and `solana` are still accepted but deprecated, and the API marks those responses with a `Sunset` header. The full request and response shapes are in the [API reference](https://github.com/rome-protocol/rome-bridge-api/blob/main/docs/API.md).

   ```bash
   curl -X POST https://bridge-api.devnet.romeprotocol.xyz/v1/quote \
     -H 'Content-Type: application/json' \
     -d '{
       "asset": "USDC",
       "direction": "to-rome",
       "sourceChain": "eip155:84532",
       "romeChainId": "200010",
       "amount": "1000000",
       "sender": { "ethereum": "0xUSER" },
       "recipient": "0xUSER"
     }'
   ```

   Amounts are base-unit integers in strings (`"1000000"` is 1 USDC). ETH amounts are in wei and, on the way out, must be a multiple of 10,000,000,000 wei (the wrapper has 8 decimals); the API rejects anything finer. The response lists the `steps`. The user signs the transactions of every step marked `userSigns: true`, in step order: EVM transactions are in `unsignedTxs`, Solana instructions in `unsignedTx`. Sign them exactly as returned. Steps with nothing to sign are done by the sponsor once Circle or Wormhole has attested the transfer. The outbound claim is the exception, described below: the user builds it.
2. **Have the user sign.** For a CCTP quote that is the USDC approval and the burn on the source chain. If the quote has an entry in `signatureRequests`, the user also signs that EIP-712 `SettleAuthorization` once the burn hash is known; fill in the burn hash and pass the result as `userSettleSig` in the next call. Only the gas-token CCTP route has one. Wormhole ETH, wrapper-intent USDC and Solana routes have none.
3. **Register the transfer.** `POST /v1/transfers` with the full quote and `step1TxHash`, the hash of the last transaction in the first step (the burn). The API checks that the transaction on the source chain matches the quote and returns a transfer `id`.
4. **Poll** `GET /v1/transfers/{id}` every few seconds until `outcome` is `complete`. The user is then funded on Rome and can use your app.

Solana home chains follow the same shape with different steps. The user sends an SPL transfer to their Rome account's token account. SOL arrives as wrapped SOL after that one transfer. On a chain whose gas token is USDC, such as Hadrian, USDC needs a second step: a Rome transaction the user signs that turns the landed wrapper into native gas. Any other SPL token goes through the `spl-solana-to-rome` route, which takes the mint in `splAsset`.

### Take assets back out

Bridging out is not the inbound flow run backwards. It has more than one signature, and the user finishes it on the home chain. Quote it with `direction` set to `from-rome`. `sourceChain` names the non-Rome side and `destinationChainId` picks the chain the user claims on. Pass both: `destinationChainId` is what decides the claim chain, and a quote without it defaults to Ethereum Sepolia whatever `sourceChain` says:

```bash
curl -X POST https://bridge-api.devnet.romeprotocol.xyz/v1/quote \
  -H 'Content-Type: application/json' \
  -d '{
    "asset": "USDC",
    "direction": "from-rome",
    "sourceChain": "eip155:84532",
    "destinationChainId": 84532,
    "romeChainId": "200010",
    "amount": "1000000",
    "sender": { "rome": "0xUSER" },
    "recipient": "0xUSER"
  }'
```

For USDC over CCTP the quote returns two steps, and the user signs both:

1. **On Rome, two transactions in order.** The first grants `RomeBridgeWithdraw` delegate rights over the user's wUSDC on Solana (`approve_spl`). The grant covers exactly the amount of this burn, so the quote includes it every time and the user signs it before each burn. The second burns the wUSDC through `RomeBridgeWithdraw`, which starts the CCTP transfer. Register the transfer with the hash of the burn. The burn spends wUSDC, the token the quote names as `burnToken`, not the native gas USDC. Funds that came in as gas are not what gets burned, so for a round trip bring USDC in with `intent: "wrapper"`.
2. **On the destination chain, the claim.** Poll `GET /v1/transfers/{id}` until step 2 is `ready`. It then carries the `message` and `attestation`. The user calls `receiveMessage(message, attestation)` on Circle's message transmitter on the destination chain (the quote names the transmitter and the CCTP domain). Nothing is sponsored here, so the user needs gas on that chain. Report the claim hash with `POST /v1/transfers/{id}/steps/2`.

ETH over Wormhole has the same shape. The user grants the same delegate rights over wETH, burns wETH on Rome, and waits for the Wormhole guardians to sign. The user then redeems on Ethereum with their own transaction: `completeTransferAndUnwrapETH` on the token bridge the quote names (`claimTokenBridge`), using the signed message (`vaa`) from step 2.

Withdrawing to a Solana address has no claim step. USDC is a single Rome transaction that withdraws to the user's Solana account. SOL is one Rome step with three transactions: the same delegate grant over wSOL, an optional creation of the recipient's wSOL token account on Solana (skipped when it already exists), and the withdraw through `RomeBridgeWithdraw`.

**First outbound transfer needs an activated account.** A CCTP burn creates a message account on Solana, and the user's account on Rome has to hold enough lamports to pay for it. A new wallet does not, so the first outbound transfer fails until the user activates once. The check is that the account holds at least 15,000,000 lamports. Read them with `account_lamports(bytes32)` on the CPI precompile at `0xff00000000000000000000000000000000000008`, passing the user's external-auth account on Solana (the CLI does this read for you). Activation calls `activate()` on the `SimpleActivator` contract listed in the [registry](https://github.com/rome-protocol/rome-registry) for your chain, and the call carries a payment in the chain's gas token. On Hadrian that is 2 USDC. The CLI does this with `rome activate <chain>`, and `rome bridge --to` stops and tells you to run it if the account is not ready. The reserve covers one burn, and the rent comes back after Circle attests the burn, which takes about 30 minutes. A second burn before then, or an account that has been drained since it was activated, needs `topUpUserPda(lamports)` on the same contract, because `activate()` reverts once the account has been activated. `rome activate` picks the right call. Inbound transfers need no activation. The quote does not include activation as a step, so your app has to check the account and offer it before the first outbound quote.

## Read the code

* [appia](https://github.com/rome-protocol/appia) — a from-home app: users bring USDC from their home chain and use Rome-side DeFi without leaving it.
* [rome-bridge-api](https://github.com/rome-protocol/rome-bridge-api) — the orchestrator (quote → verify → sponsor).

## What's next

* [Getting funded](/resources/faucets.md) — the same bridge path funds a fresh dev wallet.
* [Deploy Solidity](/developer-guides/deploy-solidity.md) — put your app on Rome.


---

# 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/developer-guides/from-home.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.
