Luồng Thanh Toán
Gói @solana-commerce/headless cung cấp các hàm độc lập framework để xây dựng
luồng thanh toán thương mại. Những công cụ này giúp tạo các đối tượng yêu cầu
thanh toán, tạo URL Solana Pay, và xác minh các khoản thanh toán trên chuỗi. Gói
này được thiết kế để hoạt động trong bất kỳ môi trường JavaScript nào: React,
Vue, Svelte, vanilla JS, Node.js, hoặc các hàm serverless.
Cài Đặt
pnpm add @solana-commerce/headless
Các Hàm Yêu Cầu Thanh Toán
Những hàm này tạo ra các đối tượng yêu cầu thanh toán chuẩn hóa cho các mô hình thương mại khác nhau. Chúng không thực hiện bất kỳ thao tác blockchain nào—chúng chỉ cấu trúc dữ liệu để sử dụng trong ví, URL Solana Pay, hoặc giao diện thanh toán tùy chỉnh.
createBuyNowRequest()
Tạo một yêu cầu thanh toán chuẩn hóa cho việc mua một sản phẩm đơn lẻ.
function createBuyNowRequest(recipient: string,product: any,options?: {memo?: string;label?: string;message?: string;}): PaymentRequest;
Tham Số
-
recipient(string, bắt buộc) - Địa chỉ ví merchant (khóa công khai Solana mã hóa base58) sẽ nhận khoản thanh toán. -
product(any, bắt buộc) - Đối tượng sản phẩm chứa:price(số, bắt buộc) - Giá sản phẩm. Đơn vị phụ thuộc vào ngữ cảnh (ví dụ: lamport cho SOL, đơn vị nhỏ cho token).currency(chuỗi, bắt buộc) - Tiền tệ thanh toán. Có thể là'SOL'hoặc địa chỉ mint token.name(chuỗi, bắt buộc) - Tên sản phẩm, được sử dụng cho memo/nhãn mặc định nếu không được cung cấp.- Các trường bổ sung (id, description, image, v.v.) được truyền qua trong mảng
products.
-
options(đối tượng, tùy chọn) - Các tùy chọn tùy chỉnh:memo(chuỗi) - Memo trên chuỗi cho giao dịch. Mặc định:"Purchase: {product.name}".label(chuỗi) - Nhãn hiển thị cho yêu cầu thanh toán (sử dụng trong Solana Pay). Mặc định:product.name.message(chuỗi) - Thông báo thành công hiển thị sau khi thanh toán. Mặc định:"Thank you for purchasing {product.name}!".
Giá Trị Trả Về
Một đối tượng PaymentRequest chứa:
recipient- Địa chỉ ví merchantamount- Giá sản phẩm (sao chép từproduct.price)currency- Tiền tệ thanh toán (sao chép từproduct.currency)products- Mảng chứa sản phẩm đơn lẻmemo- Memo giao dịch (tùy chọn hoặc mặc định: "Purchase: (product.name)")label- Nhãn thanh toán (tùy chọn hoặc mặc định: "product.name")message- Thông báo thành công (tùy chọn hoặc mặc định: "Thank you for purchasing (product.name)!")
Ví dụ:
const payment = createBuyNowRequest("merchant-wallet-address",{id: "prod_123",name: "Premium Subscription",price: 50000000, // 0.05 SOL in lamportscurrency: "SOL"},{label: "Premium Subscription",message: "Thank you for subscribing!"});
createCartRequest()
Tạo yêu cầu thanh toán cho nhiều sản phẩm trong giỏ hàng.
function createCartRequest(recipient: string,products: any[],options?: {memo?: string;label?: string;message?: string;currency?: string;}): PaymentRequest;
Tham số
-
recipient(string, bắt buộc) - Địa chỉ ví của người bán sẽ nhận thanh toán. -
products(any[], bắt buộc) - Mảng các đối tượng sản phẩm. -
options(object, tùy chọn) - Các tùy chọn tùy chỉnh:currency(string) - Loại tiền thanh toán cho toàn bộ giỏ hàng.memo(string) - Ghi chú trên chuỗi. Mặc định:"Cart purchase (products.length items)".label(string) - Nhãn thanh toán. Mặc định:"Cart Checkout".message(string) - Thông báo thành công. Mặc định:"Thank you for your purchase!".
Giá trị trả về
Một đối tượng PaymentRequest với:
recipient- Địa chỉ ví của người bánamount- Tổng giá của tất cả sản phẩm (products.reduce((sum, p) => sum + p.price, 0))currency- Loại tiền thanh toán (từ options, hoặc undefined)products- Mảng các sản phẩmmemo,label,message- Giá trị tùy chọn hoặc giá trị mặc định
Ví dụ:
const cart = createCartRequest("merchant-wallet-address",[{ id: "1", name: "Product A", price: 25 },{ id: "2", name: "Product B", price: 15 },{ id: "3", name: "Product C", price: 10 }],{currency: "USDC",label: "My Store Checkout",message: "Thank you for your order!"});// cart.amount === 50 (sum of prices)
createTipRequest()
Tạo yêu cầu thanh toán cho tiền boa hoặc quyên góp với số tiền do người dùng xác định.
function createTipRequest(recipient: string,amount: number,options?: {currency?: string;memo?: string;label?: string;message?: string;}): PaymentRequest;
Tham số
-
recipient(string, bắt buộc) - Địa chỉ ví của người nhận tiền boa (người sáng tạo, streamer, tổ chức từ thiện, v.v.). -
amount(number, bắt buộc) - Số tiền boa. Đơn vị phụ thuộc vào loại tiền (lamport cho SOL, đơn vị nhỏ cho token). -
options(object, tùy chọn) - Các tùy chọn tùy chỉnh:currency(string) - Loại tiền thanh toán. Mặc định: undefined (thông thường được xử lý là SOL bởi người tiêu dùng).memo(string) - Ghi chú trên chuỗi. Mặc định:"Thank you for your support!".label(string) - Nhãn thanh toán. Mặc định:"Tip".message(string) - Thông báo thành công. Mặc định:"Thanks for the tip!".
Giá trị trả về
Một đối tượng PaymentRequest với:
recipient- Địa chỉ ví của người nhận tiền boaamount- Số tiền boacurrency- Loại tiền thanh toán (từ options, hoặc undefined)memo,label,message- Giá trị tùy chọn hoặc giá trị mặc định
Ví dụ:
const tip = createTipRequest("creator-wallet-address",5_000_000, // 0.005 SOL in lamports{currency: "SOL",label: "Tip for Content Creator",message: "Thanks for the support!"});
Các Hàm Xác Minh Thanh Toán
Các hàm này tương tác với Solana để xác minh giao dịch và chờ xác nhận. Chúng
yêu cầu một RPC client của Solana từ thư viện gill.
verifyPayment()
Xác minh rằng một giao dịch tồn tại trên chuỗi và tùy chọn xác thực số tiền thanh toán, người nhận và token.
async function verifyPayment(rpc: SolanaClient["rpc"],signatureString: string,expectedAmount?: number,expectedRecipient?: string,expectedMint?: string): Promise<PaymentVerificationResult>;
Tham Số
-
rpc(SolanaClient['rpc'], bắt buộc) - RPC client từgill. Tạo bằngcreateSolanaClient(rpcUrl).rpc. -
signatureString(string, bắt buộc) - Chữ ký giao dịch (mã hóa base58) cần xác minh. -
expectedAmount(number, tùy chọn) - Số tiền thanh toán dự kiến để xác thực. Đơn vị phải phù hợp với loại tiền tệ:- Đối với SOL: lamport (1 SOL = 1.000.000.000 lamport)
- Đối với SPL token: đơn vị nhỏ nhất dựa trên số thập phân của token (ví dụ: USDC sử dụng 6 chữ số thập phân)
Nếu không được cung cấp, việc xác thực số tiền sẽ bị bỏ qua.
-
expectedRecipient(string, tùy chọn) - Địa chỉ ví người nhận dự kiến. Nếu được cung cấp (cùng vớiexpectedAmount), hàm sẽ xác thực rằng người nhận đã nhận được ít nhất số tiền này. Nếu không được cung cấp, việc xác thực sẽ bị bỏ qua. -
expectedMint(string, tùy chọn) - Địa chỉ mint của SPL token. Chỉ yêu cầu cho các giao dịch chuyển SPL token. Nếu không được cung cấp, hàm sẽ giả định đó là giao dịch chuyển SOL.
Giá Trị Trả Về
Một đối tượng Promise<PaymentVerificationResult>:
interface PaymentVerificationResult {verified: boolean; // True if payment is validsignature?: string; // Transaction signature (echoed back)amount?: number; // Expected amount (echoed back)recipient?: string; // Expected recipient (echoed back)error?: string; // Error message if verification failed}
Logic Xác Minh
Hàm thực hiện các kiểm tra sau:
-
Tính Hợp Lệ Của Chữ Ký: Kiểm tra rằng chữ ký hợp lệ.
-
Sự Tồn Tại Của Giao Dịch: Lấy giao dịch bằng
rpc.getTransaction(). Nếu không tìm thấy, trả vềverified: false. -
Trạng Thái Xác Nhận: Kiểm tra rằng giao dịch đã được ghi nhận trên chuỗi.
-
Xác Thực Giao Dịch Chuyển SOL (nếu có
expectedRecipientvàexpectedAmountđược cung cấp, và không cóexpectedMint):- Tìm chỉ số tài khoản của người nhận trong giao dịch
- So sánh
preBalancesvàpostBalancesđể tính toán chênh lệch số dư - Xác minh rằng chênh lệch ít nhất bằng
expectedAmount
-
Xác thực chuyển SPL Token (nếu có
expectedMint):- Tạo Associated Token Account (ATA) của người nhận cho cả Token Program và Token-2022 Program
- Kiểm tra
postTokenBalancesđể tìm ATA khớp với mint mong đợi - Xác minh số lượng token ít nhất là
expectedAmount
Các cân nhắc về bảo mật
- Xác minh phía Client: Hàm này lấy dữ liệu giao dịch từ RPC. Không để lộ URL RPC của bạn cho client.
- Hoàn tất: Hàm kiểm tra các giao dịch đã xác nhận, nhưng đối với thanh toán
có giá trị cao, hãy cân nhắc chờ trạng thái
finalized.
Ví dụ:
import { verifyPayment } from "@solana-commerce/headless";import { createSolanaClient } from "gill";const client = createSolanaClient({urlOrMoniker: "mainnet"});const result = await verifyPayment(client.rpc,"transaction-signature-here",50_000_000, // 0.05 SOL in lamports"merchant-wallet-address"// No mint = SOL transfer);if (result.verified) {console.log("Payment confirmed!");} else {console.error("Verification failed:", result.error);}
waitForConfirmation()
Kiểm tra blockchain cho đến khi giao dịch đạt trạng thái đã xác nhận hoặc đã hoàn tất, hoặc hết thời gian chờ.
async function waitForConfirmation(rpc: SolanaClient["rpc"],signatureStr: string,timeoutMs?: number): Promise<boolean>;
Tham số
-
rpc(SolanaClient['rpc'], bắt buộc) - RPC client từgill. -
signatureStr(string, bắt buộc) - Chữ ký giao dịch cần chờ. -
timeoutMs(number, tùy chọn) - Thời gian chờ tối đa tính bằng mili giây. Mặc định:30000(30 giây).
Trả về
Promise<boolean>- Trả vềtruenếu giao dịch đạt trạng tháiconfirmedhoặcfinalizedtrong thời gian chờ, ngược lại trả vềfalse.
Ví dụ:
import { waitForConfirmation } from "@solana-commerce/headless";import { createSolanaClient } from "gill";const client = createSolanaClient({urlOrMoniker: "mainnet"});// After sending transactionconst signature = await wallet.sendTransaction(transaction);// Wait for confirmation (30 second timeout)const confirmed = await waitForConfirmation(client.rpc, signature, 30000);if (confirmed) {console.log("Transaction confirmed!");} else {console.log("Timeout - transaction not confirmed within 30 seconds");}
Các hàm Solana Pay
Các hàm này tạo URL Solana Pay và mã QR có kiểu dáng để quét bằng ví di động.
createSolanaPayRequest()
Tạo một URL Solana Pay và mã QR có kiểu dáng.
async function createSolanaPayRequest(request: TransferRequestURLFields,options: SolanaPayRequestOptions): Promise<{ url: URL; qr: string }>;
Tham số
-
request(TransferRequestURLFields, bắt buộc) - Các trường yêu cầu chuyển khoản Solana Pay:recipient- Khóa công khai của người nhận (sử dụngcreateRecipient(address)từ@solana-commerce/solana-pay)amount- (tùy chọn) Số tiền thanh toán theo đơn vị nhỏ nhất (lamport cho SOL)splToken(tùy chọn) - Khóa công khai của SPL token mint (sử dụngcreateSPLToken(address))reference(tùy chọn) - Khóa công khai tham chiếu để theo dõilabel(tùy chọn) - Tên người bánmessage(tùy chọn) - Thông báo thành côngmemo(tùy chọn) - Ghi chú trên chuỗi
-
options(SolanaPayRequestOptions, bắt buộc) - Các tùy chọn tạo kiểu mã QR:size(number) - Chiều rộng/chiều cao của mã QR tính bằng pixel. Mặc định:256.background(string) - Màu nền (hex/rgb). Mặc định:'white'.color(string) - Màu mã QR (hex/rgb). Mặc định:'black'.margin(number) - Lề xung quanh mã QR tính bằng module.errorCorrectionLevel('L' | 'M' | 'Q' | 'H') - Mức độ sửa lỗi. Mức độ cao hơn cho phép chịu được nhiều hư hỏng hơn nhưng tạo mã dày đặc hơn.logo(string) - URL hình ảnh logo để nhúng vào trung tâm mã QR.logoSize(number) - Kích thước logo tính theo phần trăm kích thước mã QR.logoBackgroundColor(string) - Màu nền phía sau logo.logoMargin(number) - Lề xung quanh logo.dotStyle('dots' | 'rounded' | 'square') - Hình dạng của các module mã QR.cornerStyle('square' | 'rounded' | 'extra-rounded' | 'full-rounded' | 'maximum-rounded') - Hình dạng của các điểm đánh dấu góc.
Giá trị trả về
Một Promise phân giải thành một đối tượng:
url(URL) - URL Solana Pay (ví dụ:solana:recipient?amount=10&spl-token=...)qr(string) - URL dữ liệu được mã hóa Base64 của hình ảnh mã QR (sử dụng làm<img src={qr} />)
Ví dụ:
import {createSolanaPayRequest,createRecipient,createSPLToken} from "@solana-commerce/solana-pay";const payment = await createSolanaPayRequest({recipient: createRecipient("merchant-wallet-address"),amount: 10_000_000, // 0.01 SOL in lamportssplToken: createSPLToken("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), // USDClabel: "My Store",message: "Thank you for your purchase!"},{size: 400,background: "#FFFFFF",color: "#000000",logo: "/logo.png",logoSize: 20,errorCorrectionLevel: "H"});// Display QR codedocument.getElementById("qr").src = payment.qr;console.log(payment.url.toString()); // solana:merchant...?amount=10000000&spl-token=...
Is this page helpful?