Rút Tiền

Tổng quan

Việc rút tiền từ Private Channels là một quy trình hai bước. Đầu tiên, người dùng đốt số dư token phía kênh bằng cách gọi WithdrawFunds trên Withdraw Program. Thứ hai, một operator gọi ReleaseFunds trên Escrow Program (devnet, trong hướng dẫn này) với bằng chứng loại trừ Sparse Merkle Tree hợp lệ để giải phóng tiền. Bằng chứng SMT đảm bảo mỗi nonce rút tiền chỉ có thể được sử dụng một lần, ngăn chặn double-spend.

Bước 1: Khởi tạo Lệnh Rút Tiền trên Kênh

Gọi WithdrawFunds trên Withdraw Program để đốt số dư phía kênh của bạn. Sử dụng biến thể Async, tự động suy ra tokenAccount PDA và là dạng được khuyến nghị cho môi trường production:

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 RPC
const 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);
  • ID Withdraw Program: J231K9UEpS4y4KAPwGc4gsMNCjKFRMYcQBcjVW7vBhVi
  • Gửi giao dịch này đến gateway (http://localhost:8899), không phải đến Solana RPC công khai
  • Nếu destination được cung cấp, tiền được giải phóng sẽ đến ví đó thay vì ví của người ký

Những Điều Cần Biết

Không cần thực hiện thêm bất kỳ hành động nào sau khi gọi WithdrawFunds. Các dịch vụ operator xử lý việc thanh toán tự động:

  1. indexer-private-channel thăm dò kênh mỗi 1 giây để tìm sự kiện đốt token và ghi một bản ghi rút tiền đang chờ xử lý khi phát hiện bản ghi của bạn
  2. operator-private-channel thăm dò cơ sở dữ liệu mỗi 1 giây để tìm các bản ghi đang chờ xử lý và gửi ReleaseFunds đến Escrow Program trên Solana devnet với bằng chứng loại trừ SMT cần thiết; nó thăm dò xác nhận devnet tối đa 5 lần với khoảng cách 400 ms trước khi thử lại

Tiền thường xuất hiện trong ví devnet của bạn trong vài giây trong điều kiện bình thường.

Cách Operator Thực Hiện Thanh Toán (Tham khảo)

Sau khi đốt token phía kênh, một operator đã được cấp phép phải gọi ReleaseFunds trên Escrow Program với bằng chứng loại trừ SMT hợp lệ; operator không thể giải phóng tiền mà không chứng minh rằng nonce rút tiền chưa được sử dụng trước đó. Bước này được xử lý tự động bởi operator-private-channel; bạn không cần gọi nó theo cách thủ công.

Operator cung cấp:

  • amount: phải khớp với số lượng đã đốt
  • user: ví nhận trên devnet
  • new_withdrawal_root: gốc SMT được cập nhật sau lần rút tiền này
  • transaction_nonce: nonce duy nhất cho leaf này
  • sibling_proofs: 512 byte (16 x 32-byte sibling hash cho bằng chứng cây)

Xác minh

Sau khi lệnh gọi của operator được xác nhận, hãy kiểm tra số dư token devnet của bạn:

spl-token balance <MINT_ADDRESS> --owner <YOUR_WALLET>

Hoặc qua 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 gateway
const 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);

Bạn Đã Hoàn Thành Quickstart

Bạn đã chạy toàn bộ chu trình Private Channels trên devnet: gửi token SPL vào escrow, gửi một giao dịch off-chain qua gateway, và rút tiền trở lại ví devnet của bạn.

Is this page helpful?

Mục lục

Chỉnh sửa trang