الانتقال إلى المحتوى الرئيسي

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.

هذه الصفحة مُترجَمة آليًا بواسطة الذكاء الاصطناعي. النسخة الإنجليزية هي المرجع المعتمد.عرض النسخة الإنجليزية →
إنشاء مجمع جديد غير موضح هنا. لم تعد واجهة Raydium توفر إنشاء مجمع AMM v4 — الأزواج الجديدة تستخدم افتراضياً CPMM. برنامج AMM v4 نفسه لا يزال يقبل Initialize2 على السلسلة؛ لكنه ليس المسار الموصى به. الأمثلة أدناه تغطي عمليات المجمع المباشر التي يحتاجها كل متكامل: المبادلة والإيداع والسحب.

الإعداد

import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import fs from "node:fs";

const connection = new Connection(process.env.RPC_URL ?? clusterApiUrl("mainnet-beta"));
const owner = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(fs.readFileSync(process.env.KEYPAIR!, "utf8"))),
);
const raydium = await Raydium.load({ owner, connection, cluster: "mainnet" });

جلب مجمع حسب المعرّف

import { PublicKey } from "@solana/web3.js";

const poolId = new PublicKey("<AMM_V4_POOL_ID>");

// سحب كائن المجمع المُطبّع من SDK. بالنسبة لـ AMM v4 يتضمن حسابات OpenBook
// التي ستحتاجها منشئات التعليمات.
const data = await raydium.liquidity.getPoolInfoFromRpc({ poolId });
const { poolInfo, poolKeys, poolRpcData } = data;

console.log("Pair:", poolInfo.mintA.symbol, "/", poolInfo.mintB.symbol);
console.log("Version:", poolInfo.version);       // 4 for AMM v4
console.log("Market:", poolKeys.marketId.toBase58());
poolKeys هو الهيكل الذي تستهلكه منشئات التعليمات. يحمل كل حساب AMM v4 و OpenBook بالترتيب الذي يتوقعه البرنامج.

المبادلة (الإدخال الأساسي)

import BN from "bn.js";

