> 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/call-solana-from-evm.md).

# Call Solana from EVM

Rome's precompiles let Solidity contracts call Solana programs directly. This guide covers the mechanics.

## Prerequisites

* The Rome Solidity interfaces from the public [`rome-solidity`](https://github.com/rome-protocol/rome-solidity) repo (npm publish pending) — precompile interfaces live in [`contracts/interface.sol`](https://github.com/rome-protocol/rome-solidity/blob/master/contracts/interface.sol)
* A deployed Rome contract (see [Deploy Solidity](/developer-guides/deploy-solidity.md))

Bind each interface to its precompile address:

```solidity
import {ICrossProgramInvocation, ISystemProgram, IHelperProgram}
    from "@rome-protocol/rome-solidity/contracts/interface.sol";

ICrossProgramInvocation constant CpiProgram    = ICrossProgramInvocation(0xFF00000000000000000000000000000000000008);
ISystemProgram          constant SystemProgram = ISystemProgram(0xFF00000000000000000000000000000000000007);
IHelperProgram          constant Helper        = IHelperProgram(0xFF00000000000000000000000000000000000009);
```

## The CpiProgram precompile

`CpiProgram` (`0xFF…08`) dispatches CPI (`invoke` / `invoke_signed`) plus cross-state read shortcuts (`account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive`):

```solidity
// Call a Solana program
CpiProgram.invoke(programId, accounts, instructionData);

// Call with PDA signing (your contract signs as a PDA)
CpiProgram.invoke_signed(programId, accounts, data, seeds);
```

## Transfer lamports

For simple SOL/lamports and SPL transfers from the caller's PDA, use the HelperProgram precompile — no hand-built CPI needed:

```solidity
contract Transfers {
    IHelperProgram constant Helper = IHelperProgram(0xFF00000000000000000000000000000000000009);

    // Transfer lamports to an EVM address's PDA
    function transferSol(address to, uint64 lamports) external {
        Helper.transfer_lamports(to, lamports);
    }

    // Transfer an SPL token from the caller's PDA
    function transferSpl(address to, uint64 tokens, bytes32 mint) external {
        Helper.transfer_spl(to, tokens, mint);
    }

    // Create the caller's ATA for a mint
    function createAta(bytes32 mint) external {
        Helper.create_ata(msg.sender, mint);
    }
}
```

`transfer_spl` has several overloads (including a delegate variant for `transferFrom` flows); see `interface.sol`. On the cached track, use `ISplCached` (`0xff…05`) / `IAssociatedSplCached` (`0xff…06`) instead — a contract uses one track consistently.

## Reading account data

Read any Solana account's data via the CpiProgram read shortcuts:

```solidity
(
    uint64 lamports,
    bytes32 owner,
    bool isSigner,
    bool isWritable,
    bool executable,
    bytes memory data
) = CpiProgram.account_info(accountPubkey);
```

## PDA derivation

Find Program Derived Addresses from Solidity via the System precompile:

```solidity
ISystemProgram.Seed[] memory seeds = new ISystemProgram.Seed[](2);
seeds[0] = ISystemProgram.Seed("my-program-seed");
seeds[1] = ISystemProgram.Seed(abi.encodePacked(someValue));

(bytes32 pda, uint8 bump) = SystemProgram.find_program_address(targetProgramId, seeds);
```

## Base58 conversion

Convert between `bytes32` and base58 (Solana's address format):

```solidity
bytes memory base58Str = SystemProgram.bytes32_to_base58(pubkey);
bytes32 pubkey = SystemProgram.base58_to_bytes32(base58Bytes);
```

## Calling custom Solana programs

To call any Solana program, build the account list and instruction data yourself:

```solidity
contract CustomCPI {
    ICrossProgramInvocation constant CpiProgram = ICrossProgramInvocation(0xFF00000000000000000000000000000000000008);
    bytes32 constant MY_PROGRAM = 0x0000000000000000000000000000000000000000000000000000000000000000; // your Solana program ID

    function callMyProgram(bytes32 account1, bytes32 account2, bytes calldata ixData) external {
        ICrossProgramInvocation.AccountMeta[] memory accounts = new ICrossProgramInvocation.AccountMeta[](2);
        accounts[0] = ICrossProgramInvocation.AccountMeta(account1, false, true);
        accounts[1] = ICrossProgramInvocation.AccountMeta(account2, false, false);

        CpiProgram.invoke(MY_PROGRAM, accounts, ixData);
    }
}
```

## Key Constraints

1. **All accounts must be declared upfront.** The Solana transaction must include every account the CPI will touch — dynamic account discovery inside CPI is not possible.
2. **CPI depth limit: 4 levels.** Rome EVM → your target → the target's call → one more. Plan your call depth.
3. **Solana pubkeys are `bytes32`,** not 20-byte Ethereum addresses.
4. **Instruction data is raw bytes** in the format the target program expects (typically Borsh, little-endian).

## What's Next

* **See it in a real app** — [rome-dex](https://github.com/rome-protocol/rome-dex) (dual-lane AMM), [cardo](https://github.com/rome-protocol/cardo) (CPI routes to Meteora / Marinade / Mango / Jupiter), and [aerarium](https://github.com/rome-protocol/aerarium) call Solana from Solidity in production.
* [Call EVM from Solana](/developer-guides/call-evm-from-solana.md) — the reverse: drive EVM contracts from a Solana wallet
* [Token Interop](/core-concepts/token-interop.md) — how ERC-20 and SPL tokens work together
* [Constraints](/core-concepts/constraints.md) — CPI depth and other limits


---

# 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 dynamically by asking a question.

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

```
GET https://docs.rome.builders/developer-guides/call-solana-from-evm.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
