Skip to main content
이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
sdk-api/rust-cpi는 각 Raydium 프로그램을 호출하는 저수준 메커니즘을 다룹니다. 이 페이지는 상위 수준의 동반 자료입니다: Raydium을 자신의 프로그램에 구성하는 이유, 어떤 패턴이 당신의 사용 사례에 맞는지, 그리고 처음부터 끝까지 필요한 전체 접착제입니다.

CPI가 올바른 도구인 경우

커스텀 프로그램은 거래가 오직 당신의 프로그램만 수행할 수 있는 다른 온체인 상태 변경과 원자적으로 발생해야 할 때 의미가 있습니다. 일반적인 경우:
  • 에스크로우 / 지정가 주문 프로그램 — 사용자가 민트를 에스크로우에 예치하고, 당신의 프로그램이 가격 조건을 감시하다가 트리거되면 원자적으로 Raydium을 통해 스왑하고 사용자 계정에 크레딧을 부여합니다.
  • 애그리게이터 프록시 — Raydium과 하나 이상의 다른 DEX를 통해 스왑을 라우팅하는 단일 명령어로, 모든 홉이 당신의 프로그램이 소유한 단일 슬리피지 체크 아래에 있습니다.
  • 자동 복리 금고 — LP 또는 팜 스테이크를 금고에 예치하고, 금고가 일정에 따라 보상을 수확하고, 유동성을 다시 공급하고, 주식 토큰을 발행합니다.
  • 전략 금고 — CLMM을 통해 스왑하여 리밸런싱하는 레버리지 LP 포지션; 포지션을 종료하고 한 거래에서 담보를 스왑하는 청산자.
  • 커스텀 베스팅이 있는 토큰 출시 플랫폼 — 당신의 프로그램이 베스팅 토큰을 보유하고 일정에 따라 Raydium 풀로 릴리스합니다.
오프체인 코드에서 스왑을 보내고 싶을 뿐이라면 CPI는 과도합니다 — SDK를 사용하세요. CPI는 자신의 상태와의 원자성이 요구사항일 때만 복잡성을 정당화합니다.

구성 패턴

패턴 1: 얇은 프록시

당신의 프로그램은 어떤 정책을 검증하는 단일 명령어를 노출합니다 (예: 화이트리스트된 민트 쌍, 검증된 사용자를 위한 수수료 할인) 그리고 나서 Raydium으로 전달합니다.
상태는 사용자의 ATA에 있습니다. 당신의 프로그램은 토큰을 소유하지 않습니다. 최소한의 신뢰 풋프린트입니다.

패턴 2: 에스크로우

당신의 프로그램은 사용자의 입력 민트를 보유하는 PDA를 소유합니다. 트리거 시 PDA는 Raydium에 CPI에 서명하여 자신의 잔액을 스왑합니다.
중요한 세부 사항: PDA는 CpiContext::new_with_signer를 통해 서명합니다. 서명자 시드를 참조하세요.

패턴 3: 구성된 멀티홉

당신의 프로그램은 한 명령어에서 여러 CPI를 발행하여 모든 CPI에 걸쳐 단일 슬리피지 한계를 적용합니다. Raydium 스왑 명령어는 각각 자신의 minimum_amount_out을 가지지만, 당신은 그것들을 0 (또는 매우 느슨한 바닥)으로 설정하고 마지막 홉 후에 엄격한 최종 최소값을 직접 적용합니다.
이것은 전체 경로에 대한 단일 되돌리기 게이트를 제공합니다. 모든 홉이 슬리피지 안전하다고 신뢰할 때만 이 패턴을 사용하세요; 그렇지 않으면 각 홉이 자신의 최소값을 적용하도록 하세요.

패턴 4: 금고 / 전략

당신의 프로그램은 LP 토큰 또는 팜 스테이크를 PDA에 보유합니다. 키퍼 (또는 사용자)가 compound()를 호출하면:
  1. 팜에서 보상을 수확합니다.
  2. 보상을 풀 토큰으로 스왑합니다 (CPMM 또는 CLMM으로 CPI).
  3. 수익금을 LP에 다시 예치합니다 (또 다른 CPI).
  4. 새 LP를 스테이크합니다 (또 다른 CPI).
모두 한 거래에서 금고의 NAV가 원자적으로 이동합니다. 컴퓨트 예산은 일반적으로 600k–1M CU입니다; 주소 조회 테이블은 필수입니다.

계정 목록 구성

