転送リクエストは、Solana Pay統合の最もシンプルな形式です。ウォレットがサーバーを必要とせずに直接トランザクションを構成して送信できる、非対話型の支払いURLを作成します。
概要
転送リクエストURLは次の形式に従います:
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
基本的なSOL転送
シンプルなSOL支払いリクエストを作成:
import { address } from "@solana/kit";import { encodeURL } from "@solana/pay";// Recipient's Solana wallet addressconst recipient = address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB");// Create the payment URLconst url = encodeURL({recipient,amount: 0.01, // 0.01 SOLlabel: "My Store",message: "Thanks for your purchase!"});console.log(url.toString());// Output: solana:FvJ8k8Hh...?amount=0.01&label=My%20Store&message=Thanks%20for%20your%20purchase!
SPLトークン転送
USDC支払いリクエストを作成:
import { address } from "@solana/kit";import { encodeURL } from "@solana/pay";// USDC mint address on mainnetconst usdcMint = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const url = encodeURL({recipient: address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB"),amount: 10.5, // $10.50 USDCsplToken: usdcMint,label: "Coffee Shop",message: "Grande Latte + Tip"});console.log(url.toString());
URLパラメータ
必須パラメータ
受信者
受信者のSolanaウォレットアドレス(base58エンコード):
const recipient = address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB");
オプションパラメータ
金額
ユーザーフレンドリーな単位での支払い金額(SOLまたはトークン単位):
// SOL amountsconst solAmount = 1.5; // 1.5 SOLconst smallAmount = 0.001; // 0.001 SOL// Token amounts (USDC example)const usdcAmount = 25.99; // $25.99 USDC
省略された場合、ウォレットはユーザーに金額の入力を求めます。
SPLトークン
トークン転送の場合、ミントアドレスを指定:
// Common SPL tokensconst USDC = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");const USDT = address("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");// Omit splToken for native SOL transfers
リファレンス
支払いを追跡するための一意の識別子。リファレンスキーとして使用するアドレスを生成します:
import { generateKeyPair, getAddressFromPublicKey } from "@solana/kit";// Generate a unique referenceconst keypair = await generateKeyPair();const reference = await getAddressFromPublicKey(keypair.publicKey);
ラベル
ユーザーに表示される販売者またはアプリ名:
const label = "Acme Coffee Shop";
メッセージ
支払いの説明:
const message = "Order #12345 - 2x Americano";
メモ
オンチェーンメモ(公開表示):
const memo = "OrderId:12345";
QRコード統合
組み込みのcreateQR関数を使用してQRコードを生成します:
import { address } from "@solana/kit";import { encodeURL, createQR } from "@solana/pay";const url = encodeURL({recipient: address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB"),amount: 0.05,label: "Donation",message: "Support our project"});// Generate a QR code elementconst qr = createQR(url);// Append to DOMconst element = document.getElementById("qr-code");qr.append(element);
支払い検証
マーチャントクライアントの使用
支払いを検索して検証する最も簡単な方法:
import { address } from "@solana/kit";import { createMerchantClient } from "@solana/pay";const merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});const recipient = address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB");const reference = address("YOUR_REFERENCE_ADDRESS");// Find the transaction by referenceconst found = await merchant.pay.findReference(reference);// Validate the transfer matches expected fieldsawait merchant.pay.validateTransfer(found.signature, {recipient,amount: 0.1});console.log("Payment confirmed!", found.signature);
スタンドアロン関数の使用
import { createSolanaRpc, address } from "@solana/kit";import { findReference, validateTransfer } from "@solana/pay";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const reference = address("YOUR_REFERENCE_ADDRESS");// Find transaction by referenceconst found = await findReference(rpc, reference);// Validate transaction detailsawait validateTransfer(rpc, found.signature, {recipient: address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB"),amount: 0.1});console.log("Payment confirmed!", found.signature);
支払いの監視(WebSocket)
推奨アプローチ —
watchReferenceはWebSocket経由でサブスクライブし、一致するトランザクションが到着するとすぐに解決されます。ポーリングは不要です。
async function waitForPayment(reference, recipient, amount) {const merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});// Resolves on the first transaction mentioning this referenceconst result = await merchant.pay.watchReference(reference);if (result.err) {throw new Error(`Transaction failed: ${JSON.stringify(result.err)}`);}// Validate that the transaction matches the expected paymentawait merchant.pay.validateTransfer(result.signature, { recipient, amount });return { signature: result.signature };}
支払いのポーリング(HTTPフォールバック)
WebSocketサブスクリプションが利用できない場合(一部のRPCプロバイダーなど)、findReferenceを使用したポーリングにフォールバックします:
async function pollForPayment(reference, recipient, amount) {const merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});const checkPayment = async () => {try {const found = await merchant.pay.findReference(reference);await merchant.pay.validateTransfer(found.signature, {recipient,amount});return { success: true, signature: found.signature };} catch {return { success: false };}};// Check every 2 secondsreturn new Promise((resolve) => {const interval = setInterval(async () => {const result = await checkPayment();if (result.success) {clearInterval(interval);resolve(result);}}, 2000);});}
完全な例
以下は、QRコード生成と支払い監視を含む完全な例です:
import { address, generateKeyPair, getAddressFromPublicKey } from "@solana/kit";import { encodeURL, createQR, createMerchantClient } from "@solana/pay";const recipient = address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB");const amount = 0.1;// Generate unique reference for this paymentconst keypair = await generateKeyPair();const reference = await getAddressFromPublicKey(keypair.publicKey);// Create payment URL and QR codeconst url = encodeURL({recipient,amount,reference,label: "Demo Store",message: "Test Purchase"});const qr = createQR(url);qr.append(document.getElementById("qr-code"));// Monitor for paymentconst merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});const interval = setInterval(async () => {try {const found = await merchant.pay.findReference(reference);await merchant.pay.validateTransfer(found.signature, {recipient,amount,reference});clearInterval(interval);console.log("Payment confirmed!", found.signature);} catch {// Payment not found yet, keep polling}}, 2000);
ベストプラクティス
セキュリティ
- 常にサーバー側で支払いを検証する
- 各支払いに一意の参照を使用する
- トランザクションの金額と受取人を確認する
- トランザクションの成功ステータスを確認する
ユーザーエクスペリエンス
- 明確な支払い金額と説明を表示する
- 支払いステータスの更新を提供する
- ウォレット接続を適切に処理する
- QRコードと直接リンクの両方をサポートする
エラー処理
- ウォレット接続の失敗を処理する
- サポートされていないウォレットのフォールバックを提供する
- 分かりやすいエラーメッセージを表示する
- 支払いタイムアウトを実装する
一般的なユースケース
販売時点管理
const posPayment = encodeURL({recipient: merchantWallet,amount: 15.99,label: "Local Coffee Shop",message: `Receipt #${receiptNumber}`,memo: `POS-${terminalId}-${Date.now()}`});
寄付
// Flexible donation amount (user enters amount in wallet)const donationUrl = encodeURL({recipient: charityWallet,label: "Save the Ocean",message: "Support marine conservation"});
Eコマースチェックアウト
const checkoutUrl = encodeURL({recipient: storeWallet,amount: cartTotal,reference: orderReference,label: storeName,message: `Order ${orderId}`,memo: `ORDER:${orderId}`});
Is this page helpful?