> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust CPI

> Aufrufen von Raydium-Programmen aus einem anderen Solana-Programm — Kontolisten-Konstruktion, Signierseeds, Compute-Budget und Error-Propagation-Muster für CPMM, CLMM, Farm v6 und LaunchLab. AMM v4 wird separat behandelt, da es keine Anchor-Crate hat.

<Info>
  **Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.**

  [Englische Version ansehen →](/sdk-api/rust-cpi)
</Info>

<Info>
  CPI (»Cross-Program Invocation«) ist der Mechanismus, mit dem ein Solana-Programm ein anderes aufruft. Raydiums Anchor-Programme werden mit CPI-Wrapper-Crates ausgeliefert, die den Aufrufplatz wie einen typisierten Funktionsaufruf erscheinen lassen — Kontostrukturen mit validierten Feldnamen und `cpi::<ix>()`-Hilfsfunktionen. Diese Seite dokumentiert das allgemeine Muster; für produktspezifische Snippets siehe die Code-Demos-Seite jedes Produktkapitels.
</Info>

## Cargo-Abhängigkeiten

```toml theme={null}
[dependencies]
anchor-lang            = "0.29"
anchor-spl             = "0.29"
raydium_cp_swap        = { git = "https://github.com/raydium-io/raydium-cp-swap", features = ["cpi"] }
raydium_amm_v3         = { git = "https://github.com/raydium-io/raydium-clmm",    features = ["cpi"] }
# AMM v4 and farm v6: no published Anchor CPI crate. See "AMM v4 / farm v6" below.
```

Das `cpi`-Feature-Flag sorgt dafür, dass die Crates nur zu der CPI-Oberfläche kompiliert werden (Kontostrukturen + Invoker) anstelle des vollständigen Programms, sodass Ihr Binary klein bleibt.