const amountIn = new BN(1_000_000);            // 1 USDC (6-decimal quote)
const inputMint = new PublicKey(poolInfo.mintB.address);  // USDC
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountOut({
  poolInfo,
  amountIn,
  mintIn: inputMint,
  mintOut: new PublicKey(poolInfo.mintA.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn,
  amountOut: computed.minAmountOut,
  fixedSide: "in",
  inputMint,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Swap tx:", txId);
SDK يضيف كل حساب OpenBook تلقائياً. لا تحاول استبدالها يدويّاً — البرنامج يتحقق من كل فتحة.

المبادلة (الإخراج الأساسي)

const amountOut = new BN(1_000_000_000);       // 1 SOL (9-decimal base)
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountIn({
  poolInfo,
  amountOut,
  mintOut: new PublicKey(poolInfo.mintA.address),
  mintIn: new PublicKey(poolInfo.mintB.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn: computed.maxAmountIn,
  amountOut,
  fixedSide: "out",
  inputMint: new PublicKey(poolInfo.mintB.address),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });

إضافة السيولة

const amountA = new BN(100_000_000);           // 0.1 SOL

const { anotherAmount, maxAnotherAmount } = raydium.liquidity.computePairAmount({
  poolInfo,
  amount: amountA,
  baseIn: true,
  slippage: 0.01,
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo,
  poolKeys,
  amountInA: amountA,
  amountInB: maxAnotherAmount,
  fixedSide: "a",
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
fixedSide: "a" يخبر SDK أنك وفّرت amountInA الدقيق وأن amountInB يجب أن يكون على الأكثر maxAnotherAmount. السيولة المباشرة للمجمع تُسوّى قبل حساب النسبة المئوية، لذا نسبة الإيداع تطابق الاحتياطيات الطازجة.

إزالة السيولة

const lpAmount = new BN(50_000);               // LP to burn

const { execute } = await raydium.liquidity.removeLiquidity({
  poolInfo,
  poolKeys,
  lpAmount,
  baseAmountMin: new BN(0),
  quoteAmountMin: new BN(0),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
الحدود الدنيا للانزلاق تحمي ضد تغيير حالة المجمع بين اقتباسك المسبق وزمن التسجيل.

ضبط وحدة الحساب / رسم الأولوية

مبادلات AMM v4 ثقيلة على الحساب لأن كل تعليمة تتحقق من حالة OpenBook الكاملة. المبادلة النموذجية تستخدم 180k–250k CU اعتماداً على عدد الطلبات المفتوحة التي تحتاج إلى التسوية في الطريق. دائماً حدد حد وحدة الحساب:
import { ComputeBudgetProgram } from "@solana/web3.js";

const { execute, innerTransactions } = await raydium.liquidity.swap({
  /* ...params... */
  computeBudgetConfig: {
    units: 400_000,
    microLamports: 50_000,       // priority fee
  },
});
إذا حذفت computeBudgetConfig، قد يستخدم SDK افتراضيّه الخاص بأي حال؛ تحقق من innerTransactions للتأكيد. انظر integration-guides/priority-fee-tuning.

CPI من Rust مباشرة

إذا كان عليك CPI إلى AMM v4 من برنامج Anchor خاص بك، ستحتاج إلى نمذجة قائمة الحسابات الخاصة بـ SwapBaseIn بدقة. رسم بسيط:
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::solana_program::instruction::Instruction;

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

#[derive(Accounts)]
pub struct ProxyAmmV4Swap<'info> {
    /// CHECK:
    pub token_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm:          UncheckedAccount<'info>,
    /// CHECK:
    pub amm_authority: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_open_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_target_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_coin_token_account: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_pc_token_account: UncheckedAccount<'info>,
    /// CHECK:
    pub market_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_bids: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_asks: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_event_queue: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_coin_vault: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_pc_vault: UncheckedAccount<'info>,
    /// CHECK:
    pub market_vault_signer: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_source: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_dest: UncheckedAccount<'info>,
    pub user_owner: Signer<'info>,
}

pub fn proxy_swap(
    ctx: Context<ProxyAmmV4Swap>,
    amount_in: u64,
    minimum_amount_out: u64,
) -> Result<()> {
    // Instruction discriminator for SwapBaseIn is 9 on AMM v4.
    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(ctx.accounts.token_program.key(), false),
            AccountMeta::new(ctx.accounts.amm.key(), false),
            AccountMeta::new_readonly(ctx.accounts.amm_authority.key(), false),
            AccountMeta::new(ctx.accounts.amm_open_orders.key(), false),
            AccountMeta::new(ctx.accounts.amm_target_orders.key(), false),
            AccountMeta::new(ctx.accounts.pool_coin_token_account.key(), false),
            AccountMeta::new(ctx.accounts.pool_pc_token_account.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_program.key(), false),
            AccountMeta::new(ctx.accounts.market.key(), false),
            AccountMeta::new(ctx.accounts.market_bids.key(), false),
            AccountMeta::new(ctx.accounts.market_asks.key(), false),
            AccountMeta::new(ctx.accounts.market_event_queue.key(), false),
            AccountMeta::new(ctx.accounts.market_coin_vault.key(), false),
            AccountMeta::new(ctx.accounts.market_pc_vault.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_vault_signer.key(), false),
            AccountMeta::new(ctx.accounts.user_source.key(), false),
            AccountMeta::new(ctx.accounts.user_dest.key(), false),
            AccountMeta::new_readonly(ctx.accounts.user_owner.key(), true),
        ],
        data,
    };
    invoke_signed(&ix, &ctx.accounts.to_account_infos(), &[])?;
    Ok(())
}
AMM v4 لا يشحن صندوق Anchor لـ CPI. الرسم أعلاه يستخدم Instruction مبنيّة يدويّاً.

الأخطاء الشائعة

  • فقدان حساب OpenBook. جميع 8 حسابات من جانب OpenBook مطلوبة على كل مبادلة وإيداع وسحب؛ SDK يتعامل مع هذا، التعليمات المبنيّة يدويّاً غالباً لا تفعل.
  • قراءة أرصدة الخزينة الخام. لا تعكس الكميات المرهونة خارج السلسلة أو الأرباح المتراكمة. استخدم اقتباس SDK أو api-v3.raydium.io/pools/info/ids.
  • طابور أحداث OpenBook ممتلئ. قد يؤدي المجمع إلى عودة المبادلات مع SerumOrderError عندما تحتاج طابور أحداث السوق إلى الدوران. الدوران خالٍ من الأذونات (MonitorStep على حسابات OpenBook للسوق).
  • Mint من Token-2022. غير مدعوم. لا يمكن إنشاء مجمع AMM v4 ضد Token-2022 mint؛ أي زوج Token-2022 يجب أن يكون على CPMM أو CLMM.

الخطوات التالية

المصادر: