Fixed Delegation

A fixed delegation lets a user approve another wallet or service to pull up to a fixed token amount. Each successful transfer reduces the remaining allowance. Use expiryTs = 0 for no expiry.

This guide keeps the flow visible. Each snippet uses the SDK functions directly so you can see which account is derived, which instruction is sent, and which signer pays or authorizes each step.

Install

pnpm add @solana/subscriptions @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token

Create The Delegation

The setup has four parts:

  1. Create a client with the user signer and subscriptions plugin.
  2. Derive the user's token account and Subscription Authority PDA.
  3. Initialize the Subscription Authority if it does not exist yet.
  4. Create the fixed delegation and derive its PDA for later transfers.
import { address, createClient } from '@solana/kit';
import { solanaLocalRpc } from '@solana/kit-plugin-rpc';
import { signer } from '@solana/kit-plugin-signer';
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
import {
fetchMaybeSubscriptionAuthority,
findFixedDelegationPda,
findSubscriptionAuthorityPda,
subscriptionsProgram,
} from '@solana/subscriptions';
const client = createClient()
.use(signer(userSigner))
.use(solanaLocalRpc({ rpcUrl: 'http://127.0.0.1:8899' }))
.use(subscriptionsProgram());
const tokenMint = address('TOKEN_MINT_ADDRESS_HERE');
const delegatee = address('DELEGATEE_WALLET_ADDRESS_HERE');
const nonce = 0n;
const amount = 1_000_000n;
const expiryTs = BigInt(Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30);
const [userAta] = await findAssociatedTokenPda({
mint: tokenMint,
owner: userSigner.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const [subscriptionAuthorityPda] = await findSubscriptionAuthorityPda({
user: userSigner.address,
tokenMint,
});
const subscriptionAuthority = await fetchMaybeSubscriptionAuthority(
client.rpc,
subscriptionAuthorityPda,
);
if (!subscriptionAuthority.exists) {
await client.subscriptions.instructions
.initSubscriptionAuthority({
tokenMint,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
userAta,
})
.sendTransaction();
}
await client.subscriptions.instructions
.createFixedDelegation({
tokenMint,
delegatee,
nonce,
amount,
expiryTs,
})
.sendTransaction();
const [delegationPda] = await findFixedDelegationPda({
subscriptionAuthority: subscriptionAuthorityPda,
delegator: userSigner.address,
delegatee,
nonce,
});

Transfer From The Delegation

The delegatee signs the transfer. The SDK needs the same delegation PDA, the user's token account, and the receiver token account.

const receiverAta = address('RECEIVER_TOKEN_ACCOUNT_ADDRESS_HERE');
await client.subscriptions.instructions
.transferFixed({
delegatee: delegateeSigner,
delegator: userSigner.address,
delegatorAta: userAta,
tokenMint,
delegationPda,
amount: 100_000n,
receiverAta,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
})
.sendTransaction();

Revoke The Delegation

The delegator can revoke the delegation at any time. Revoking closes the delegation PDA and returns its rent to the signer.

await client.subscriptions.instructions
.revokeDelegation({
authority: userSigner,
delegationAccount: delegationPda,
})
.sendTransaction();

Notes

  • The user's token account must exist before initialization.
  • Amounts are in base units. For a 6-decimal token, 1_000_000 means 1 token.
  • Run initSubscriptionAuthority only when the Subscription Authority account does not already exist.
  • The user signs setup and revoke transactions. The delegatee signs transfers.

Is this page helpful?

Spis treści

Edytuj stronę

Zarządzane przez

© 2026 Solana Foundation.
Wszelkie prawa zastrzeżone.
Bądź na bieżąco