ПлатежіРозширені платежі

Дозволи на витрачання

Токенові програми Solana підтримують делегування — надання іншому обліковому запису дозволу на переказ токенів з вашого токенового облікового запису до вказаного ліміту. Це дозволяє реалізувати такі сценарії, як автоматизовані платежі, ескроу-сервіси та обробка платежів третіми сторонами без втрати контролю над вашими коштами.

Як працює делегування

Коли ви схвалюєте делегата, ви надаєте певному обліковому запису право переказувати токени від вашого імені:

  • Власник зберігає контроль: ви як і раніше володієте токенами і можете переказувати їх або відкликати делегування в будь-який момент
  • Обмежене витрачання: делегат може переказати лише до схваленої суми
  • Один делегат на обліковий запис: кожен токеновий обліковий запис може мати лише одного активного делегата
  • Нове схвалення замінює попереднє: схвалення нового делегата автоматично відкликає попереднього

Делегування є некастодіальним. Делегат може витрачати токени до встановленого ліміту, але не може отримати доступ до облікового запису або вивести кошти понад схвалену суму. Власник може відкликати делегування в будь-який момент.

Бізнес-сценарії використання

Сценарій використанняЯк допомагає делегування
Платіжні процесориПродавець надає процесору дозвіл на проведення транзакцій
Автоматизована зарплатаКазначейство схвалює зарплатний сервіс для виплати заробітних плат
Ескроу-сервісиПокупець делегує ескроу-агенту право на умовне вивільнення коштів
Торгові платформиКористувач схвалює біржу для виконання угод від його імені
Випуск картокКористувач схвалює емітента картки для списання покупок з його токенового облікового запису

Схвалення делегата

Надайте іншому обліковому запису дозвіл витрачати токени з вашого облікового запису:

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
});

Параметри:

  • source: обліковий запис токенів, який надає дозвіл
  • delegate: обліковий запис, який отримає дозвіл на витрачання
  • owner: поточний власник облікового запису токенів (має підписати транзакцію)
  • amount: максимальна кількість токенів, яку делегат може переказати
  • decimals: кількість десяткових знаків токена для валідації (запобігає помилкам з десятковими знаками)

Демонстрація

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.

Відкликання делегата

Видалити всі дозволи на витрачання від поточного делегата:

import { getRevokeInstruction } from "@solana-program/token";
const revokeInstruction = getRevokeInstruction({
source: tokenAccountAddress, // Your token account
owner: ownerKeypair // You (must sign)
});

Відкликання видаляє всі дозволи делегата — часткове відкликання неможливе. Якщо потрібно зменшити ліміт, схваліть того самого делегата з меншою сумою.

Демонстрація

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.

Переказ як делегат

Діючи як делегат, використовуйте звичайний переказ, але підписуйте keypair делегата замість власника:

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
});

Переказ буде успішним, якщо:

  • На вихідному рахунку достатньо коштів
  • Делегат підписує транзакцію

Кожен переказ зменшує залишок дозволеної суми. Коли дозволена сума досягає нуля, делегат більше не може переказувати токени.

Демонстрація

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.

Перевірка статусу делегування

Запитайте обліковий запис токенів, щоб побачити його поточного делегата та залишок дозволу:

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");
}

Демонстрація

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.

Міркування безпеки

Для власників облікових записів:

  • Схвалюйте лише перевірених делегатів
  • Встановлюйте мінімально необхідний ліміт витрат
  • Відкликайте делегування, коли воно більше не потрібне
  • Відстежуйте свої облікові записи на предмет несподіваних переказів

Для постачальників послуг (делегатів):

  • Чітко повідомляйте користувачам про запитуваний ліміт витрат
  • Впроваджуйте належне управління ключами для вашого облікового запису делегата
  • Відстежуйте використання дозволеної суми, щоб запитувати повторне схвалення до вичерпання лімітів

Делегування проти зберігання

АспектДелегуванняПовне зберігання
Власність токенівЗалишається у користувачаКористувач передає зберігачу
Контроль витратОбмежений схваленою сумоюПовний доступ до переданих коштів
ВідкликанняМиттєве, власникомПотребує співпраці зберігача
РизикОбмежений схваленою сумоюВесь баланс
Необхідна довіраОбмеженаВисока

Делегування забезпечує золоту середину — дозволяє автоматизовані платежі, обмежуючи ризик схваленою сумою.

Пов'язані ресурси

РесурсОпис
Схвалення делегатаЯк надати іншому обліковому запису дозвіл витрачати з вашого облікового запису токенів.
Відкликання делегатаЯк видалити існуючого делегата та відкликати його дозволи на витрачання.
Переказ токенівЯк переказувати токени між обліковими записами токенів.

Is this page helpful?

Керується

© 2026 Фонд Solana.
Всі права захищені.
Залишайтеся на зв'язку