Alur Pembayaran
Paket @solana-commerce/headless menyediakan fungsi-fungsi yang tidak terikat
framework untuk membangun alur pembayaran perdagangan. Alat-alat ini membantu
membuat objek permintaan pembayaran, menghasilkan URL Solana Pay, dan
memverifikasi pembayaran on-chain. Paket ini dirancang untuk bekerja di
lingkungan JavaScript apa pun: React, Vue, Svelte, vanilla JS, Node.js, atau
fungsi serverless.
Instalasi
pnpm add @solana-commerce/headless
Fungsi Permintaan Pembayaran
Fungsi-fungsi ini membuat objek permintaan pembayaran yang terstandarisasi untuk pola perdagangan yang berbeda. Mereka tidak melakukan operasi blockchain apa pun—mereka hanya menyusun data untuk digunakan dalam dompet, URL Solana Pay, atau UI pembayaran kustom.
createBuyNowRequest()
Membuat permintaan pembayaran terstandarisasi untuk pembelian produk tunggal.
function createBuyNowRequest(recipient: string,product: any,options?: {memo?: string;label?: string;message?: string;}): PaymentRequest;
Parameter
-
recipient(string, wajib) - Alamat dompet pedagang (kunci publik Solana yang dikodekan base58) yang akan menerima pembayaran. -
product(any, wajib) - Objek produk yang berisi:price(angka, wajib) - Harga produk. Satuannya tergantung pada konteks (misalnya, lamport untuk SOL, unit minor untuk token).currency(string, wajib) - Mata uang pembayaran. Bisa berupa'SOL'atau alamat mint token.name(string, wajib) - Nama produk, digunakan untuk memo/label default jika tidak disediakan.- Bidang tambahan (id, deskripsi, gambar, dll.) diteruskan dalam array
products.
-
options(objek, opsional) - Opsi kustomisasi:memo(string) - Memo on-chain untuk transaksi. Default:"Purchase: {product.name}".label(string) - Label tampilan untuk permintaan pembayaran (digunakan dalam Solana Pay). Default:product.name.message(string) - Pesan sukses yang ditampilkan setelah pembayaran. Default:"Thank you for purchasing {product.name}!".
Hasil Pengembalian
Objek PaymentRequest yang berisi:
recipient- Alamat dompet pedagangamount- Harga produk (disalin dariproduct.price)currency- Mata uang pembayaran (disalin dariproduct.currency)products- Array yang berisi satu produkmemo- Memo transaksi (opsi atau default: "Pembelian: (product.name)")label- Label pembayaran (opsi atau default: "product.name")message- Pesan sukses (opsi atau default: "Terima kasih telah membeli (product.name)!")
Contoh:
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()
Membuat permintaan pembayaran untuk beberapa produk dalam keranjang belanja.
function createCartRequest(recipient: string,products: any[],options?: {memo?: string;label?: string;message?: string;currency?: string;}): PaymentRequest;
Parameter
-
recipient(string, wajib) - Alamat dompet merchant yang akan menerima pembayaran. -
products(any[], wajib) - Array objek produk. -
options(objek, opsional) - Opsi kustomisasi:currency(string) - Mata uang pembayaran untuk seluruh keranjang.memo(string) - Memo on-chain. Default:"Cart purchase (products.length items)".label(string) - Label pembayaran. Default:"Cart Checkout".message(string) - Pesan sukses. Default:"Thank you for your purchase!".
Mengembalikan
Objek PaymentRequest dengan:
recipient- Alamat dompet merchantamount- Jumlah semua harga produk (products.reduce((sum, p) => sum + p.price, 0))currency- Mata uang pembayaran (dari opsi, atau undefined)products- Array produkmemo,label,message- Nilai opsi atau default
Contoh:
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()
Membuat permintaan pembayaran untuk tips atau donasi dengan jumlah yang ditentukan pengguna.
function createTipRequest(recipient: string,amount: number,options?: {currency?: string;memo?: string;label?: string;message?: string;}): PaymentRequest;
Parameter
-
recipient(string, wajib) - Alamat dompet penerima tip (kreator, streamer, badan amal, dll.). -
amount(number, wajib) - Jumlah tip. Satuan tergantung pada mata uang (lamport untuk SOL, unit minor untuk token). -
options(objek, opsional) - Opsi kustomisasi:currency(string) - Mata uang pembayaran. Default: undefined (biasanya dianggap sebagai SOL oleh konsumen).memo(string) - Memo on-chain. Default:"Thank you for your support!".label(string) - Label pembayaran. Default:"Tip".message(string) - Pesan sukses. Default:"Thanks for the tip!".
Mengembalikan
Objek PaymentRequest dengan:
recipient- Alamat dompet penerima tipamount- Jumlah tipcurrency- Mata uang pembayaran (dari opsi, atau undefined)memo,label,message- Nilai opsi atau default
Contoh:
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!"});
Fungsi Verifikasi Pembayaran
Fungsi-fungsi ini berinteraksi dengan Solana untuk memverifikasi transaksi dan
menunggu konfirmasi. Fungsi-fungsi ini memerlukan klien RPC Solana dari pustaka
gill.
verifyPayment()
Memverifikasi bahwa transaksi ada di on-chain dan secara opsional memvalidasi jumlah pembayaran, penerima, dan token.
async function verifyPayment(rpc: SolanaClient["rpc"],signatureString: string,expectedAmount?: number,expectedRecipient?: string,expectedMint?: string): Promise<PaymentVerificationResult>;
Parameter
-
rpc(SolanaClient['rpc'], wajib) - Klien RPC darigill. Buat dengancreateSolanaClient(rpcUrl).rpc. -
signatureString(string, wajib) - Tanda tangan transaksi (base58-encoded) yang akan diverifikasi. -
expectedAmount(number, opsional) - Jumlah pembayaran yang diharapkan untuk divalidasi. Satuan harus sesuai dengan mata uang:- Untuk SOL: lamport (1 SOL = 1.000.000.000 lamport)
- Untuk token SPL: unit minor berdasarkan desimal token (misalnya, USDC menggunakan 6 desimal)
Jika tidak diberikan, validasi jumlah akan dilewati.
-
expectedRecipient(string, opsional) - Alamat dompet penerima yang diharapkan. Jika diberikan (bersama denganexpectedAmount), fungsi akan memvalidasi bahwa penerima menerima setidaknya jumlah ini. Jika tidak diberikan, validasi akan dilewati. -
expectedMint(string, opsional) - Alamat mint token SPL. Hanya diperlukan untuk transfer token SPL. Jika tidak diberikan, fungsi akan mengasumsikan transfer SOL.
Nilai Kembalian
Objek 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}
Logika Verifikasi
Fungsi ini melakukan pemeriksaan berikut:
-
Validitas Tanda Tangan: Memeriksa bahwa tanda tangan valid.
-
Keberadaan Transaksi: Mengambil transaksi menggunakan
rpc.getTransaction(). Jika tidak ditemukan, mengembalikanverified: false. -
Status Konfirmasi: Memeriksa bahwa transaksi telah tercatat di on-chain.
-
Validasi Transfer SOL (jika
expectedRecipientdanexpectedAmountdiberikan, dan tidak adaexpectedMint):- Menemukan indeks akun penerima dalam transaksi
- Membandingkan
preBalancesdanpostBalancesuntuk menghitung delta saldo - Memverifikasi delta setidaknya
expectedAmount
-
Validasi Transfer Token SPL (jika
expectedMintdisediakan):- Menurunkan Associated Token Account (ATA) penerima untuk Token Program dan Token-2022 Program
- Memeriksa
postTokenBalancesuntuk ATA yang cocok dengan mint yang diharapkan - Memverifikasi jumlah token minimal
expectedAmount
Pertimbangan Keamanan
- Verifikasi Sisi Klien: Fungsi ini mengambil data transaksi dari RPC. Jangan ekspos URL RPC Anda ke klien.
- Finalisasi: Fungsi ini memeriksa transaksi yang dikonfirmasi, tetapi untuk
pembayaran bernilai tinggi, pertimbangkan untuk menunggu status
finalized.
Contoh:
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()
Melakukan polling blockchain hingga transaksi mencapai status confirmed atau finalized, atau timeout.
async function waitForConfirmation(rpc: SolanaClient["rpc"],signatureStr: string,timeoutMs?: number): Promise<boolean>;
Parameter
-
rpc(SolanaClient['rpc'], wajib) - Klien RPC darigill. -
signatureStr(string, wajib) - Signature transaksi yang ditunggu. -
timeoutMs(number, opsional) - Waktu maksimal untuk menunggu dalam milidetik. Default:30000(30 detik).
Nilai Kembali
Promise<boolean>- Mengembalikantruejika transaksi mencapaiconfirmedatau statusfinalizeddalam batas timeout,falsejika sebaliknya.
Contoh:
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");}
Fungsi Solana Pay
Fungsi-fungsi ini menghasilkan URL Solana Pay dan kode QR bergaya untuk pemindaian dompet seluler.
createSolanaPayRequest()
Membuat URL Solana Pay dan kode QR bergaya.
async function createSolanaPayRequest(request: TransferRequestURLFields,options: SolanaPayRequestOptions): Promise<{ url: URL; qr: string }>;
Parameter
-
request(TransferRequestURLFields, wajib) - Field permintaan transfer Solana Pay:recipient- Public key penerima (gunakancreateRecipient(address)dari@solana-commerce/solana-pay)amount- (opsional) Jumlah pembayaran dalam unit terkecil (lamport untuk SOL)splToken(opsional) - Public key mint token SPL (gunakancreateSPLToken(address))reference(opsional) - Public key referensi untuk pelacakanlabel(opsional) - Nama merchantmessage(opsional) - Pesan suksesmemo(opsional) - Memo on-chain
-
options(SolanaPayRequestOptions, wajib) - Opsi styling kode QR:size(angka) - Lebar/tinggi kode QR dalam piksel. Default:256.background(string) - Warna latar belakang (hex/rgb). Default:'white'.color(string) - Warna kode QR (hex/rgb). Default:'black'.margin(angka) - Margin di sekitar kode QR dalam modul.errorCorrectionLevel('L' | 'M' | 'Q' | 'H') - Tingkat koreksi kesalahan. Tingkat yang lebih tinggi memungkinkan lebih banyak kerusakan tetapi menghasilkan kode yang lebih padat.logo(string) - URL gambar logo untuk disematkan di tengah kode QR.logoSize(angka) - Ukuran logo sebagai persentase dari ukuran kode QR.logoBackgroundColor(string) - Warna latar belakang di belakang logo.logoMargin(angka) - Margin di sekitar logo.dotStyle('dots' | 'rounded' | 'square') - Bentuk modul kode QR.cornerStyle('square' | 'rounded' | 'extra-rounded' | 'full-rounded' | 'maximum-rounded') - Bentuk penanda sudut.
Nilai Kembali
Sebuah Promise yang menyelesaikan ke sebuah objek:
url(URL) - URL Solana Pay (misalnya,solana:recipient?amount=10&spl-token=...)qr(string) - Data URL kode QR yang dikodekan Base64 (gunakan sebagai<img src={qr} />)
Contoh:
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?