> 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/vi/huong-dan-cho-nha-phat-trien/call-solana-from-evm.md).

# Gọi Solana từ EVM

Gọi các chương trình Solana từ Solidity thông qua CPI và các precompile trợ giúp của Rome.

Các precompile của Rome cho phép các hợp đồng Solidity gọi trực tiếp các chương trình Solana. Hướng dẫn này trình bày cơ chế hoạt động.

## Điều kiện tiên quyết

* Các giao diện Solidity của Rome từ kho công khai [`rome-solidity`](https://github.com/rome-protocol/rome-solidity) repo (được cài từ GitHub, không phải npm — xem [Triển khai Solidity](/vi/huong-dan-cho-nha-phat-trien/deploy-solidity.md#using-the-rome-solidity-sdk)) — các giao diện precompile nằm trong [`contracts/interface.sol`](https://github.com/rome-protocol/rome-solidity/blob/master/contracts/interface.sol)
* Một hợp đồng Rome đã triển khai (xem [Triển khai Solidity](/vi/huong-dan-cho-nha-phat-trien/deploy-solidity.md))

Liên kết từng giao diện với địa chỉ precompile của nó:

```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);
```

## Precompile CpiProgram

`CpiProgram` (`0xFF…08`) thực hiện CPI (`invoke` / `invoke_signed`) cùng các lối tắt đọc cross-state (`account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive`):

```solidity
// Gọi một chương trình Solana
CpiProgram.invoke(programId, accounts, instructionData);

// Gọi với ký hiệu PDA: PDA thuộc quyền bên ngoài của hợp đồng bạn ký, cộng thêm một
// PDA con đã gắn salt cho mỗi mục trong `salts` (Rome suy ra ["EXTERNAL_AUTHORITY", contract, salt])
CpiProgram.invoke_signed(programId, accounts, data, salts);
```

## Chuyển lamports

Đối với các lần chuyển lamport và SPL đơn giản, hãy dùng precompile HelperProgram — không cần tự dựng CPI. Một hợp đồng gọi nó sẽ hoạt động như **chính nó**: các lần chuyển bên dưới di chuyển lamport và token của chính hợp đồng (PDA quyền bên ngoài của nó ký), chứ không phải của người dùng. Để một hợp đồng kéo token SPL của người dùng vào một tài khoản token do nó kiểm soát, và biết chúng thuộc về ai, người dùng cấp một ủy quyền SPL. Một ERC-20 `chuyển` hoặc `transferFrom` được chuyển cho một hợp đồng chỉ ghi có vào sổ ký quỹ của wrapper và không cấp cho hợp đồng một tài khoản token nào để chi tiêu từ đó — xem [Tích hợp một chương trình Solana](/vi/huong-dan-cho-nha-phat-trien/integrate-solana-program.md).

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

    // Chuyển lamport từ PDA của hợp đồng này sang PDA của một địa chỉ EVM
    function transferSol(address to, uint64 lamports) external {
        Helper.transfer_lamports(to, lamports);
    }

    // Chuyển một token SPL từ tài khoản token thuộc quyền sở hữu của PDA của hợp đồng này
    function transferSpl(address to, uint64 tokens, bytes32 mint) external {
        Helper.transfer_spl(to, tokens, mint);
    }

    // Tạo ATA của người gọi cho một mint
    function createAta(bytes32 mint) external {
        Helper.create_ata(msg.sender, mint);
    }
}
```

`transfer_spl` có nhiều overload (bao gồm một biến thể delegate cho `transferFrom` các luồng); xem `interface.sol`. Trên track đã lưu cache, hãy dùng `ISplCached` (`0xff…05`) / `IAssociatedSplCached` (`0xff…06`) thay vào đó — một hợp đồng dùng nhất quán một track, và chỉ track cũ mới có thể `invoke` một chương trình tùy chỉnh (xem [Tích hợp một chương trình Solana](/vi/huong-dan-cho-nha-phat-trien/integrate-solana-program.md)).

## Đọc dữ liệu tài khoản

Đọc dữ liệu của bất kỳ tài khoản Solana nào qua các lối tắt đọc của CpiProgram:

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

## Suy ra PDA

Tìm Program Derived Address từ Solidity qua precompile System:

```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);
```

## Chuyển đổi Base58

Chuyển đổi giữa `bytes32` và base58 (định dạng địa chỉ của Solana):

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

## Gọi các chương trình Solana tùy chỉnh

Để gọi bất kỳ chương trình Solana nào, bạn tự xây dựng danh sách tài khoản và dữ liệu lệnh:

```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);
    }
}
```

## Ràng buộc chính

1. **Tất cả tài khoản phải được khai báo từ trước.** Giao dịch Solana phải bao gồm mọi tài khoản mà CPI sẽ chạm tới — không thể khám phá tài khoản động bên trong CPI.
2. **Giới hạn độ sâu CPI: 4 cấp.** Rome EVM → mục tiêu của bạn → lời gọi của mục tiêu → thêm một lớp nữa. Hãy lên kế hoạch cho độ sâu lời gọi.
3. **Pubkey Solana là `bytes32`,** không phải địa chỉ Ethereum 20 byte.
4. **Dữ liệu lệnh là các byte thô** theo định dạng mà chương trình đích mong đợi (thường là Borsh, little-endian).

## Tiếp theo là gì

* **Xem trong một ứng dụng thực tế** — [cardo](https://github.com/rome-protocol/cardo) gửi các lời gọi CPI tới precompile trực tiếp từ ví của người dùng, không cần hợp đồng trung gian; [rome-dex](https://github.com/rome-protocol/rome-dex) (AMM hai làn) cũng làm như vậy và còn có một hợp đồng router không lưu ký; [aerarium](https://github.com/rome-protocol/aerarium) là một ứng dụng cho vay không gọi các chương trình Solana từ Solidity.
* [Tích hợp một chương trình Solana](/vi/huong-dan-cho-nha-phat-trien/integrate-solana-program.md) — danh tính Solana của người dùng, ký thay cho nó, quy tắc một track, và việc cấp tài khoản cho một chương trình thực ở phía bên kia
* [Tài liệu tham chiếu precompile](/vi/tai-lieu-tham-khao/precompiles.md) — mọi selector trên mọi precompile
* [Gọi EVM từ Solana](/vi/huong-dan-cho-nha-phat-trien/call-evm-from-solana.md) — chiều ngược lại: điều khiển các hợp đồng EVM từ một ví Solana
* [Tương tác token](/vi/cac-khai-niem-cot-loi/token-interop.md) — cách ERC-20 và token SPL hoạt động cùng nhau
* [Ràng buộc](/vi/cac-khai-niem-cot-loi/constraints.md) — độ sâu CPI và các giới hạn khác


---

# 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/vi/huong-dan-cho-nha-phat-trien/call-solana-from-evm.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.
