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

# Panggil EVM dari Solana

Biarkan dompet Solana mengendalikan kontrak EVM di Rome — tanpa kunci Ethereum. Dompet menandatangani, dan transaksinya masuk ke Solana.

Kebalikan dari [Call Solana from EVM](/id/panduan-pengembang/call-solana-from-evm.md): dompet Solana (misalnya Solflare) memanggil kontrak EVM apa pun di Rome secara langsung, dengan **tanpa kunci Ethereum**. Inilah cara [Aerarium](/id/aplikasi-di-rome/apps.md) memungkinkan pengguna asli Solana berbagi kontrak yang sama seperti pengguna EVM.

Cara satu panggilan adalah `submitRomeTxV1`, yang membuat proxy menyusun satu transaksi Solana v1 untuk panggilan tersebut; halaman ini menjelaskan mekanismenya.

## Alamat sintetis

Identitas EVM dompet Solana adalah **alamat sintetis** — 20 byte terakhir dari `keccak256` dari public key Solana 32 byte miliknya:

```
synthetic_evm_address = keccak256(solana_pubkey)[12:]
```

Ini adalah `msg.sender` saat dompet memanggil kontrak, dan identitas stabil tempat nonce dan penyimpanannya berada. Derivasi ini dipatok dalam protokol, sehingga dompet selalu dipetakan ke alamat yang sama.

```javascript
import { syntheticAddress } from "@rome-protocol/sdk";
const from = syntheticAddress(solanaPubkey); // 0x… 20 bytes
```

## Synthetic adalah pass-through — ia tidak menyimpan token saat idle

Saldo yang dapat dibelanjakan milik pengguna asli Solana berada di **wallet Solana** (sebagai token SPL), ditampilkan 1:1 di sisi EVM sebagai **ERC20SPL wrapper** (mis. `wUSDC`). Synthetic tidak menyimpan apa pun saat idle, jadi nilai mengalir *melalui* melaluinya — setiap langkah ditandatangani oleh dompet Solana:

1. **Provision (sekali).** PDA otorisasi eksternal dari synthetic yang baru dibuat tidak ada sampai `create_pda` dijalankan — dan transfer di bawah ini ditandatangani oleh PDA itu. `submitRomeTxSolanaLane` menyediakannya secara otomatis saat pertama kali digunakan (atau panggil `provisionSynthetic` untuk langkah "Activate" yang eksplisit; periksa dengan `isSyntheticProvisioned`). Dengan `submitRomeTxV1`, periksa `isSyntheticProvisioned` dan kirim `buildCreatePdaCall` melaluinya sekali.
2. **Tahap pendanaan (dompet → synthetic).** Pindahkan token dari ATA dompet ke milik synthetic — `ActivateAta` langkah, dibangun oleh `buildFundLeg`. Sekarang `wrapper.balanceOf(synthetic)` membaca saldo itu, sehingga synthetic membelanjakannya sebagai ERC-20 biasa (`transfer` / `transferFrom`) — **bukan** sebagai native `msg.value`, yang tidak dimilikinya.
3. **Panggilan (`DoTxUnsigned`).** Synthetic menjalankan transaksi EVM — misalnya `approve` lalu vault `deposit` yang menarik melalui `transferFrom`.
4. **Tahap sweep (synthetic → dompet).** Setelah withdraw / borrow / claim menempatkan token di synthetic, `buildSweepLeg` mendorongnya kembali ke ATA dompet milik pengguna sendiri (`HelperProgram.transfer_spl`), sehingga synthetic berakhir nol bersih.

