> ## 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.

# PDA'lar ve CPI'ler

> Program-derived addresses ve cross-program invocation — Raydium'un durumu deterministik şekilde yönetmesine ve diğer programlarla birleşmesine olanak tanıyan iki ilkel. Seed'ler, bump'lar, invoke vs invoke_signed ve Raydium kodunun izlediği desenler.

<Info>
  **Bu sayfa yapay zekâ tarafından otomatik olarak çevrilmiştir. İngilizce sürüm esas alınır.**

  [İngilizce sürümü görüntüle →](/solana-fundamentals/pdas-and-cpis)
</Info>

<Info>
  **PDA'lar** (program-derived addresses) ve **CPI'ler** (cross-program invocation) Raydium'u mümkün kılan iki ilkeldir. PDA'lar, bir programın özel anahtarlar olmadan deterministik adresler "sahip olmasını" sağlar — havuz yöneticileri ve vault'lar bu şekilde çalışır. CPI'ler, bir programın başka bir programı çağırmasını sağlar — Raydium'un SPL Token programı aracılığıyla token'ları değiştirmesi ve entegratörlerin Raydium'u kendi akışlarına dahil etmesi bu şekilde gerçekleşir. Raydium kaynak kodunu okumadan önce her ikisini anlamakta fayda vardır.
</Info>

## PDA'lar: anahtarsız adresler

Bir **Program-Derived Address** şu özelliklere sahip bir açık anahtardır:

* ed25519 eğrisinin üzerinde değildir (bunun için özel bir anahtar yoktur).
* Bir program ID'si ve bir dizi seed'den deterministik olarak türetilir.
* Yalnızca türetme programı tarafından `invoke_signed` aracılığıyla imzalanabilir.

Her Raydium havuz yöneticisi, her havuz durumu hesabı, her vault, her farm durumu — hepsi PDA'dır.

### Türetme

Bir PDA, program ID'si ve seed'ler hash'lenerek hesaplanır, ardından sonucu eğri dışına çıkaran bir "bump" baytı bulunur. Eğri dışı bir adres üreten ilk bump (genellikle 255'ten başlayıp azalan) başarılı olur; bu, **kanonik bump**'tır.

```ts theme={null}
import { PublicKey } from "@solana/web3.js";

const [poolAuthority, bump] = PublicKey.findProgramAddressSync(
  [Buffer.from("authority"), poolId.toBuffer()],
  CPMM_PROGRAM_ID,
);
```

Seed'ler herhangi bir şey olabilir — dizeler, diğer pubkey'ler, `u64` değerleri little-endian baytlar olarak. Raydium'un geleneği, insan tarafından okunabilir bir ön ek ve sonrasında benzersiz tanımlayıcıları kullanmaktır.

### Raydium PDA desenleri

Raydium programlarındaki yaygın PDA'lar:

| PDA                         | Seed'ler                                  | Program |
| --------------------------- | ----------------------------------------- | ------- |
| AMM yöneticisi (AMM v4)     | `[b"amm authority"]` + bump               | AMM v4  |
| Havuz durumu (CPMM)         | `[b"pool", amm_config, mint_a, mint_b]`   | CPMM    |
| Havuz vault'u (CPMM)        | `[b"pool_vault", pool, mint]`             | CPMM    |
| Yönetici (CPMM)             | `[b"vault_and_lp_mint_auth_seed"]`        | CPMM    |
| Havuz durumu (CLMM)         | `[b"pool", amm_config, mint_0, mint_1]`   | CLMM    |
| Tick dizisi (CLMM)          | `[b"tick_array", pool, start_tick_index]` | CLMM    |
| Gözlem (CLMM)               | `[b"observation", pool]`                  | CLMM    |
| Kişisel pozisyon (CLMM)     | `[b"position", position_nft_mint]`        | CLMM    |
| Farm durumu (Farm v6)       | `[b"pool_farm_state", farm_id]`           | Farm v6 |
| Kullanıcı defteri (Farm v6) | `[b"user_ledger", farm, user]`            | Farm v6 |

