نظرة عامة
يتكون السحب من القنوات الخاصة من خطوتين. أولاً، يقوم المستخدم بحرق رصيد الرموز المميزة على جانب القناة عن طريق استدعاء WithdrawFunds على برنامج السحب. ثانياً، يستدعي المشغّل ReleaseFunds على برنامج الضمان (devnet، في هذا الدليل التطبيقي) مع إثبات استبعاد Sparse Merkle Tree صالح لتحرير الأموال. يضمن إثبات SMT أن كل nonce سحب لا يمكن استخدامه إلا مرة واحدة، مما يمنع الإنفاق المزدوج.
الخطوة 1: بدء عملية السحب على القناة
استدعِ WithdrawFunds على برنامج السحب لحرق رصيدك على جانب القناة.
استخدم المتغير Async، الذي يشتق تلقائياً PDA الخاص بـ tokenAccount وهو
الشكل الموصى به للاستخدام في بيئة الإنتاج:
import { getWithdrawFundsInstructionAsync } from "../private-channel-withdraw-program/clients/typescript/src/generated";import {createSolanaRpc,address,pipe,createTransactionMessage,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,appendTransactionMessageInstruction,signAndSendTransactionMessageWithSigners,assertIsTransactionMessageWithSingleSendingSigner,getBase58Decoder} from "@solana/kit";// Point to the gateway, not a public Solana RPCconst privateChannelRpc = createSolanaRpc("http://localhost:8899");const withdrawIx = await getWithdrawFundsInstructionAsync({user: userSigner,mint: address(mintAddress),amount: 1_000_000n, // 1 USDC (6 decimals)destination: null // null = release to signer's devnet wallet});const { value: latestBlockhash } = await privateChannelRpc.getLatestBlockhash({ commitment: "confirmed" }).send();// Sent to the Private Channels gateway (not Solana RPC directly), which// expects the legacy transaction format - do not switch this to version 0.const transactionMessage = pipe(createTransactionMessage({ version: "legacy" }),(m) => setTransactionMessageFeePayerSigner(userSigner, m),(m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),(m) => appendTransactionMessageInstruction(withdrawIx, m));assertIsTransactionMessageWithSingleSendingSigner(transactionMessage);const signatureBytes =await signAndSendTransactionMessageWithSigners(transactionMessage);const signature = getBase58Decoder().decode(signatureBytes);console.log("Withdrawal initiated:", signature);
- معرّف برنامج السحب:
J231K9UEpS4y4KAPwGc4gsMNCjKFRMYcQBcjVW7vBhVi - أرسل هذه المعاملة إلى البوابة (
http://localhost:8899)، وليس إلى نقطة اتصال RPC عامة بسولانا - إذا تم توفير
destination، فستذهب الأموال المحررة إلى تلك المحفظة بدلاً من محفظة الموقّع
ما الذي يمكن توقعه
لا يلزم اتخاذ أي إجراء آخر بعد استدعاء WithdrawFunds. تتولى خدمات المشغّل
معالجة التسوية تلقائياً:
indexer-private-channelيستطلع القناة كل ثانية واحدة بحثاً عن أحداث الحرق ويكتب سجل سحب معلّق عند اكتشاف سحبكoperator-private-channelيستطلع قاعدة البيانات كل ثانية واحدة بحثاً عن السجلات المعلّقة ويرسلReleaseFundsإلى برنامج الضمان على سولانا devnet مع إثبات استبعاد SMT المطلوب؛ ويستطلع تأكيد devnet حتى 5 مرات بفواصل زمنية تبلغ 400 مللي ثانية قبل إعادة المحاولة
تظهر الأموال عادةً في محفظة devnet الخاصة بك في غضون ثوانٍ قليلة في الظروف الاعتيادية.
كيفية تسوية المشغّل (مرجع)
بعد الحرق على جانب القناة، يجب على المشغّل المُزوَّد استدعاء ReleaseFunds على
برنامج الضمان مع إثبات استبعاد SMT صالح؛ لا يمكن للمشغّل تحرير
الأموال دون إثبات أن nonce السحب لم يُستخدم من قبل. تتم معالجة هذه الخطوة
تلقائياً بواسطة operator-private-channel؛ ولا تحتاج إلى استدعائها بنفسك.
يوفر المشغّل:
amount: يجب أن يطابق المبلغ المحروقuser: محفظة المستلم على devnetnew_withdrawal_root: جذر SMT المحدَّث بعد هذا السحبtransaction_nonce: nonce فريد لهذه الورقةsibling_proofs: 512 بايت (16 × تجزئة أشقاء بحجم 32 بايت لإثبات الشجرة)
التحقق
بعد تأكيد استدعاء المشغّل، تحقق من رصيد رمزك المميز على devnet:
spl-token balance <MINT_ADDRESS> --owner <YOUR_WALLET>
أو عبر RPC:
import { createSolanaRpc, address } from "@solana/kit";import { findAssociatedTokenPda } from "@solana-program/token";const TOKEN_PROGRAM_ADDRESS = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");// Query devnet directly; ReleaseFunds settles here, not through the gatewayconst rpc = createSolanaRpc("https://api.devnet.solana.com");const [yourDevnetAta] = await findAssociatedTokenPda({mint: address(mintAddress),owner: address(userSigner.address),tokenProgram: TOKEN_PROGRAM_ADDRESS});const balance = await rpc.getTokenAccountBalance(yourDevnetAta).send();console.log(balance.value.uiAmountString);
لقد أتممت البدء السريع
لقد نفّذت دورة القنوات الخاصة الكاملة على devnet: أودعت رموز SPL في الضمان، وأرسلت تحويلاً خارج السلسلة عبر البوابة، وسحبت الأموال مرة أخرى إلى محفظة devnet الخاصة بك.
Is this page helpful?