Os programas de tokens da Solana suportam delegação—conceder a outra conta permissão para transferir tokens da sua conta de tokens até um limite especificado. Isso permite casos de uso como pagamentos automatizados, serviços de custódia e processamento de pagamentos por terceiros sem abrir mão da custódia dos seus fundos.
Como funciona a delegação
Quando você aprova um delegado, está a autorizar uma conta específica a transferir tokens em seu nome:
- O proprietário mantém a custódia: Você ainda é dono dos tokens e pode transferir ou revogar a qualquer momento
- Gasto limitado: O delegado só pode transferir até o valor aprovado
- Um único delegado por conta: Cada conta de tokens só pode ter um delegado ativo
- Nova aprovação substitui a antiga: Aprovar um novo delegado revoga automaticamente o anterior
A delegação é não custodial. O delegado pode gastar tokens até o limite, mas não pode aceder ou drenar a conta além do valor aprovado. O proprietário pode revogar a qualquer momento.
Casos de uso empresariais
| Caso de uso | Como a delegação ajuda |
|---|---|
| Processadores de pagamento | O comerciante concede permissão ao processador para liquidar transações |
| Folha de pagamento automática | A tesouraria aprova o serviço de folha de pagamento para desembolsar salários |
| Serviços de custódia | O comprador delega ao agente de custódia para liberação condicional |
| Plataformas de negociação | O utilizador aprova a exchange para executar negociações em seu nome |
| Emissão de cartões | O utilizador aprova o emissor do cartão para debitar compras na sua conta de tokens |
Aprovar um delegado
Conceder permissão a outra conta para gastar tokens da sua conta:
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});
Parâmetros:
source: A token account que concede a permissãodelegate: A conta que terá permissão de gastoowner: Proprietário atual da token account (deve assinar a transação)amount: Quantidade máxima de tokens que o delegado pode transferirdecimals: Decimais do token para validação (previne erros de casas decimais)
Demonstração
// 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// =============================================================================
Revogar um delegado
Remover todas as permissões de gasto do delegado atual:
import { getRevokeInstruction } from "@solana-program/token";const revokeInstruction = getRevokeInstruction({source: tokenAccountAddress, // Your token accountowner: ownerKeypair // You (must sign)});
Revogar remove todas as permissões do delegado—não há revogação parcial. Se precisar reduzir o limite, aprove o mesmo delegado com um valor menor.
Demonstração
// 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// =============================================================================
Transferir como delegado
Ao atuar como delegado, use uma transferência padrão mas assine com o keypair do delegado em vez do proprietário:
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});
A transferência será bem-sucedida se:
- A conta de origem tiver saldo suficiente
- O delegado assinar a transação
Cada transferência reduz o limite restante. Quando o limite chega a zero, o delegado não pode mais transferir tokens.
Demonstração
// 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// =============================================================================
Verificar o estado da delegação
Consultar uma token account para ver o seu delegado atual e o limite restante:
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// =============================================================================
Considerações de segurança
Para proprietários de contas:
- Aprove apenas delegados de confiança
- Defina o limite de gastos mínimo necessário
- Revogue delegações quando já não forem necessárias
- Monitorize as suas contas para transferências inesperadas
Para fornecedores de serviços (delegados):
- Comunique claramente o limite de gastos solicitado aos utilizadores
- Implemente uma gestão adequada de chaves para a sua conta de delegado
- Acompanhe o consumo de permissões para solicitar nova aprovação antes que os limites se esgotem
Delegação vs. custódia
| Aspeto | Delegação | Custódia total |
|---|---|---|
| Propriedade dos tokens | O utilizador mantém | O utilizador transfere para o custodiante |
| Controlo de gastos | Limitado ao montante aprovado | Acesso total aos fundos transferidos |
| Revogação | Instantânea, pelo proprietário | Requer cooperação do custodiante |
| Exposição ao risco | Limitada ao montante aprovado | Saldo total |
| Confiança necessária | Limitada | Elevada |
A delegação oferece um meio-termo—permitindo pagamentos automatizados enquanto limita a exposição ao risco ao montante aprovado.
Recursos relacionados
| Recurso | Descrição |
|---|---|
| Aprovar delegado | Como conceder a outra conta permissão para gastar da sua token account. |
| Revogar delegado | Como remover um delegado existente e revogar as suas permissões de gasto. |
| Transferir token | Como transferir tokens entre token accounts. |
Is this page helpful?