Każda transakcja w sieci Solana wymaga SOL do opłacenia prowizji sieciowych. Jednak użytkownicy Twojej aplikacji płatniczej oczekują, że będą dokonywać transakcji w stablecoinach — bez konieczności zarządzania saldem drugiego tokena. Abstrakcja opłat eliminuje tę barierę, pozwalając, by ktoś inny pokrył opłaty.
Ten przewodnik obejmuje dwa poziomy:
- Jak działa sponsorowanie opłat — podstawowy mechanizm Solana
- Abstrakcja opłat na dużą skalę z Kora — gotowa do wdrożenia usługa abstrakcji opłat
Jak działa sponsorowanie opłat
Transakcje Solana mają wyznaczonego płatnika opłat — konto, które pokrywa prowizję sieciową. Domyślnie jest to pierwszy sygnatariusz. Możesz jednak wskazać inne konto jako płatnika opłat, co pozwala osobie trzeciej ("sponsorowi") pokryć opłaty w imieniu nadawcy.
Zarówno nadawca, jak i sponsor muszą podpisać transakcję:
- Nadawca podpisuje, aby autoryzować transfer swoich tokenów
- Sponsor podpisuje, aby autoryzować opłacenie prowizji sieciowej
Zobacz Jak działają płatności w Solana, aby poznać podstawowe pojęcia dotyczące płatności.
Poniższe kroki pokazują podstawowy przebieg. Pełny, gotowy do uruchomienia kod znajdziesz w sekcji Demo.
Utwórz konto sponsora
Wygeneruj osobny keypair dla sponsora, który będzie opłacał prowizje transakcyjne. Sponsor potrzebuje SOL na opłaty, ale nie musi posiadać tokenów, które są przesyłane.
Utwórz instrukcję transferu
Utwórz instrukcję transferu tokenów z nadawcą jako autoryzującym. Nadawca jest właścicielem tokenów i musi podpisać transfer.
const sponsor = (await generateKeypair()).signer;const transferInstruction = getTransferInstruction({source: senderAta,destination: recipientAta,authority: sender, // Sender signs for the transferamount: 250_000n // adjusted for the mint's decimals});
Wyślij z sponsorem jako płatnikiem opłat
Użyj prepareAndSend zarówno z authority (nadawcą, który podpisuje transfer),
jak i feePayer (sponsorem, który opłaca prowizje). Obie strony muszą podpisać
transakcję.
const sponsor = (await generateKeypair()).signer;const transferInstruction = getTransferInstruction({source: senderAta,destination: recipientAta,authority: sender,amount: 250_000n});const signature = await client.transaction.prepareAndSend({authority: sender, // Signs the transfer instructionfeePayer: sponsor, // Pays the transaction feesinstructions: [transferInstruction],version: 0});
Demo
// Generate keypairs for sender, recipient, and sponsor (fee payer)const sender = (await generateKeypair()).signer;const recipient = (await generateKeypair()).signer;const sponsor = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Recipient Address:", recipient.address);console.log("Sponsor Address (Fee Payer):", sponsor.address);// Demo Setup: Create client, mint account, token accounts, and fund with initial tokensconst { client, mint } = await demoSetup(sender, recipient, sponsor);console.log("\nMint Address:", mint.address);// Derive the Associated Token Accounts addresses (ATAs) for sender and recipientconst [senderAta] = await findAssociatedTokenPda({mint: mint.address,owner: sender.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});const [recipientAta] = await findAssociatedTokenPda({mint: mint.address,owner: recipient.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});console.log("Sender Token Account:", senderAta.toString());console.log("Recipient Token Account:", recipientAta.toString());// =============================================================================// Sponsored Token Payment Demo// =============================================================================// Create instruction to transfer tokens from sender to recipient// Transferring 250,000 base units = 0.25 tokens (with 6 decimals)const transferInstruction = getTransferInstruction({source: senderAta,destination: recipientAta,authority: sender, // Pass signer, not just addressamount: 250_000n // 0.25 tokens});// Prepare and send transaction with sponsor as fee payer using @solana/client// The sponsor pays transaction fees, sender signs for the transferconst signature = await client.transaction.prepareAndSend({authority: sender, // Sender signs the transfer instructionfeePayer: sponsor, // Sponsor pays the transaction fees (different account)instructions: [transferInstruction],version: 0});console.log("\n=== Sponsored Token Payment Complete ===");console.log("Transaction Signature:", signature.toString());// Fetch final token account balances using @solana/client SPL token helperconst splToken = client.splToken({mint: mint.address,tokenProgram: "auto"});const senderBalance = await splToken.fetchBalance(sender.address);const recipientBalance = await splToken.fetchBalance(recipient.address);console.log("\nSender Token Account Balance:", senderBalance);console.log("Recipient Token Account Balance:", recipientBalance);// Fetch transaction detailsconst transaction = await client.runtime.rpc.getTransaction(signature, {encoding: "jsonParsed",maxSupportedTransactionVersion: 0}).send();const feePayer = transaction?.transaction.message.accountKeys?.[0];console.log("\nNote: The first account in accountKeys is always the fee payer");console.log("Fee Payer Address:", feePayer);// =============================================================================// Demo Setup Helper Function// =============================================================================
Gdy tworzysz token account dla użytkownika końcowego, może on zamknąć to konto i odzyskać SOL użyte na rent. Rozważ pobieranie opłaty za utworzenie konta w stablecoinach lub uwzględnij ten koszt w ekonomii swojego produktu.
Abstrakcja opłat na dużą skalę z Kora
Prymityw płatnika opłat jest potężny, ale zbudowanie produkcyjnego systemu bezgazowego wymaga więcej: zarządzania portfelami sponsorów, obsługi konwersji tokenów (aby użytkownicy mogli "płacić" opłaty w USDC), limitowania transakcji i kontroli bezpieczeństwa.
Kora upraszcza tę złożoność. To serwer JSON-RPC, który zapewnia abstrakcję opłat, dzięki czemu użytkownicy nie potrzebują SOL. Możesz całkowicie sponsorować opłaty lub akceptować płatności opłat w dowolnym tokenie.
Wdróż Korę jednym poleceniem:
cargo install kora-clikora --config path/to/kora.toml rpc start --signers-config path/to/signers.toml
Następnie użyj klienta Kora do podpisywania i wysyłania transakcji:
pnpm add @solana/kora
import { KoraClient } from "@solana/kora";const kora = new KoraClient({ rpcUrl: "https://your-kora-instance" });const { signature } = await kora.signAndSendTransaction({transaction: base64EncodedTransaction});
Materiały o Kora
Is this page helpful?