Programy Tokenów Solana obsługują delegowanie — czyli przyznawanie innemu kontu uprawnienia do transferu tokenów z Twojego token account do określonego limitu. Pozwala to na realizację takich scenariuszy jak automatyczne płatności, usługi escrow czy przetwarzanie płatności przez strony trzecie, bez utraty kontroli nad własnymi środkami.
Jak działa delegowanie
Gdy zatwierdzasz delegata, upoważniasz konkretne konto do transferowania tokenów w Twoim imieniu:
- Właściciel zachowuje kontrolę: Nadal jesteś właścicielem tokenów i możesz w każdej chwili dokonać transferu lub odwołać uprawnienia
- Limit wydatków: Delegat może przelać tylko zatwierdzoną kwotę
- Jeden delegat na konto: Każdy token account może mieć tylko jednego aktywnego delegata
- Nowe zatwierdzenie zastępuje stare: Zatwierdzenie nowego delegata automatycznie cofa poprzednie uprawnienie
Delegowanie jest niepowiernicze. Delegat może wydawać tokeny tylko do ustalonego limitu, ale nie ma dostępu do środków poza zatwierdzoną kwotą. Właściciel może w każdej chwili cofnąć uprawnienia.
Przykłady zastosowań biznesowych
| Zastosowanie | Jak pomaga delegowanie |
|---|---|
| Procesory płatności | Sprzedawca przyznaje procesorowi uprawnienia do rozliczania transakcji |
| Automatyczna wypłata pensji | Skarbnik zatwierdza usługę kadrową do wypłaty wynagrodzeń |
| Usługi escrow | Kupujący deleguje agentowi escrow warunkowe zwolnienie środków |
| Platformy tradingowe | Użytkownik zatwierdza giełdę do realizacji transakcji w jego imieniu |
| Wydawanie kart | Użytkownik zatwierdza wystawcę karty do obciążania jego token account |
Zatwierdzanie delegata
Przyznaj innemu kontu uprawnienia do wydawania tokenów z Twojego konta:
import { getApproveCheckedInstruction } from "@solana-program/token";// Approve delegate to spend up to 1,000 USDC (6 decimals)const approveInstruction = getApproveCheckedInstruction({source: tokenAccountAddress, // Your token accountmint: usdcMintAddress, // USDC mintdelegate: delegateAddress, // Account receiving permissionowner: ownerKeypair, // You (must sign)amount: 1_000_000_000n, // 1,000 USDC in base unitsdecimals: 6});
Parametry:
source: token account przyznający uprawnieniadelegate: konto, które otrzyma uprawnienia do wydawaniaowner: obecny właściciel token account (musi podpisać transakcję)amount: maksymalna liczba tokenów, jaką delegat może przelaćdecimals: liczba miejsc po przecinku tokena do walidacji (zapobiega błędom dziesiętnym)
Demo
// Generate keypairs for sender and delegateconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);// Demo Setup: Create client, mint account, token account, and fund with initial tokensconst { client, mint, senderAta } = await demoSetup(sender);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);// =============================================================================// Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst signature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Approve Delegate ===");console.log("Transaction Signature:", signature);// Fetch token account data to show delegate is setconst tokenData = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenData.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Odwołanie delegata
Usuń wszystkie uprawnienia do wydawania środków obecnemu delegatowi:
import { getRevokeInstruction } from "@solana-program/token";const revokeInstruction = getRevokeInstruction({source: tokenAccountAddress, // Your token accountowner: ownerKeypair // You (must sign)});
Odwołanie usuwa wszystkie uprawnienia delegata — nie ma częściowego odwołania. Jeśli chcesz zmniejszyć limit, zatwierdź tego samego delegata z niższą kwotą.
Demo
// Generate keypairs for sender and delegateconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);// Demo Setup: Create client, mint account, token account, and fund with initial tokensconst { client, mint, senderAta } = await demoSetup(sender);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);// =============================================================================// Transaction 1: Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst approveSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Transaction 1: Approve Delegate ===");console.log("Transaction Signature:", approveSignature);// Fetch token account data to show delegate is setconst tokenDataAfterApprove = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenDataAfterApprove.data);// =============================================================================// Transaction 2: Revoke Delegate// =============================================================================// Create instruction to revoke delegateconst revokeInstruction = getRevokeInstruction({source: senderAta,owner: sender});// Send revoke transactionconst revokeSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [revokeInstruction]});console.log("\n=== Transaction 2: Revoke Delegate ===");console.log("Transaction Signature:", revokeSignature);// Fetch token account data to show delegate is revokedconst tokenDataAfterRevoke = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenDataAfterRevoke.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Przelew jako delegat
Działając jako delegat, użyj standardowego przelewu, ale podpisz go keypair delegata zamiast właściciela:
import { getTransferCheckedInstruction } from "@solana-program/token";const transferInstruction = getTransferCheckedInstruction({source: ownerTokenAccount, // The account you have permission to spend frommint: usdcMintAddress,destination: recipientTokenAccount,authority: delegateKeypair, // You (the delegate) sign, not the owneramount: 100_000_000n, // 100 USDCdecimals: 6});
Przelew zakończy się powodzeniem, jeśli:
- Konto źródłowe ma wystarczające saldo
- Delegat podpisze transakcję
Każdy przelew zmniejsza pozostały limit. Gdy limit osiągnie zero, delegat nie może już wykonywać przelewów tokenów.
Demo
// Generate keypairs for sender, delegate, and recipientconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;const recipient = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);console.log("Recipient Address:", recipient.address);// Demo Setup: Create client, mint account, token accounts, and fund with initial tokensconst { client, mint, senderAta, recipientAta } = await demoSetup(sender,delegate,recipient);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);console.log("Recipient ATA:", recipientAta);// =============================================================================// Transaction 1: Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst approveSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Transaction 1: Approve Delegate ===");console.log("Delegate Address:", delegate.address);console.log("Transaction Signature:", approveSignature);// =============================================================================// Fetch Token Account Data to Demonstrate Delegate is Set// =============================================================================const tokenAccountData = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenAccountData.data);// =============================================================================// Transaction 2: Transfer Using Delegate// =============================================================================// Create instruction to transfer tokens using delegate// Note: delegate is the authority here, not the ownerconst transferInstruction = getTransferCheckedInstruction({source: senderAta,mint: mint.address,destination: recipientAta,authority: delegate, // Delegate signs this transactionamount: 500_000n, // 0.5 tokens with 6 decimalsdecimals: 6});// Send transfer transaction// Delegate pays for the transaction and authorizes the transfer (sender not needed)const transferSignature = await client.transaction.prepareAndSend({authority: delegate, // Delegate pays fee and signsinstructions: [transferInstruction]});// =============================================================================// Fetch Final Token Account Balances// =============================================================================const finalSenderToken = await fetchToken(client.runtime.rpc, senderAta);const finalRecipientToken = await fetchToken(client.runtime.rpc, recipientAta);console.log("\n=== Transaction 2: Transfer Using Delegate ===");console.log("Transaction Signature:", transferSignature);console.log("\nSender Token Account Data:", finalSenderToken.data);console.log("\nRecipient Token Account Data:", finalRecipientToken.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Sprawdzanie statusu delegacji
Sprawdź token account, aby zobaczyć obecnego delegata i pozostały limit:
import { fetchToken } from "@solana-program/token";const tokenAccount = await fetchToken(rpc, tokenAccountAddress);if (tokenAccount.data.delegate) {console.log("Delegate:", tokenAccount.data.delegate);console.log("Remaining allowance:", tokenAccount.data.delegatedAmount);} else {console.log("No delegate set");}
Demo
// Demo Setup: Create client, mint, two token accounts (one with delegate, one without)const { client, ataWithDelegate, ataWithoutDelegate } = await demoSetup();// =============================================================================// Fetch Token Accounts// =============================================================================// Fetch token account with delegateconst tokenWithDelegate = await fetchToken(client.runtime.rpc, ataWithDelegate);console.log("Token Account with Delegate:", tokenWithDelegate);// Fetch token account without delegateconst tokenWithoutDelegate = await fetchToken(client.runtime.rpc,ataWithoutDelegate);console.log("\nToken Account without Delegate:", tokenWithoutDelegate);// =============================================================================// Demo Setup Helper Function// =============================================================================
Wskazówki dotyczące bezpieczeństwa
Dla właścicieli kont:
- Zatwierdzaj tylko zaufanych delegatów
- Ustaw minimalny niezbędny limit wydatków
- Cofnij delegacje, gdy nie są już potrzebne
- Monitoruj swoje konta pod kątem nieoczekiwanych transferów
Dla dostawców usług (delegatów):
- Jasno komunikuj użytkownikom żądany limit wydatków
- Wdrażaj odpowiednie zarządzanie kluczami dla swojego konta delegata
- Monitoruj wykorzystanie limitu, aby poprosić o ponowną akceptację zanim limit się wyczerpie
Delegacja a powiernictwo
| Aspekt | Delegacja | Pełne powiernictwo |
|---|---|---|
| Własność tokena | Użytkownik zachowuje | Użytkownik przekazuje powiernikowi |
| Kontrola wydatków | Ograniczona do zatwierdzonej kwoty | Pełny dostęp do przekazanych środków |
| Odwołanie | Natychmiastowe, przez właściciela | Wymaga współpracy powiernika |
| Ekspozycja na ryzyko | Ograniczona do zatwierdzonej kwoty | Całe saldo |
| Wymagane zaufanie | Ograniczone | Wysokie |
Delegacja to rozwiązanie pośrednie — umożliwia automatyczne płatności, jednocześnie ograniczając ekspozycję na ryzyko do zatwierdzonej kwoty.
Powiązane zasoby
| Zasób | Opis |
|---|---|
| Zatwierdź delegata | Jak przyznać innemu kontu uprawnienia do wydawania z twojego token account. |
| Cofnij delegata | Jak usunąć istniejącego delegata i cofnąć jego uprawnienia do wydawania. |
| Przelej token | Jak przelać tokeny między token account. |
Is this page helpful?