Kullanıcılar ve entegratörler, hiçbir şey getirmeden bu adresler hesaplayabilir — genel girdiler (havuz ID'si, farm ID'si, kullanıcı anahtarı) verildiğinde, PDA deterministiktir.

### Kanonik bump

İlk olarak eğri dışı adresler üreten birden fazla bump olabilse de, Raydium programları her zaman **kanonik bump** kullanır (255'ten azaltılarak bulunur). Bu, PDA'nın hesap verilerine depolanır, böylece sonraki işlemler bunu iletebilir ve (pahalı) türetme döngüsünü atlayabilir:

```rust theme={null}
#[account]
pub struct PoolState {
    pub bump: [u8; 1],
    // ... havuz durumunun geri kalanı
}
```

Sonraki işlemlerde, bump havuz durumundan okunur ve yeniden hesaplanmaz.

## CPI'ler: diğer programları çağırma

**Cross-Program Invocation**, bir programın başka bir programın talimatlarını tek bir işlem içinde satır içi çağırmasını sağlar. Raydium, CPI'leri yoğun şekilde kullanır:

* Swap talimatları, token'ları taşımak için SPL Token programını çağırır.
* CLMM, pozisyon NFT'sini basmak için Metaplex çağırır.
* Havuz oluşturma, hesapları tahsis etmek için Sistem Programını çağırır.
* Farm v6, ödülleri aktarmak için SPL Token çağırır.

Entegratörler ayrıca Raydium'a *çağırmak* için CPI'leri kullanır — vault stratejileri, kaldıraçlı-LP protokolleri ve otomatik-compounder'lar bu şekilde çalışır. Bkz. [`integration-guides/cpi-integration`](/tr/integration-guides/cpi-integration).

### invoke vs invoke\_signed

Solana çalışma zamanı iki CPI ilkeli sunar:

* **`invoke`**: başka bir programı çağırın; çağrılan program, dış işlemin imzacılarını devralır.
* **`invoke_signed`**: bir programı *bir PDA adına* çağırın; çalışma zamanı PDA'nın seed'lerini doğrular ve imzayı yetkilendirir.

`invoke_signed`, programların özel anahtarları yönetmeden hesaplar üzerinde yetki sahibi olmasını sağlayan sihirdir.

### Örnek: Raydium'un havuz vault'undan transfer etmesi

Bir havuz vault'u, yöneticisi havuz programının bir PDA'sı olan bir Token Hesabıdır. Bir swap sırasında token'ları dışarı aktarmak için, havuz programı bu PDA olarak imza atmalıdır:

```rust theme={null}
// Havuz yöneticisinin seed'leri
let authority_seeds: &[&[u8]] = &[
    b"vault_and_lp_mint_auth_seed",
    &[authority_bump],
];
let signer_seeds: &[&[&[u8]]] = &[authority_seeds];

// CPI bağlamını oluştur
let cpi_accounts = Transfer {
    from:      input_vault.to_account_info(),
    to:        user_ata.to_account_info(),
    authority: pool_authority.to_account_info(),
};
let cpi_program = token_program.to_account_info();
let cpi_ctx     = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds);

// Yürüt
token::transfer(cpi_ctx, amount)?;
```

Çalışma zamanı, `invoke_signed`'ın CPMM programı tarafından çağrıldığını görür, `vault_and_lp_mint_auth_seed + bump`'ın CPMM program ID'si ile hash'lendiğinde `pool_authority`'nin adresine türetilip türetilmediğini doğrular ve token transfer'inde yönetici imzasına izin verir. Özel anahtar söz konusu değildir.

### Örnek: entegratör Raydium CPMM'yi çağırma

Bir entegratör programı (örn. emanet) Raydium'un `swap_base_input` talimatını CPI aracılığıyla çağırabilir:

```rust theme={null}
use raydium_cpmm::cpi::{self, accounts::Swap};

let cpi_accounts = Swap {
    payer:                order.to_account_info(),      // PDA, imzalayacak
    authority:            pool_authority_info,
    amm_config:           amm_config_info,
    pool_state:           pool_info,
    input_token_account:  order_input_ata,
    output_token_account: order_output_ata,
    input_vault:          input_vault_info,
    output_vault:         output_vault_info,
    input_token_program:  input_token_program_info,
    output_token_program: output_token_program_info,
    input_token_mint:     input_mint_info,
    output_token_mint:    output_mint_info,
    observation_state:    observation_info,
};

let seeds = &[b"order", user.key.as_ref(), &[order.bump]];
let cpi_ctx = CpiContext::new_with_signer(
    cpmm_program.to_account_info(),
    cpi_accounts,
    &[seeds],
);

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

Bu, kanonik entegrasyon desenidir — tam emanet örneği için [`integration-guides/cpi-integration`](/tr/integration-guides/cpi-integration) bölümünü görebilirsiniz.

## CPI derinlik sınırı

Solana, CPI derinliğini **4 seviye** ile sınırlandırır. Bir işlemin üst düzey talimatı derinlik 0 olarak sayılır; her CPI çağırması derinliği arttırır.

Pratik etki: Raydium'un kendi swap'ı zaten 1-2 seviye CPI kullanır (Raydium → SPL Token). Raydium'u çağıran bir entegratör 2 seviye kullanır. Eğer bu entegratör başka bir entegratör tarafından çağrılırsa, 3 seviyedir. 4. seviye sınırdır.

Çoğu bileşim bunu kolayca aşar, ancak derin iç içe geçme (aggregator → router → Raydium → hook) buna çarpabilir. Düz tasarım, derin olmayan tasarım yapın.

## Kalan hesaplar

Bir Raydium talimatı değişken sayıda hesaba ihtiyaç duyduğunda (örn. bilinmeyen sayıda tick dizisini geçen CLMM swap'ı), ekstra hesaplar **kalan hesaplar** olarak iletilir — sabit hesap listesine eklenir, konuma göre yorumlanır.

CPMM'nin `SwapV2`'si, transfer-hook programlarının ekstra gerekli hesapları için kalan hesapları kullanır. İstemciler gerekli hesapları getirir ve ekler:

```ts theme={null}
const swapIx = await raydium.cpmm.swap({
  /* ... */
  // SDK kalan hesapları otomatik olarak yönetir
});
```

CPI seviyesinde, entegratörler kalan hesapları kendi talimatları aracılığıyla iletmelidir:

```rust theme={null}
pub struct Swap<'info> {
    // ... sabit hesaplar
    // Plus ctx.remaining_accounts aracılığıyla ilenen kalan hesaplar
}

