PagamentosPagamentos avançados

Permissões de gasto

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 usoComo a delegação ajuda
Processadores de pagamentoO comerciante concede permissão ao processador para liquidar transações
Folha de pagamento automáticaA tesouraria aprova o serviço de folha de pagamento para desembolsar salários
Serviços de custódiaO comprador delega ao agente de custódia para liberação condicional
Plataformas de negociaçãoO utilizador aprova a exchange para executar negociações em seu nome
Emissão de cartõesO 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 account
mint: usdcMintAddress, // USDC mint
delegate: delegateAddress, // Account receiving permission
owner: ownerKeypair, // You (must sign)
amount: 1_000_000_000n, // 1,000 USDC in base units
decimals: 6
});

Parâmetros:

  • source: A token account que concede a permissão
  • delegate: A conta que terá permissão de gasto
  • owner: Proprietário atual da token account (deve assinar a transação)
  • amount: Quantidade máxima de tokens que o delegado pode transferir
  • decimals: Decimais do token para validação (previne erros de casas decimais)

Demonstração

Approve Delegate
// Generate keypairs for sender and delegate
const 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 tokens
const { client, mint, senderAta } = await demoSetup(sender);
console.log("\nMint Address:", mint.address);
console.log("Sender ATA:", senderAta);
// =============================================================================
// Approve Delegate
// =============================================================================
// Create instruction to approve delegate
const approveInstruction = getApproveCheckedInstruction({
source: senderAta,
mint: mint.address,
delegate: delegate.address,
owner: sender,
amount: 1_000_000n, // 1.0 tokens with 6 decimals
decimals: 6
});
// Send approve transaction
const 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 set
const tokenData = await fetchToken(client.runtime.rpc, senderAta);
console.log("\nSender Token Account Data:", tokenData.data);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

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 account
owner: 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

Revoke Delegate
// Generate keypairs for sender and delegate
const 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 tokens
const { 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 delegate
const approveInstruction = getApproveCheckedInstruction({
source: senderAta,
mint: mint.address,
delegate: delegate.address,
owner: sender,
amount: 1_000_000n, // 1.0 tokens with 6 decimals
decimals: 6
});
// Send approve transaction
const 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 set
const tokenDataAfterApprove = await fetchToken(client.runtime.rpc, senderAta);
console.log("\nSender Token Account Data:", tokenDataAfterApprove.data);
// =============================================================================
// Transaction 2: Revoke Delegate
// =============================================================================
// Create instruction to revoke delegate
const revokeInstruction = getRevokeInstruction({
source: senderAta,
owner: sender
});
// Send revoke transaction
const 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 revoked
const tokenDataAfterRevoke = await fetchToken(client.runtime.rpc, senderAta);
console.log("\nSender Token Account Data:", tokenDataAfterRevoke.data);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

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:

Transfer as Delegate
import { getTransferCheckedInstruction } from "@solana-program/token";
const transferInstruction = getTransferCheckedInstruction({
source: ownerTokenAccount, // The account you have permission to spend from
mint: usdcMintAddress,
destination: recipientTokenAccount,
authority: delegateKeypair, // You (the delegate) sign, not the owner
amount: 100_000_000n, // 100 USDC
decimals: 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

Transfer as Delegate
// Generate keypairs for sender, delegate, and recipient
const 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 tokens
const { 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 delegate
const approveInstruction = getApproveCheckedInstruction({
source: senderAta,
mint: mint.address,
delegate: delegate.address,
owner: sender,
amount: 1_000_000n, // 1.0 tokens with 6 decimals
decimals: 6
});
// Send approve transaction
const 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 owner
const transferInstruction = getTransferCheckedInstruction({
source: senderAta,
mint: mint.address,
destination: recipientAta,
authority: delegate, // Delegate signs this transaction
amount: 500_000n, // 0.5 tokens with 6 decimals
decimals: 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 signs
instructions: [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
// =============================================================================
Console
Click to execute the code.

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

Check Delegation Status
// 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 delegate
const tokenWithDelegate = await fetchToken(client.runtime.rpc, ataWithDelegate);
console.log("Token Account with Delegate:", tokenWithDelegate);
// Fetch token account without delegate
const tokenWithoutDelegate = await fetchToken(
client.runtime.rpc,
ataWithoutDelegate
);
console.log("\nToken Account without Delegate:", tokenWithoutDelegate);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

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

AspetoDelegaçãoCustódia total
Propriedade dos tokensO utilizador mantémO utilizador transfere para o custodiante
Controlo de gastosLimitado ao montante aprovadoAcesso total aos fundos transferidos
RevogaçãoInstantânea, pelo proprietárioRequer cooperação do custodiante
Exposição ao riscoLimitada ao montante aprovadoSaldo total
Confiança necessáriaLimitadaElevada

A delegação oferece um meio-termo—permitindo pagamentos automatizados enquanto limita a exposição ao risco ao montante aprovado.

Recursos relacionados

RecursoDescrição
Aprovar delegadoComo conceder a outra conta permissão para gastar da sua token account.
Revogar delegadoComo remover um delegado existente e revogar as suas permissões de gasto.
Transferir tokenComo transferir tokens entre token accounts.

Is this page helpful?

Gerenciado por

© 2026 Fundação Solana.
Todos os direitos reservados.
Conecte-se
  • Blog