Настройка приймання платежів в Solana (SOL)
Специфіка Solana-платежів в тому, що тут нема нативного стандарту "платіжного запиту" рівня BIP-21 (Bitcoin) чи EIP-681 (Ethereum). Натомість є Solana Pay — відкритий протокол, розроблений Solana Labs спільно з екосистемою, що охоплює більшість payment use cases: прості SOL-переводи, SPL-токени, трансакційні запити з довільною логікою на бекенді.
Solana Pay: Transfer Request
Найпростіший сценарій — запит на передачу фіксованої суми SOL або SPL-токена. URL-схема:
solana:<recipient>?amount=<value>&label=<label>&message=<message>&memo=<memo>
Приклад для оплати 10 USDC:
solana:7Np41RSSZFkBmBUkVBntbRMzEnbZBqVkjFEf3BQnkGTi
?amount=10
&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
&label=MyShop
&message=Order%20%2312345
&memo=ORDER-12345
spl-token — mint address USDC на mainnet. memo — довільна рядок, записується в трансакцію on-chain через Memo program, використовується для reconciliation замовлень.
Цей URL кодується в QR-код. Гаманці з підтримкою Solana Pay (Phantom, Solflare, Backpack) автоматично розбирають його і показують деталі платежу.
Генерація QR на бекенді
import {
encodeURL,
createQR,
TransferRequestURLFields,
} from "@solana/pay";
import { PublicKey } from "@solana/web3.js";
import BigNumber from "bignumber.js";
function createPaymentRequest(orderId: string, amountUSDC: number) {
const recipient = new PublicKey("YOUR_MERCHANT_WALLET");
const splToken = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const urlFields: TransferRequestURLFields = {
recipient,
amount: new BigNumber(amountUSDC),
splToken,
label: "MyShop",
message: `Order #${orderId}`,
memo: orderId,
};
const url = encodeURL(urlFields);
const qrCode = createQR(url, 360, "transparent");
return { url: url.toString(), qrCode };
}
Верифікація платежу
Після показу QR потрібно підтвердити факт оплати. Solana Pay надає findReference — пошук трансакції по reference pubkey (унікальний ключ, додаваний в кожний платіж):
import { findReference, validateTransfer } from "@solana/pay";
import { Connection, clusterApiUrl, Keypair } from "@solana/web3.js";
const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
// reference — унікальний keypair для кожного замовлення
const reference = Keypair.generate().publicKey;
// Polling кожні 2 секунди
async function pollForPayment(reference: PublicKey, expectedAmount: BigNumber) {
while (true) {
try {
const signatureInfo = await findReference(connection, reference, {
finality: "confirmed",
});
await validateTransfer(connection, signatureInfo.signature, {
recipient: MERCHANT_WALLET,
amount: expectedAmount,
splToken: USDC_MINT,
reference,
});
return signatureInfo.signature; // платіж підтверджений
} catch (e) {
// FindReferenceError — трансакція ще не появилася, чекаємо
await new Promise((r) => setTimeout(r, 2000));
}
}
}
validateTransfer перевіряє: правильний recipient, правильна сума, правильний токен. Якщо що-то не совпадає — кидає исключение. Це захист від спроби оплатити "подібною" трансакцією.
Finality в Solana
Solana не має probabilistic finality як Bitcoin. Тут є рівні:
-
processed— трансакція включена в блок, можливий rollback при форку -
confirmed— блок отримав >66% голосів супербільшості -
finalized— блок в rooted частині ланцюга, rollback неможливий
Для платежів використовуйте confirmed — це баланс швидкості (~2–3 сек) і безпеки. finalized додає ще ~5–10 сек, оправдано лише для крупних сум.
Що потрібно для повноцінної реалізації
- Merchant wallet (краще hardware wallet або multisig через Squads Protocol)
- Endpoint створення платіжного запиту з унікальним reference
- WebSocket або polling для моніторингу підтвердження
- Збереження
signatureтрансакції в базі для аудиту - Обробка timeout (Solana Pay рекомендує 2 хв, після — показувати помилку)
- RPC endpoint: не публічний
api.mainnet-beta.solana.comдля production — він throttled; використовувати Helius, QuickNode або Alchemy