Bagian berikut menjelaskan apa yang versi lama `submitRomeTxSolanaLane` dibangun di sisi klien. `submitRomeTxV1` membuat proxy menyusun transaksi v1 sebagai gantinya, tanpa discovery akun, ComputeBudget, atau treasure wallet di kode Anda; lihat [endpoint external-V1](#the-external-v1-endpoints) di bawah.

## Bagaimana panggilan dibangun

`submitRomeTxSolanaLane` melakukan semua ini. Mekanismenya:

1. **Bangun transaksi EIP-1559 tanpa tanda tangan** dengan `dari` = alamat synthetic — tanpa tanda tangan secp256k1.
2. **Temukan akun** — panggil [`rome_emulateCallAccounts`](/id/referensi/json-rpc.md) dengan `dari`, `ke`, `data`, **dan `nilai`** (jika panggilan bersifat payable). Menyertakan `nilai` penting: proxy meniru *nyata* panggilan, sehingga setiap penulisan penyimpanan yang bergantung pada nilai — misalnya slot mapping baru — dialokasikan dan akun Solananya dikembalikan. Jika diabaikan, akun itu tidak ada, dan transaksi gagal dengan *"instruction modified data of a read-only account."*
3. **Susun transaksi Solana:** dua **ComputeBudget** instruksi (EVM Rome memerlukan batas CU yang dinaikkan ≈1,35 juta dan heap frame besar ≈250 KB — default Solana akan gagal) + **`DoTxUnsigned`** instruksi (RLP tanpa tanda tangan + akun yang ditemukan) + **treasure wallet** (eksekusi membayarnya sedikit biaya; discovery menghilangkannya, jadi SDK menambahkannya).
4. **Dompet menandatangani dan mengirim.** Panduan **Dompet Solana menandatangani transaksi Solana (Ed25519) dan mengirimkannya ke RPC Solana — bukan ke proxy.** Runtime Solana memverifikasi tanda tangan; di chain, program menurunkan `msg.sender` dari penandatangan itu. Otoritasnya adalah tanda tangan Solana, bukan Ethereum. (Proxy hanya digunakan untuk emulasi/discovery pada langkah 2.)

PDA milik pengguna (`["EXTERNAL_AUTHORITY", synthetic_address]`) memiliki akun token mereka dan menandatangani CPI SPL atas nama mereka — jadi pengguna Solana dapat melakukan supply, borrow, swap, dan LP sepenuhnya dari dompet Solana mereka.

## endpoint external-V1

`submitRomeTxV1` adalah cara satu panggilan: ia meminta proxy untuk transaksi v1 yang sudah disusun, memeriksanya, meminta dompet menandatanganinya, dan mengirimkannya ke RPC Solana, sambil merelay melalui proxy ketika panggilan tidak muat. Proxy mengekspos jalur yang sama seperti method RPC, sehingga klien mana pun dapat menggunakannya tanpa SDK (daftar lengkap di [Dukungan JSON-RPC](/id/referensi/json-rpc.md)):

* `rome_composeUnsignedAtomicV1(rlp, pubkey, signature)` — satu transaksi Solana v1; dompet menandatanganinya dan aplikasi menyiarkannya ke RPC Solana. Ditolak jika panggilan tidak muat dalam satu transaksi atomik.
* `rome_composeUnsignedIterativeV1(rlp, pubkey, signature)` — setiap tahap eksekusi (atomik jika muat, jika tidak maka tahap iteratif); dompet menandatangani masing-masing, `rome_submitSignedV1Plan` menyiarkannya. Batas pada rencana panjang ada di [Panggilan yang direlai dan panggilan panjang](#relayed-calls-and-long-calls).
* `rome_relayUnsignedV1(rlp, pubkey, signature)` — satu tanda tangan dompet, payer milik proxy menjalankan setiap tahap dan mengembalikan hash tx EVM; synthetic membayar gas Rome, jadi isi sekali dengan `rome_composeExternalDepositV1`.

**Tanda tangan otorisasi.** `rlp` adalah isi EIP-1559 tanpa tanda tangan dengan 9 field. Dompet menandatangani, dengan kunci Ed25519-nya, baik 32 byte mentah `keccak256(0x02 ‖ rlp)` atau pesan yang mudah dibaca

```
Otorisasi Rome\n0x<64 karakter hex huruf kecil dari hash itu>
```

Keduanya diterima; bentuk yang mudah dibaca adalah yang ditampilkan dompet dengan jelas dalam `signMessage` prompt-nya. Program menghitung ulang hash dari body yang dijalankannya dan mengharuskan pesan yang ditandatangani persis salah satu dari dua bentuk tersebut, sehingga tanda tangan atas satu body tidak pernah dapat mengotorisasi body lain, dan nonce body mencegah replay.

## Panggilan yang direlai dan panggilan panjang

Beberapa panggilan tidak muat dalam satu transaksi Solana. Bagian ini menjelaskan apa yang terjadi setelah itu, dan batas apa yang berlaku.

### Saat penyusun atomik menolak

`rome_composeUnsignedAtomicV1` menolak panggilan yang tidak muat dalam satu transaksi atomik. `submitRomeTxV1` lalu merelay panggilan melalui proxy dengan **yang sama** tanda tangan otorisasi, sehingga dompet tidak diminta lagi. Hasilnya memiliki `route: "relay"` dan tanpa `tanda tangan`. Berikan `relayOnRefusal: false` untuk menjadikan penolakan sebagai error, atau panggil `relayV1` sendiri jika ingin merelay secara sengaja.

Tiga hal yang perlu diketahui tentang panggilan yang direlay:

* **Synthetic membayar gas.** Pada jalur relay, proxy mengirim dan membayar transaksi Solana, dan panggilan dibayar dalam token gas native chain dari saldo synthetic. Saldo harus setidaknya `gasLimit × maxFeePerGas`. `fundSyntheticGas(deps, amountWei)` mengisinya dari akun token milik dompet sendiri untuk token gas chain (USDC di Hadrian dan Rubicon); dompet menandatangani satu transaksi v1 biasa, dan membutuhkan sedikit SOL untuk biaya Solana. `amountWei` berada dalam wei 18 desimal chain dan harus kelipatan 10^12, kalau tidak proxy menolaknya. Tanpa SDK, `rome_composeExternalDepositV1` membangun transaksi yang sama.
* **Revert tidak melempar error.** Panggilan yang direlay dan revert di sisi EVM tetap terselesaikan normal, dengan `receipt.status === "0x0"`. Periksa `receipt?.status === "0x1"` sebelum menganggap panggilan selesai. `receipt` adalah `null` jika receipt tidak muncul tepat waktu.
* **`relayOnRefusal: false` adalah pilihan yang dibuat di SDK, bukan kunci.** Proxy sudah memegang tanda tangan otorisasi untuk payload tersebut dan dapat menjalankannya melalui jalur mana pun, hingga `gasLimit × maxFeePerGas`.

```javascript
const res = await submitRomeTxV1(deps, { to, data, value });
if (res.route === "relay" && res.receipt?.status !== "0x1") {
  // panggilan yang direlay dan revert tetap terselesaikan; tidak melempar error
}
```

### Panggilan panjang

Panggilan yang memerlukan lebih dari satu transaksi berjalan sebagai sesi iteratif: program menjalankan sebanyak mungkin langkah EVM yang muat di setiap transaksi Solana dan menyimpan statusnya di antaranya. Dua cara untuk menjalankannya dari dompet Solana:

* **Relay-kan.** `rome_relayUnsignedV1` membutuhkan satu tanda tangan dompet dan payer milik proxy mengirim setiap tahap. Synthetic membayar gas, seperti di atas.
* **Tandatangani sendiri setiap tahap.** `rome_composeUnsignedIterativeV1` mengembalikan setiap tahap dengan slot tanda tangan kosong, dompet menandatangani masing-masing, dan `rome_submitSignedV1Plan` menyiarkannya berurutan. Setiap tahap adalah transaksi Solana terpisah untuk ditandatangani dompet, jadi dompet yang menandatangani satu transaksi setiap kali akan meminta konfirmasi sekali per tahap, di atas tanda tangan otorisasi. Dompet membayar biaya Solana pada setiap tahap.

Batasnya:

| Batas                                                    | Nilai           | Asalnya dari                                                                                                             |
| -------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Transaksi dalam satu `rome_submitSignedV1Plan` panggilan | 64              | Proxy menolak rencana yang lebih panjang                                                                                 |
| Tahap yang akan direncanakan oleh penyusun iteratif      | 128             | Batas dalam penyusun iteratif Rust Rome SDK, yang juga membatasi rencana `rome_composeUnsignedIterativeV1` mengembalikan |
| Iterasi dalam satu sesi                                  | 160             | Program Rome EVM; setelah melewati itu sesi berhenti dilanjutkan, melepaskan kunci akunnya, dan berakhir                 |
| Ukuran transaksi dan akun Solana                         | 4 KB, 64 alamat | Setiap tahap adalah transaksi Solana v1                                                                                  |

Kebanyakan panggilan nyata selesai dalam tahap jauh lebih sedikit daripada batas ini. Batas 64 transaksi pada rencana yang ditandatangani dompet adalah yang pertama akan Anda temui. Panggilan yang membutuhkan lebih banyak tahap daripada itu tidak dapat disiarkan melalui `rome_submitSignedV1Plan`.

Panggilan panjang tidak dapat membuat CPI legacy-track. Panggilan yang memutasi pada precompile legacy (`0xff…08`, `0xff…09` dan `0x42…16`) ditolak dalam sesi iteratif dengan `CpiProhibitedInIterativeTx`. Pembacaan state Solana dan precompile cached-track (`0xff…04`, `0xff…05`, `0xff…06`, `0xff…0b`) berfungsi. Panggilan yang membuat CPI legacy-track harus muat dalam satu transaksi atomik, apa pun jalur pengirimannya. Lihat [Kendala](/id/konsep-inti/constraints.md) dan [Anggaran Komputasi](/id/konsep-inti/compute-budget.md).

## Implementasi referensi

* **Aerarium** — menggerakkan Compound v3 (supply / borrow) dari dompet Solana melalui `DoTxUnsigned`. Ini adalah referensi untuk jalur transaksi legacy yang dijelaskan di atas, bukan untuk `submitRomeTxV1`.
* **Rome DEX** bukan contoh dari halaman ini: sisi Solananya adalah program Solana native yang ditandatangani langsung oleh dompet, dan sisi EVM-nya berbagi pool yang sama.

Aerarium tidak memerlukan bridge atau dompet kedua — alamat synthetic menjadikan satu kunci Solana sebagai akun EVM kelas utama. Untuk pola v1, ikuti [Build a dual-lane app](/id/panduan-pengembang/dual-lane-app.md).

## Apa Selanjutnya

* [Call Solana from EVM](/id/panduan-pengembang/call-solana-from-evm.md) — arah sebaliknya, melalui CPI
* [Interop Token](/id/konsep-inti/token-interop.md) — bagaimana saldo dibagikan di antara EVM dan Solana


---

# 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/id/panduan-pengembang/call-evm-from-solana.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.