Für funktionierende CPI-Beispiele, die die Kontostrukturen end-to-end verbinden, siehe [`raydium-io/raydium-cpi-example`](https://github.com/raydium-io/raydium-cpi-example) (behandelt AMM v4, CPMM und CLMM).

## Kontolisten-Konstruktion

Jede Raydium-CPI erfordert eine `Accounts`-Struktur im aufrufenden Programm. Felder entsprechen 1:1 der Kontenreihenfolge des Programm-Befehls mit Feldvalidierungen:

```rust theme={null}
use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount, Mint};

#[derive(Accounts)]
pub struct MyProxySwap<'info> {
    #[account(mut)]
    pub user: Signer<'info>,

    /// CHECK: validated by CPMM
    #[account(mut)]
    pub pool_state: UncheckedAccount<'info>,

    /// CHECK: ditto
    pub amm_config: UncheckedAccount<'info>,

    /// CHECK: ditto
    pub pool_authority: UncheckedAccount<'info>,

    #[account(mut)]
    pub input_vault: Account<'info, TokenAccount>,
    #[account(mut)]
    pub output_vault: Account<'info, TokenAccount>,

    pub input_mint: Account<'info, Mint>,
    pub output_mint: Account<'info, Mint>,

    #[account(mut)]
    pub user_input_ata:  Account<'info, TokenAccount>,
    #[account(mut)]
    pub user_output_ata: Account<'info, TokenAccount>,

    pub cpmm_program: Program<'info, raydium_cp_swap::program::RaydiumCpSwap>,
    pub token_program: Program<'info, Token>,
    pub token_program_2022: Program<'info, anchor_spl::token_2022::Token2022>,
    /// CHECK: observation PDA
    #[account(mut)]
    pub observation_state: UncheckedAccount<'info>,
}
```

Die meisten Raydium-seitigen Konten sind `UncheckedAccount`, weil der aufgerufene (Raydium) die Validierung übernimmt. Ihr aufrutendes Programm validiert nur streng Konten, die *Sie* besitzen — Benutzer-ATAs, Ihre eigenen PDAs. Der `/// CHECK:`-Doc-Kommentar unterdrückt Anchors Warnung über fehlende Checks.

## Aufbau des CPI-Aufrufs

Anchor generiert eine Hilfsfunktion pro Befehl:

```rust theme={null}
use raydium_cp_swap::cpi::{self, accounts::Swap as CpmmSwap};

pub fn my_proxy_swap(
    ctx: Context<MyProxySwap>,
    amount_in: u64,
    minimum_amount_out: u64,
) -> Result<()> {
    let cpi_accounts = CpmmSwap {
        payer:                ctx.accounts.user.to_account_info(),
        authority:            ctx.accounts.user.to_account_info(),
        amm_config:           ctx.accounts.amm_config.to_account_info(),
        pool_state:           ctx.accounts.pool_state.to_account_info(),
        input_token_account:  ctx.accounts.user_input_ata.to_account_info(),
        output_token_account: ctx.accounts.user_output_ata.to_account_info(),
        input_vault:          ctx.accounts.input_vault.to_account_info(),
        output_vault:         ctx.accounts.output_vault.to_account_info(),
        input_token_program:  ctx.accounts.token_program.to_account_info(),
        output_token_program: ctx.accounts.token_program.to_account_info(),
        input_token_mint:     ctx.accounts.input_mint.to_account_info(),
        output_token_mint:    ctx.accounts.output_mint.to_account_info(),
        observation_state:    ctx.accounts.observation_state.to_account_info(),
    };
    let cpi_ctx = CpiContext::new(
        ctx.accounts.cpmm_program.to_account_info(),
        cpi_accounts,
    );

    cpi::swap_base_input(cpi_ctx, amount_in, minimum_amount_out)?;
    Ok(())
}
```

`cpi::swap_base_input` wird aus dem IDL generiert; seine Argumentliste spiegelt die Argumentliste des Anchor-Befehls.

## Signierseeds (PDA-signierte CPI)

Wenn Ihr Programm die CPI im Namen einer PDA signiert (häufig bei Tresoren, Hinterlegungen usw.), verwenden Sie `CpiContext::new_with_signer`:

```rust theme={null}
let bump         = ctx.accounts.my_authority_bump;
let signer_seeds: &[&[&[u8]]] = &[&[b"my_authority", &[bump]]];

let cpi_ctx = CpiContext::new_with_signer(
    ctx.accounts.cpmm_program.to_account_info(),
    cpi_accounts,
    signer_seeds,
);

cpi::swap_base_input(cpi_ctx, amount_in, minimum_amount_out)?;
```

Die Signierseeds müssen mit der Ableitung der PDA übereinstimmen. Für jedes Konto, das als `authority` (oder ähnliche Signierrolle) weitergegeben wird, prüft die Solana-Runtime, dass die PDA durch diese Seeds signiert.

## Verbleibende Konten

Einige Raydium-Befehle nutzen **verbleibende Konten** — eine variable Liste, die nach den festen Konten angehängt wird. Die kanonischen Beispiele:

* **CLMM `SwapV2`**: hängt 1–8 `TickArrayState`-Konten an, die den Tick-Arrays entsprechen, die der Swap durchlaufen könnte.
* **Farm v6 `Deposit`**: hängt `(reward_vault, user_reward_ata)`-Paare für jeden aktiven Reward-Stream an.

Anchors CPI-Hilfsfunktionen prüfen verbleibende Konten nicht typsicher. Übergeben Sie diese über `.with_remaining_accounts(...)`:

```rust theme={null}
let cpi_ctx = CpiContext::new(program, accounts)
    .with_remaining_accounts(ctx.remaining_accounts.to_vec());
```

Die Reihenfolge ist wichtig: das Empfängerprogramm iteriert die verbleibenden Konten in der Reihenfolge, in der Sie diese übergeben. Bei CLMM müssen Tick-Arrays direktional sortiert werden (erstes Array in Swap-Richtung zuerst). Bei Farm v6 gehen Reward-Slots in Slot-Index-Reihenfolge.

## Error-Propagation

Raydiums Programme geben ihre eigenen Error-Enums zurück. Anchor umhüllt diese; Ihr aufrutendes Programm sieht sie als `Err(ProgramError::Custom(code))`. Um spezifische Fehler zu handhaben:

```rust theme={null}
use raydium_cp_swap::error::ErrorCode as CpmmErr;

match cpi::swap_base_input(cpi_ctx, amount_in, minimum_amount_out) {
    Ok(_) => Ok(()),
    Err(e) => {
        msg!("CPMM swap failed: {:?}", e);
        // Re-raise, or convert to your own error type.
        Err(e)
    }
}
```

Die Error-Code-Nummer ist stabil gemäß der IDL-Richtlinie ([`sdk-api/anchor-idl`](/de/sdk-api/anchor-idl)). Sie können gegen spezifische Codes testen, indem Sie gegen den numerischen Wert vergleichen.

## Compute-Budget in zusammengesetzten CPIs

Jeder CPI-Frame hat Overhead (\~1.500 CU für den Aufruf selbst), und der eigene CU-Verbrauch des aufgerufenen Programms stapelt sich auf Ihrem. Eine Transaktion, die einen CPMM-Swap von innerhalb Ihres Programms aufruft, verbraucht:

```
your_program_cu
+ ~1_500       (CPI overhead)
+ ~150_000     (CPMM swap, SPL-token variant)
+ ~200_000     (if Token-2022 with transfer fee)
+ ~10_000      (observation update)
```

Für Stacking-Routing (Ihr Programm → Aggregator → CPMM + CLMM + Farm Harvest) Budget ≥500k CU. Setzen Sie immer einen expliziten `ComputeBudgetProgram::set_compute_unit_limit(...)`-Befehl in der Transaktion — das Standard-200k-CU-Limit wird sich stumm erschöpfen.

## AMM v4 — manuelle Instruction-Konstruktion

AMM v4 hat keine Anchor-Crate. Bauen Sie die `Instruction` von Hand:

```rust theme={null}
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::solana_program::instruction::{Instruction, AccountMeta};

const AMM_V4_PROGRAM_ID: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");

// SwapBaseIn discriminator is 9.
let mut data = vec![9u8];
data.extend_from_slice(&amount_in.to_le_bytes());
data.extend_from_slice(&minimum_amount_out.to_le_bytes());

let ix = Instruction {
    program_id: AMM_V4_PROGRAM_ID,
    accounts: vec![
        AccountMeta::new_readonly(token_program_id, false),
        AccountMeta::new(amm_id, false),
        AccountMeta::new_readonly(amm_authority, false),
        // ... remaining accounts per products/amm-v4/instructions ...
    ],
    data,
};
invoke_signed(&ix, &account_infos, signer_seeds)?;
```

Siehe [`products/amm-v4/code-demos`](/de/products/amm-v4/code-demos) für die vollständige Kontoliste.

## Farm v6 — Reward-Pair-verbleibende Konten

Farm v6s `Deposit` / `Withdraw` / `Harvest` nutzen das `(reward_vault_i, user_reward_ata_i)`-Pair-Muster in verbleibenden Konten. Genaue Reihenfolge:

```
remaining_accounts = [
    reward_vault_0, user_reward_ata_0,
    reward_vault_1, user_reward_ata_1,
    ...
]
```

Ein Pair pro **aktiven** (laufenden oder beendeten-aber-ungesammelten) Reward-Slot. Lassen Sie ungenutzte Slots weg; das Programm dispatched von `farm_state.reward_infos[i].reward_state`.

## Testen eines CPI-Flows

Local Dev erfordert, dass die Raydium-Programme in Ihrem Test-Validator verfügbar sind. Optionen:

1. **`anchor test` mit Program Clone** — in `Anchor.toml`:

   ```toml theme={null}
   [test.validator]
   clone = [
     { address = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK" },  # CPMM
     { address = "CLMM...program-id..." },                          # CLMM
     { address = "farm-v6-program-id..." },                         # farm v6
   ]
   ```

   Dies zieht den eingesetzten Bytecode von Mainnet in Ihren lokalen Validator.

2. **Devnet** — Raydium setzt alle Programme auf Devnet mit denselben Program-IDs wie Mainnet ein. Führen Sie `anchor test --provider.cluster devnet` aus, um auf Live-Code zuzugreifen.

3. **Lokales Deploy** — Klonen Sie die Raydium-Repos und `anchor deploy` auf einen lokalen Validator. Fügt Test-Zyklus-Overhead hinzu, ermöglicht aber, dass Sie den aufgerufenen Code zum Debuggen ändern.

## Verweise

* [`products/cpmm/code-demos`](/de/products/cpmm/code-demos), [`products/clmm/code-demos`](/de/products/clmm/code-demos), [`products/amm-v4/code-demos`](/de/products/amm-v4/code-demos), [`products/farm-staking/code-demos`](/de/products/farm-staking/code-demos) — produktspezifische CPI-Beispiele.
* [`sdk-api/anchor-idl`](/de/sdk-api/anchor-idl) — IDL-Abruf und Clientregeneration.
* [`integration-guides/cpi-integration`](/de/integration-guides/cpi-integration) — übergeordnete Muster: Hinterlegungen, Tresore, Aggregator-Komposition.

Quellen:

* [raydium-cp-swap](https://github.com/raydium-io/raydium-cp-swap)
* [raydium-clmm](https://github.com/raydium-io/raydium-clmm)
* [Anchor CPI docs](https://www.anchor-lang.com/docs/cross-program-invocations)
