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

# EVM에서 Solana 호출

Rome의 CPI와 헬퍼 프리컴파일을 통해 Solidity에서 Solana 프로그램을 호출하세요.

Rome의 precompile을 사용하면 Solidity 계약이 Solana 프로그램을 직접 호출할 수 있습니다. 이 가이드는 그 메커니즘을 설명합니다.

## 사전 요구 사항

* 공개된 Rome Solidity 인터페이스는 [`rome-solidity`](https://github.com/rome-protocol/rome-solidity) 저장소에서 제공됩니다(GitHub에서 설치하며, npm이 아닙니다 — [Solidity 배포](/ko/developer-guides/deploy-solidity.md#using-the-rome-solidity-sdk)) — precompile 인터페이스는 다음에 있습니다 [`contracts/interface.sol`](https://github.com/rome-protocol/rome-solidity/blob/master/contracts/interface.sol)
* 배포된 Rome 계약(참조 [Solidity 배포](/ko/developer-guides/deploy-solidity.md))

각 인터페이스를 해당 precompile 주소에 연결합니다:

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

## CpiProgram precompile

`CpiProgram` (`0xFF…08`)는 CPI를 처리합니다 (`invoke` / `invoke_signed`)와 cross-state 읽기 단축 기능을 제공합니다 (`account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive`):

```solidity
// Solana 프로그램 호출
CpiProgram.invoke(programId, accounts, instructionData);

// PDA 서명을 사용한 호출: 계약의 external-authority PDA가 서명하고, 추가로 하나
// `salts`의 각 항목마다 salted sub-PDA (Rome은 ["EXTERNAL_AUTHORITY", contract, salt]를 파생합니다)
CpiProgram.invoke_signed(programId, accounts, data, salts);
```

## lamport 전송

간단한 lamport 및 SPL 전송에는 HelperProgram precompile을 사용하세요 — 직접 CPI를 구성할 필요가 없습니다. 이를 호출하는 계약은 **자체적으로**: 아래 전송은 사용자의 것이 아니라 계약 자체의 lamport와 토큰(계약의 external-authority PDA가 서명함)을 이동합니다. 계약이 사용자의 SPL 토큰을 자신이 제어하는 토큰 계정으로 끌어오고 그것이 누구의 것인지 알게 하려면, 사용자가 SPL delegation을 부여합니다. ERC-20 `전송에서는 후크가 작동하지 않습니다` 또는 `transferFrom` 을 계약에 보내면 wrapper의 escrow 장부에만 적립되고, 계약에는 사용할 토큰 계정이 주어지지 않습니다 — 참조 [Solana 프로그램 통합](/ko/developer-guides/integrate-solana-program.md).

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

    // 이 계약의 PDA에서 EVM 주소의 PDA로 lamport 전송
    function transferSol(address to, uint64 lamports) external {
        Helper.transfer_lamports(to, lamports);
    }

    // 이 계약의 PDA가 소유한 토큰 계정에서 SPL 토큰 전송
    function transferSpl(address to, uint64 tokens, bytes32 mint) external {
        Helper.transfer_spl(to, tokens, mint);
    }

    // 민트에 대한 호출자의 ATA를 생성
    function createAta(bytes32 mint) external {
        Helper.create_ata(msg.sender, mint);
    }
}
```

`transfer_spl` 에는 여러 오버로드가 있습니다(포함:  `transferFrom` 흐름을 위한 delegate 변형); 정확한 시그니처는 `interface.sol`. cached track에서는 다음을 사용하세요 `ISplCached` (`0xff…05`) / `IAssociatedSplCached` (`0xff…06`)을 대신 사용하세요 — 계약은 한 가지 track만 일관되게 사용하며, legacy track만 `invoke` 커스텀 프로그램(참조 [Solana 프로그램 통합](/ko/developer-guides/integrate-solana-program.md)).

## 계정 데이터 읽기

CpiProgram의 읽기 단축 기능을 통해 모든 Solana 계정의 데이터를 읽을 수 있습니다:

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

## PDA 파생

System precompile을 통해 Solidity에서 Program Derived Address를 찾습니다:

```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 변환

다음 간 변환 `bytes32` 및 base58(Solana의 주소 형식):

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

## 커스텀 Solana 프로그램 호출

어떤 Solana 프로그램이든 호출하려면 계정 목록과 instruction 데이터를 직접 구성해야 합니다:

```solidity
contract CustomCPI {
    ICrossProgramInvocation constant CpiProgram = ICrossProgramInvocation(0xFF00000000000000000000000000000000000008);
    bytes32 constant MY_PROGRAM = 0x0000000000000000000000000000000000000000000000000000000000000000; // 사용자 Solana 프로그램 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);
    }
}
```

## 주요 제약

1. **모든 계정은 미리 선언되어야 합니다.** Solana 트랜잭션에는 CPI가 접근할 모든 계정이 포함되어야 합니다 — CPI 내부에서 동적으로 계정을 찾는 것은 불가능합니다.
2. **CPI 깊이 제한: 4단계.** Rome EVM → 대상 → 대상의 호출 → 한 단계 더. 호출 깊이를 계획하세요.
3. **Solana pubkey는 `bytes32`,** 20바이트 Ethereum 주소가 아닙니다.
4. **instruction 데이터는 원시 바이트입니다** 대상 프로그램이 기대하는 형식으로(보통 Borsh, little-endian) 제공되어야 합니다.

## 다음 단계

* **실제 앱에서 확인하기** — [cardo](https://github.com/rome-protocol/cardo) 어댑터 계약 없이 사용자의 지갑에서 바로 precompile로 CPI 호출을 보냅니다; [rome-dex](https://github.com/rome-protocol/rome-dex) (dual-lane AMM)도 같은 방식으로 동작하며, custody-less router 계약도 있습니다; [aerarium](https://github.com/rome-protocol/aerarium) 은 Solidity에서 Solana 프로그램을 호출하지 않는 대출 앱입니다.
* [Solana 프로그램 통합](/ko/developer-guides/integrate-solana-program.md) — 사용자의 Solana 신원, 그 신원으로 서명하는 것, one-track 규칙, 그리고 반대편의 실제 프로그램을 위한 계정 프로비저닝
* [프리컴파일 참조](/ko/reference/precompiles.md) — 모든 precompile의 모든 selector
* [Solana에서 EVM 호출](/ko/developer-guides/call-evm-from-solana.md) — 반대 방향: Solana 지갑으로 EVM 계약을 구동하기
* [토큰 상호운용성](/ko/core-concepts/token-interop.md) — ERC-20과 SPL 토큰이 함께 동작하는 방식
* [제약 사항](/ko/core-concepts/constraints.md) — CPI 깊이 및 기타 제한


---

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