Abstrakcja opłat

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:

  1. Jak działa sponsorowanie opłat — podstawowy mechanizm Solana
  2. 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.

Sponsor Transaction Fee
const sponsor = await generateKeyPairSigner();
const transferInstruction = getTransferCheckedInstruction({
source: senderAta,
mint: mint.address,
destination: recipientAta,
authority: sender, // Sender signs for the transfer
amount: 250_000n, // adjusted for the mint's decimals
decimals: 6
});

Wyślij z sponsorem jako płatnikiem opłat

Utwórz klienta z sponsorem ustawionym jako płatnik opłat za pomocą payer(sponsor), następnie wywołaj client.sendTransaction. Sponsor podpisuje w celu opłacenia opłaty sieciowej, podczas gdy nadawca podpisuje w celu autoryzacji transferu — sendTransaction automatycznie zbiera wszystkich wskazanych sygnatariuszy.

Sponsor Transaction Fee
const sponsor = await generateKeyPairSigner();
const transferInstruction = getTransferCheckedInstruction({
source: senderAta,
mint: mint.address,
destination: recipientAta,
authority: sender,
amount: 250_000n,
decimals: 6
});
const client = createClient()
.use(payer(sponsor)) // Sponsor pays the transaction fees
.use(solanaLocalRpc());
const { context } = await client.sendTransaction([transferInstruction]);

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.

Wyślij z sponsorem jako płatnikiem opłat

Utwórz klienta z sponsorem ustawionym jako płatnik opłat za pomocą payer(sponsor), następnie wywołaj client.sendTransaction. Sponsor podpisuje w celu opłacenia opłaty sieciowej, podczas gdy nadawca podpisuje w celu autoryzacji transferu — sendTransaction automatycznie zbiera wszystkich wskazanych sygnatariuszy.

Sponsor Transaction Fee
const sponsor = await generateKeyPairSigner();

Demo

Demo
// Generate keypairs for sender, recipient, and sponsor (fee payer)
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const sponsor = await generateKeyPairSigner();
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 tokens
const { client, mint } = await demoSetup(sender, recipient, sponsor);
console.log("\nMint Address:", mint.address);
// Derive the Associated Token Accounts addresses (ATAs) for sender and recipient
const [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 = getTransferCheckedInstruction({
source: senderAta,
mint: mint.address,
destination: recipientAta,
authority: sender, // Sender signs to authorize the transfer
amount: 250_000n, // 0.25 tokens
decimals: 6
});
// Send transaction with sponsor as fee payer using @solana/kit
// The sponsor (client.payer) pays fees; the sender signs for the transfer
const { context } = await client.sendTransaction([transferInstruction]);
const signature = context.signature;
console.log("\n=== Sponsored Token Payment Complete ===");
console.log("Transaction Signature:", signature.toString());
// Fetch final token account balances from the RPC
const senderBalance = await client.rpc.getTokenAccountBalance(senderAta).send();
const recipientBalance = await client.rpc
.getTokenAccountBalance(recipientAta)
.send();
console.log("\nSender Token Account Balance:", senderBalance.value.uiAmount);
console.log(
"Recipient Token Account Balance:",
recipientBalance.value.uiAmount
);
// Fetch transaction details
const transaction = await client.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
// =============================================================================
Console
Click to execute the code.

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 radzi sobie z tą złożonością. To serwer JSON-RPC, który zapewnia abstrakcję opłat, dzięki czemu użytkownicy nigdy nie potrzebują SOL. Możesz w pełni sponsorować opłaty lub akceptować płatności za opłaty w dowolnym tokenie.

Wdróż Korę jednym poleceniem:

cargo install kora-cli
kora --config path/to/kora.toml rpc start --signers-config path/to/signers.toml

Następnie skieruj klienta Kit na swój serwer Kora i wysyłaj transakcje przy użyciu tego samego API co powyżej:

pnpm add @solana/kora
import { address } from "@solana/kit";
import { createKitKoraClient } from "@solana/kora";
// A Kora-backed Kit client: Kora is the fee payer, and users pay
// fees in the SPL token of your choice instead of SOL
const kora = await createKitKoraClient({
endpoint: "https://your-kora-instance",
rpcUrl: "https://api.mainnet-beta.solana.com",
feeToken: address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), // USDC
feePayerWallet: sender // Signs to authorize the token fee payment
});
// Same instruction, same call—Kora sponsors the network fee
const { context } = await kora.sendTransaction([transferInstruction]);
console.log("Signature:", context.signature);

Materiały o Kora

Is this page helpful?

Spis treści

Edytuj stronę