交易請求
交易請求通過啟用動態、由伺服器組成的交易,解鎖了 Solana Pay 的全部功能,能夠處理任何類型的 Solana 操作。
與包含所有支付信息於 URL 中的轉賬請求不同,交易請求使用互動式端點,根據實時數據和業務邏輯構建自定義交易。
這種方法將 Solana Pay 從一個簡單的支付系統轉變為一個完整的商業平台,能夠處理複雜的業務場景、動態定價和高級交易流程。
交易請求的運作方式
交易請求遵循一個簡單的 URL 格式,指向您的伺服器端點:
solana:<link>link 的值應該是指向您的 API 端點的 URL,該端點處理 GET 和 POST 請求。當用戶掃描交易請求的 QR 碼時,他們的錢包會啟動一個四步驟的過程:
初始 GET 請求:檢索顯示信息,例如您的商業名稱和標誌
用戶確認:錢包向用戶顯示商業信息
POST 請求:將用戶的公鑰發送到您的端點
交易回應:您的伺服器構建一個自定義交易並以 base64 編碼字符串的形式返回
然後錢包向用戶展示此交易以供批准和簽署。
solana:https://myapi.com/pay?amount=100&product=premium&reference=abc123構建 API 端點
創建交易請求端點需要在同一 URL 上處理 GET 和 POST 請求。以下是使用 Next.js App Router 的結構:
import { NextRequest, NextResponse } from 'next/server';
// CORS headers for wallet compatibility
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: corsHeaders });
}
export async function GET() {
// Implementation details below...
}
export async function POST(request: NextRequest) {
// Implementation details below...
}GET 請求處理器
GET 請求提供顯示資訊,幫助用戶了解他們正在互動的內容:
export async function GET() {
return NextResponse.json({
label: "Coffee Shop Demo",
icon: "https://solana.com/src/img/branding/solanaLogoMark.svg",
}, { headers: corsHeaders });
}回應格式:
{
"label": "Coffee Shop Demo",
"icon": "https://solana.com/src/img/branding/solanaLogoMark.svg"
}這些資訊幫助用戶在進行實際交易組成之前了解他們即將互動的內容。
POST 請求處理器
POST 請求是交易請求真正發揮作用的地方。您的端點接收用戶的公鑰並構建完全自定義的交易:
export async function POST(request: NextRequest) {
// Parse user's public key from request body
const body = await request.json();
const { account } = body;
// Connect to Solana network
const connection = new Connection(clusterApiUrl("devnet"));
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
// Create transaction with user as fee payer
const transaction = new Transaction({
feePayer: new PublicKey(account),
blockhash: blockhash,
lastValidBlockHeight: lastValidBlockHeight,
});
// ========================================
// ADD YOUR CUSTOM INSTRUCTIONS HERE
// ========================================
// This is where you build your transaction logic.
// You can add any combination of instructions:
// Example 1: Simple SOL transfer
// const transferInstruction = SystemProgram.transfer({
// fromPubkey: new PublicKey(account),
// toPubkey: new PublicKey("YOUR_MERCHANT_WALLET"),
// lamports: LAMPORTS_PER_SOL * 0.01, // 0.01 SOL
// });
// transaction.add(transferInstruction);
// Serialize the transaction for the wallet
const serializedTransaction = transaction.serialize({
requireAllSignatures: false,
verifySignatures: false,
});
return NextResponse.json({
transaction: serializedTransaction.toString('base64'),
message: "Transaction created successfully", // Customize this message
}, { headers: corsHeaders });
}進階功能
受限交易
交易請求通過在構建交易之前驗證條件來實現複雜的訪問控制。由於您控制端點,您可以檢查 NFT 擁有權、白名單成員資格或任何其他條件:
// Check NFT ownership before building transaction
const nfts = await metaplex.nfts().findAllByOwner({ owner: account }).run();
const hasRequiredNFT = nfts.some(nft =>
nft.collection?.address.toString() === requiredCollection
);
if (!hasRequiredNFT) {
return response.status(403).json({
error: "Access denied: Required NFT not found"
});
}
// Build transaction only for verified users部分簽名以增強安全性
對於需要管理員密鑰對或多方身份驗證批准的交易,Solana Pay 支援部分簽名。您的伺服器可以在發送給用戶之前添加其簽名:
const transaction = new Transaction({
feePayer: account,
blockhash,
lastValidBlockHeight,
});
// Add your instructions requiring admin signature
transaction.add(customInstruction);
// Partially sign with your admin keypair
transaction.partialSign(adminKeypair);
// Send to user for final signature
const serializedTransaction = transaction.serialize({
requireAllSignatures: false,
});範例
作為完整的範例,您可以使用 Solana Foundation 提供的 Solana NFT Minter 範例。