// kalan_hesapları CPI'ye ilet
cpi::swap_base_input(
    cpi_ctx.with_remaining_accounts(ctx.remaining_accounts.to_vec()),
    amount_in,
    min_out,
)?;
```

## PDA tuzakları

### Yanlış seed'ler → yanlış adres

Seed'lerin yanlış sırada, yanlış kodlanmış veya ekstra bir bayt içeren/dışarı çıkan bir hata sessizce farklı bir PDA üretir. İşlem belirsiz şekilde başarısız olur (program varolmayan bir hesabı okumaya çalışır). Her zaman seed türetmesini bilinen altın değerlere karşı birim-test edin.

### Bump depolanmıyor

Eğer her işlemde bump'ı yeniden türetirseniz, türetme döngüsü için hesaplama ödeyersiniz. Kanonik bump'ı PDA'nın verilerine depolayın ve oradan okuyun.

### Kanonik vs kanonik olmayan bump karıştırılması

Kanonik olmayan bump'lar (eğri dışı üreten bulunursa) `invoke_signed` tarafından izin verilir, ancak Raydium programları tarafından `assert_eq!(bump, canonical_bump)` aracılığıyla reddedilir. Birisi kanonik olmayan bir bump ile PDA talep etmeye çalışırsa, tx başarısız olur.

### PDA'yı imzacı olarak iletme, ancak sahip programı olmadığında

Yalnızca PDA'nın türetilmesindeki ID'si bulunan program `invoke_signed`'ı seed'leriyle çağırabilir. Eğer çalışırsanız, çalışma zamanı reddeder.

## CPI tuzakları

### `remaining_accounts` iletmeyi unutma

Eğer dış talimatınız transfer-hook hesaplarını `remaining_accounts`'da iletiyorsa, ancak Raydium'a yapılan CPI onları iletmiyorsa, Raydium başarısız olur çünkü hook hesaplarını bulamaz. Her zaman ihtiyaç duyduğunda CPI'lere `with_remaining_accounts` ekleyin.

### Yazılabilir bayrakları uyuşmazlığı

Dış talimatın yazılabilir olarak işaretlediği bir hesap, CPI çağrısında da yazılabilir olmalıdır eğer çağrılan program bunu yazmayı amaçlıyorsa. Uyuşmazlık → çalışma zamanı reddi.

### Kira hesaplamıyor

Hesap oluşturan bir programa CPI (örn. ATA oluşturma), ödeyen'in kira için yeterli SOL'a sahip olmasını gerektirir. Başarısız kira kontrolleri belirsiz hatalar olarak görünür.

## Çalışan örnek: Raydium CPMM PDA'larını hesaplama

```ts theme={null}
import { PublicKey } from "@solana/web3.js";

