Yêu cầu Giao dịch

Yêu cầu giao dịch cho phép các luồng thanh toán tương tác bằng cách cho phép ví giao tiếp với máy chủ của bạn để soạn bất kỳ giao dịch Solana nào. Điều này mở khóa các trường hợp sử dụng nâng cao như đúc NFT, định giá động, giao dịch DeFi đa bước và logic nghiệp vụ tùy chỉnh.

Tổng quan

Yêu cầu giao dịch tuân theo định dạng URL này:

solana:<server-endpoint-url>

Ví thực hiện hai yêu cầu HTTP đến điểm cuối của bạn:

  1. Yêu cầu GET - Lấy thông tin thanh toán (nhãn, biểu tượng)
  2. Yêu cầu POST - Lấy giao dịch để ký

Thiết lập Cơ bản

1. Cài đặt Phụ thuộc

pnpm add @solana/pay@beta @solana/kit @solana-program/system \
@solana/kit-plugin-rpc @solana/kit-plugin-payer @solana/kit-plugin-instruction-plan

2. Tạo Điểm cuối API

Thiết lập một điểm cuối API xử lý cả yêu cầu GET và POST:

// pages/api/pay.ts (Next.js) or similar endpoint
import { address, createNoopSigner, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import { createMerchantClient } from "@solana/pay";
const MERCHANT_WALLET = address(process.env.MERCHANT_WALLET);
export default async function handler(req, res) {
if (req.method === "GET") {
return handleGet(req, res);
}
if (req.method === "POST") {
return handlePost(req, res);
}
return res.status(405).json({ error: "Method not allowed" });
}
// GET request handler
async function handleGet(req, res) {
const label = "My Store";
const icon = "https://mystore.com/icon.png";
res.status(200).json({
label,
icon
});
}
// POST request handler
async function handlePost(req, res) {
try {
const { account } = req.body;
if (!account) {
return res.status(400).json({ error: "Missing account parameter" });
}
const buyerAddress = address(account);
// Create the merchant client for building the transaction
const merchant = createMerchantClient({
rpcUrl: process.env.SOLANA_RPC_URL
});
// Build transfer instruction (createNoopSigner because the wallet signs later)
const instruction = getTransferSolInstruction({
source: createNoopSigner(buyerAddress),
destination: MERCHANT_WALLET,
amount: lamports(100_000_000n) // 0.1 SOL
});
// Build a base64-encoded transaction
const transaction = merchant.pay.buildTransaction(buyerAddress, [
instruction
]);
res.status(200).json({
transaction,
message: "Thanks for your purchase!"
});
} catch (error) {
console.error("Transaction creation error:", error);
res.status(500).json({ error: "Failed to create transaction" });
}
}

3. Tạo URL Thanh toán

Tạo URL yêu cầu giao dịch:

import { encodeURL } from "@solana/pay";
// Your API endpoint
const apiUrl = "https://yoursite.com/api/pay";
// Create transaction request URL
const url = encodeURL({
link: new URL(apiUrl)
});
console.log(url.toString());
// Output: solana:https://yoursite.com/api/pay

Phía Ví: Lấy Yêu cầu Giao dịch

Ở phía ví, sử dụng fetchTransaction để lấy và ký giao dịch từ URL yêu cầu giao dịch:

import { createWalletClient } from "@solana/pay";
const wallet = createWalletClient({
rpcUrl: "https://api.mainnet-beta.solana.com",
payer: myWalletSigner
});
// Parse the Solana Pay URL
const parsed = wallet.pay.parseURL(url);
if ("link" in parsed) {
// This is a transaction request — fetch the transaction from the server
const transaction = await wallet.pay.fetchTransaction(
myWalletSigner.address,
parsed.link
);
// Sign and send the transaction...
}

Ví dụ Nâng cao

Thanh toán Token SPL

Tạo giao dịch thanh toán USDC:

import { address } from "@solana/kit";
import {
fetchMint,
findAssociatedTokenPda,
getTransferCheckedInstruction,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
async function createTokenPaymentInstruction(rpc, buyer, amount) {
const USDC_MINT = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
// Get mint info for decimals
const mint = await fetchMint(rpc, USDC_MINT);
// Derive associated token accounts
const [buyerATA] = await findAssociatedTokenPda({
owner: buyer,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
mint: USDC_MINT
});
const [merchantATA] = await findAssociatedTokenPda({
owner: MERCHANT_WALLET,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
mint: USDC_MINT
});
// Calculate token amount with decimals
const tokenAmount = BigInt(Math.round(amount * 10 ** mint.data.decimals));
return getTransferCheckedInstruction({
source: buyerATA,
mint: USDC_MINT,
destination: merchantATA,
authority: buyer,
amount: tokenAmount,
decimals: mint.data.decimals
});
}

Định giá Động với Giảm giá

Triển khai định giá động dựa trên dữ liệu khách hàng:

async function handlePost(req, res) {
const { account } = req.body;
const buyer = address(account);
// Check if customer holds discount NFT
const hasDiscountNFT = await checkForDiscountNFT(buyer);
// Calculate dynamic price
let price = 10; // $10 base price
if (hasDiscountNFT) {
price = price * 0.8; // 20% discount
}
const merchant = createMerchantClient({
rpcUrl: process.env.SOLANA_RPC_URL
});
const instruction = await createTokenPaymentInstruction(
merchant.rpc,
buyer,
price
);
const transaction = merchant.pay.buildTransaction(buyer, [instruction]);
const message = hasDiscountNFT
? `20% discount applied! Total: $${price.toFixed(2)}`
: `Total: $${price.toFixed(2)}`;
res.status(200).json({ transaction, message });
}

Tích hợp Quản lý Đơn hàng

Tích hợp với hệ thống đơn hàng hiện có của bạn:

import { address, AccountRole, createNoopSigner, lamports } from "@solana/kit";
// Enhanced POST handler with order management
async function handlePost(req, res) {
const { account } = req.body;
const { orderId } = req.query;
if (!orderId) {
return res.status(400).json({ error: "Missing order ID" });
}
// Get order details
const order = await db.orders.findById(orderId);
if (!order || order.status !== "pending") {
return res.status(400).json({ error: "Invalid order" });
}
const buyer = address(account);
// Create payment instruction (createNoopSigner because the wallet signs later)
const instruction = getTransferSolInstruction({
source: createNoopSigner(buyer),
destination: MERCHANT_WALLET,
amount: lamports(BigInt(Math.round(order.total * 1e9)))
});
// Add reference for tracking (accounts is readonly, so spread into a new instruction)
const withRef = {
...instruction,
accounts: [
...(instruction.accounts ?? []),
{
address: address(order.referenceKey),
role: AccountRole.READONLY
}
]
};
const merchant = createMerchantClient({ rpcUrl: process.env.SOLANA_RPC_URL });
const transaction = merchant.pay.buildTransaction(buyer, [withRef]);
// Update order status
await db.orders.update(orderId, {
status: "processing",
walletAddress: account
});
res.status(200).json({
transaction,
message: `Order ${order.id} - ${order.items.length} items`
});
}

Xác thực Thanh toán

Xác thực các giao dịch đã hoàn thành:

import { address } from "@solana/kit";
import { createMerchantClient } from "@solana/pay";
const merchant = createMerchantClient({
rpcUrl: "https://api.mainnet-beta.solana.com"
});
async function validatePayment(reference, recipient, amount) {
try {
const found = await merchant.pay.findReference(reference);
// findReference only locates a signature mentioning the reference address.
// validateTransfer checks recipient, amount, and token match.
await merchant.pay.validateTransfer(found.signature, {
recipient,
amount,
reference
});
return {
success: true,
signature: found.signature
};
} catch (error) {
console.error("Payment validation error:", error);
}
return { success: false };
}

Xử lý Lỗi

Triển khai xử lý lỗi mạnh mẽ:

async function handlePost(req, res) {
try {
const { account } = req.body;
if (!account) {
return res.status(400).json({
error: "Missing account parameter",
code: "MISSING_ACCOUNT"
});
}
let buyer;
try {
buyer = address(account);
} catch {
return res.status(400).json({
error: "Invalid account address",
code: "INVALID_ACCOUNT"
});
}
const instruction = getTransferSolInstruction({
source: createNoopSigner(buyer),
destination: MERCHANT_WALLET,
amount: lamports(100_000_000n)
});
const merchant = createMerchantClient({
rpcUrl: process.env.SOLANA_RPC_URL
});
const transaction = merchant.pay.buildTransaction(buyer, [instruction]);
res.status(200).json({
transaction,
message: "Payment ready"
});
} catch (error) {
console.error("Transaction request error:", error);
res.status(500).json({
error: "Internal server error",
code: "INTERNAL_ERROR"
});
}
}

Thực hành Tốt nhất

Bảo mật

  • Xác thực tất cả các tham số đầu vào
  • Chỉ tính toán số tiền ở phía máy chủ
  • Sử dụng HTTPS cho tất cả các endpoint
  • Triển khai giới hạn tốc độ yêu cầu
  • Lưu trữ dữ liệu nhạy cảm một cách an toàn

Hiệu suất

  • Lưu cache dữ liệu thường xuyên truy cập
  • Sử dụng connection pooling
  • Triển khai timeout cho request
  • Cân nhắc sử dụng webhook để xác nhận thanh toán

Trải nghiệm Người dùng

  • Cung cấp thông báo lỗi rõ ràng
  • Hiển thị tiến trình giao dịch
  • Xử lý vấn đề mạng một cách mượt mà
  • Hỗ trợ thử lại giao dịch

Is this page helpful?

Quản lý bởi

© 2026 Solana Foundation.
Đã đăng ký bản quyền.
Kết nối