호출 프로그램의 Accounts 구조체는 Raydium 프로그램의 계정 순서를 반영하지만, 대부분의 Raydium 측 계정은 Raydium이 자체적으로 검증하기 때문에 UncheckedAccount입니다. 당신은 당신이 소유한 계정에만 제약을 추가합니다:
비대칭성 — 당신의 계정에 대한 엄격한 검증, Raydium의 계정에 대한 UncheckedAccount — 은 게으름이 아닙니다. 수신자는 자신의 것을 검증합니다; 호출자에서 이중 검증하는 것은 CU를 낭비하고 Raydium이 새로운 구조체 레이아웃 필드를 배포할 때 동기화되지 않을 위험이 있습니다.

CPI 호출 자체

PDA 서명자 시드

CPI는 authority로 전달된 PDA가 호출자가 주장하는 파생과 일치할 때만 성공합니다. 둘 다 다음에 동의해야 합니다:
  1. 시드 바이트 시퀀스 (여기서 [b"escrow", user.key().as_ref()]).
  2. 범프.
  3. 호출 프로그램 ID (Raydium이 아닌 당신의 프로그램).
PDA가 무엇과 일치해야 하는지 유의하세요. CPMM의 authority 슬롯은 CPMM 자체의 보관소 PDA입니다 — CPMM이 직접 파생하고 스스로 서명하는 고정된 프로그램 전역 계정이며, 당신의 프로그램이 통제하거나 대체하지 않습니다. 당신의 PDA 시드가 일치해야 하는 계정은 **payer**입니다: 검증은 CPMM 자체의 transfer_from_user_to_pool_vault 헬퍼 내부에서 이루어지며, payer로 전달된 계정이 input_token_account의 소유자여야 합니다. 일반적인 버그: escrow_input_ata가 에스크로우 PDA의 소유인데 user를 payer로 전달하는 것입니다. SPL Token 프로그램은 owner mismatch로 거부합니다. 항상 payer를 ATA의 소유자로 지정하고, 그 소유자가 PDA인 경우 new_with_signer로 서명하세요.

남은 계정

여러 Raydium 명령어는 고정된 계정 뒤에 추가된 가변 길이 계정 목록을 가집니다 — 남은 계정.
  • CLMM SwapV2: 스왑이 스왑 방향으로 순회할 수 있는 틱 배열에 대한 1–8개의 TickArrayState 계정.
  • Farm v6 Deposit / Harvest / Withdraw: (reward_vault, user_reward_ata) 쌍, 활성 보상 슬롯당 한 쌍.
  • Token-2022 전송 훅 민트: 전송 훅 프로그램과 훅이 필요한 모든 계정.
Anchor CPI 헬퍼는 남은 계정을 타입 체크하지 않습니다. 그것들을 통과시키세요:
순서가 중요합니다. CLMM의 경우:
팜 v6 수확의 경우:
당신의 호출 프로그램은 클라이언트로부터 받은 남은 계정을 변경되지 않은 상태로 전달해야 합니다. 필터링하거나 재정렬하려고 하지 마세요.

구성된 호출을 위한 컴퓨트 예산

CPI는 호출 프레임 자체에 약 1,500 CU를 소비합니다. 피호출자 자신의 CU 사용량은 그 위에 쌓입니다. 아래 피호출자 수치는 2026-09-09에 거래량이 많은 풀의 실제 메인넷 트랜잭션에서 측정한 값으로, Raydium 프로그램 자체 호출에 대한 Program <id> consumed N of M compute units 로그 라인에서 읽었습니다(따라서 내부 토큰 프로그램 CPI가 포함됩니다): 각 CPI 프레임에 약 1,500을 더하고 그 위에 당신의 프로그램 오버헤드를 더하세요. CLMM 스왑 비용은 틱 교차 횟수에 따라 증가하므로 그 수치는 하한으로 취급하세요. Token-2022 민트는 전송 자체의 확장 처리 비용을 추가합니다. 일률적인 배수를 적용하지 말고 자신의 민트에 대해 직접 측정하세요.
이 페이지의 이전 개정판에는 5–7배 높은 추정치가 실려 있었습니다(CPMM 스왑 약 150,000 CU, CLMM 약 180,000). 그 수치는 측정된 적이 없습니다. 문서에 적힌 숫자가 아니라 직접 측정한 computeUnitsConsumed 값을 기준으로 예산을 세우세요 — 그리고 ATA 생성, wSOL 래핑, 컴퓨트 예산 명령어까지 계산에 넣으면 전체 트랜잭션 비용은 Raydium 명령어 단독보다 크다는 점에 유의하세요.
항상 명시적 ComputeBudgetProgram::set_compute_unit_limit을 설정하세요:
기본 200k CU 한계는 구성된 호출이 완료되기 훨씬 전에 조용히 소진됩니다.

오류 전파

