Огляд
Виведення коштів з Private Channels — це двоетапний процес. Спочатку користувач спалює
свій баланс токенів на стороні каналу, викликаючи WithdrawFunds у програмі Withdraw
Program. Потім оператор викликає ReleaseFunds у програмі Escrow Program (devnet,
у цьому покроковому керівництві) з дійсним доказом виключення Sparse Merkle Tree для
вивільнення коштів. Доказ SMT гарантує, що кожен одноразовий код виведення може бути використаний лише один раз,
запобігаючи подвійним витратам.
Крок 1: Ініціювання виведення в каналі
Викличте WithdrawFunds у програмі Withdraw Program, щоб спалити ваш баланс на стороні каналу.
Використовуйте варіант 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);
- Ідентифікатор програми Withdraw Program:
J231K9UEpS4y4KAPwGc4gsMNCjKFRMYcQBcjVW7vBhVi - Надішліть цю транзакцію до шлюзу (
http://localhost:8899), а не до публічного RPC Solana - Якщо вказано
destination, вивільнені кошти надходять до цього гаманця замість гаманця підписанта
Чого очікувати
Після виклику WithdrawFunds жодних додаткових дій не потрібно. Оператор
автоматично обробляє розрахунки:
indexer-private-channelопитує канал кожну 1 секунду на предмет подій спалення та записує запис про очікуване виведення, коли ваше буде виявленоoperator-private-channelопитує базу даних кожну 1 секунду на предмет очікуваних записів і надсилаєReleaseFundsдо програми Escrow Program на Solana devnet з необхідним доказом виключення SMT; він опитує devnet для підтвердження до 5 разів з інтервалом 400 мс перед повторною спробою
Зазвичай кошти з'являються у вашому гаманці devnet протягом кількох секунд за нормальних умов.
Як оператор здійснює розрахунки (Довідка)
Після спалення на стороні каналу підготовлений оператор повинен викликати ReleaseFunds у
програмі Escrow Program з дійсним доказом виключення SMT; оператор не може вивільнити
кошти без підтвердження того, що одноразовий код виведення не використовувався раніше. Цей крок
виконується автоматично за допомогою operator-private-channel; вам не потрібно викликати
його самостійно.
Оператор надає:
amount: має збігатися зі спаленою сумоюuser: гаманець одержувача на devnetnew_withdrawal_root: оновлений корінь SMT після цього виведенняtransaction_nonce: унікальний одноразовий код для цього листаsibling_proofs: 512 байт (16 x 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);
Ви завершили швидкий старт
Ви виконали повний цикл Private Channels на devnet: внесли SPL-токени до ескроу, здійснили позамережевий переказ через шлюз і вивели кошти назад до вашого гаманця devnet.
Життєвий цикл каналу
Детально ознайомтеся з учасниками та повним процесом від внеску до виведення.
Автентифікація та ролі
Додайте JWT-автентифікацію до вашої інтеграції.
Довідка з вивільнення коштів
Повна довідка з інструкції ReleaseFunds для інструментів оператора.
Sparse Merkle Tree
Дізнайтеся, як докази виведення запобігають подвійним витратам.
Is this page helpful?