const CPMM_PROGRAM_ID = new PublicKey("CPMMoo8L3F4NbTegBCKVNunggL7H1Zpdmwpwh8KMoZ0F");

function computeCpmmPdas(ammConfig, mintA, mintB) {
  const [poolState, poolBump] = PublicKey.findProgramAddressSync(
    [
      Buffer.from("pool"),
      ammConfig.toBuffer(),
      mintA.toBuffer(),
      mintB.toBuffer(),
    ],
    CPMM_PROGRAM_ID,
  );

  const [authority] = PublicKey.findProgramAddressSync(
    [Buffer.from("vault_and_lp_mint_auth_seed")],
    CPMM_PROGRAM_ID,
  );

  const [vaultA] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_vault"), poolState.toBuffer(), mintA.toBuffer()],
    CPMM_PROGRAM_ID,
  );

  const [vaultB] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_vault"), poolState.toBuffer(), mintB.toBuffer()],
    CPMM_PROGRAM_ID,
  );

  const [observation] = PublicKey.findProgramAddressSync(
    [Buffer.from("observation"), poolState.toBuffer()],
    CPMM_PROGRAM_ID,
  );

  return { poolState, authority, vaultA, vaultB, observation, poolBump };
}
```

Bu, `getPoolInfoFromRpc({ poolId })` çağırdığınızda Raydium SDK'sının kapaklar altında yaptığı şeydir — gidiş-dönüş olmadan ilişkili PDA'ları türetir.

## İşaretçiler

* [`solana-fundamentals/account-model`](/tr/solana-fundamentals/account-model) — PDA'ların hesap modelinde nasıl sığdığı.
* [`solana-fundamentals/programs-and-anchor`](/tr/solana-fundamentals/programs-and-anchor) — PDA'ları bildirmek için Anchor'ın yardımcıları.
* [`integration-guides/cpi-integration`](/tr/integration-guides/cpi-integration) — Raydium'a CPI yapan entegrasyonlar oluşturma.
* [`sdk-api/rust-cpi`](/tr/sdk-api/rust-cpi) — Raydium'un Rust CPI türleri.

Kaynaklar:

* [Solana PDA belgeleri](https://docs.solana.com/developing/programming-model/calling-between-programs).
* [Anchor PDA & CPI belgeleri](https://www.anchor-lang.com/docs/pdas-and-cpis).