Raydium의 프로그램은 안정적인 오류 코드를 가진 Anchor 오류를 반환합니다. 당신의 호출 프로그램은 그것들을 Err(ProgramError::Custom(code))로 봅니다. 기본적으로 버블링하세요:
또는 특정 코드를 가로채세요:
ERROR_CODE_OFFSET 항목에 주의하세요: #[error_code] 배리언트는 6000부터 시작하는 번호로 발행되므로, 순수 enum 판별자와 비교하면 절대 일치하지 않습니다. (anchor-lang이나 raydium_cp_swap에는 is_err 헬퍼가 없습니다 — 이 페이지의 이전 리비전은 존재하지 않는 헬퍼를 사용했습니다.) 오류 코드-의미 매핑은 IDL 정책에 따라 안정적입니다 (sdk-api/anchor-idl); 새 코드는 끝에 추가되고, 기존 코드는 절대 의미가 변경되지 않습니다.

완전한 실제 예제: 지정가 주문 에스크로우

흐름:
  1. open_order — 사용자가 input_mint의 amount_in을 에스크로우 PDA에 예치합니다; 목표 min_amount_out과 만료를 기록합니다.
  2. execute_order — 누구든지 (키퍼)가 현재 풀 계정으로 호출합니다. 프로그램은 현재 견적이 min_amount_out 이상인지 확인한 다음 Raydium 스왑을 CPI하고 출력을 에스크로우에 유지합니다.
  3. claim — 사용자가 에스크로우에서 출력 민트를 인출합니다.
키퍼는 거래 수수료를 지불합니다 (그들은 다른 곳에서 키퍼 수수료를 받습니다 — 표시되지 않음). order PDA는 에스크로우의 입력 ATA를 소유하므로 payer로서 CPI에 서명합니다. 따라서 ExecuteOrder에는 CPMM 자체의 보관소 PDA를 위한 pool_authority: UncheckedAccount<'info> 필드도 필요합니다. Raydium 측 슬리피지 체크 와 에스크로우 자체의 델타 체크 모두 바닥을 적용합니다 — 이중 확인입니다.

테스트

로컬 검증자에 Raydium 프로그램을 통합 테스트로 가져오기 (Anchor.toml에서):
풀 상태 계정도 복제하세요. 그래야 테스트가 실제로 스왑을 실행할 수 있습니다; anchor test는 시작 시 메인넷에서 가져옵니다. sdk-api/rust-cpi를 참조하세요.

구성에 특정한 함정

재진입성

Solana는 진정한 재진입성이 없습니다 — CPI는 같은 호출에서 원래 프로그램으로 다시 호출할 수 없습니다. 하지만 당신은 여전히 자신을 논리적 재진입성으로 구성할 수 있습니다: CPI가 당신의 상태를 읽고, 그 다음 당신의 코드가 CPI가 변경하지 않았다고 가정하고 다시 읽습니다. Raydium의 경우 CPI는 당신의 상태를 건드리지 않으므로 이것은 예를 들어 플래시 론 컨텍스트보다 덜 우려됩니다. 하지만 Raydium을 대출 프로토콜과 구성하면 주의하세요.

계정 가변성 드리프트

당신의 프로그램이 계정을 mut로 전달하지만 Raydium이 읽기 전용으로 예상하는 경우(또는 그 반대), 런타임은 InvalidAccountData로 호출을 거부합니다. 항상 Raydium 명령어의 예상 가변성을 IDL에서 확인하세요. raydium_cp_swap::cpi::accounts::Swap은 CPMM 자체 Swap 구조체의 #[account(mut)] 표시로부터 각 계정의 가변성을 대신 설정해 줍니다 — 생성된 필드는 모두 일반 AccountInfo<'info>이므로, 플래그를 담고 있는 것은 필드 타입이 아니라 파생된 ToAccountMetas 구현입니다.

Token-2022 프로그램 필드

입력 및 출력 민트는 다른 토큰 프로그램 아래에 있을 수 있습니다 — 하나는 SPL Token, 하나는 Token-2022. CPI는 이 이유로 별도의 input_token_program과 output_token_program 필드를 가집니다. 항상 각 민트의 owner 필드를 확인하고 올바른 프로그램을 각 슬롯으로 라우팅하세요.

버전화된 거래

2개 이상의 Raydium CPI와 ATA 생성을 수행하는 구성된 tx는 레거시 (v0-without-LUT) 거래에 거의 맞지 않습니다. V0을 주소 조회 테이블과 함께 사용하세요; raydium.getRaydiumLutAddresses()를 통해 Raydium의 공개 LUT를 가져오세요.

포인터

출처: