PagosSuscripciones

Delegación Recurrente

Una delegación recurrente permite que un usuario autorice a otra billetera o servicio a retirar hasta un límite que se reinicia en cada período.

Esta guía mantiene visibles las partes móviles. Primero derivas las cuentas, inicializas la Autoridad de Suscripción si es necesario, creas la delegación recurrente y luego usas ese PDA de delegación para las transferencias.

Instalación

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

Crear la Delegación

La configuración tiene cuatro partes:

  1. Crear un cliente con el firmante del usuario y el plugin de suscripciones.
  2. Derivar la cuenta de tokens del usuario, el PDA de la Autoridad de Suscripción y el PDA de delegación recurrente.
  3. Inicializar la Autoridad de Suscripción si aún no existe.
  4. Crear la delegación recurrente con el monto del período, la duración del período, la hora de inicio y la expiración.
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,
findRecurringDelegationPda,
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 now = BigInt(Math.floor(Date.now() / 1000));
const nonce = 0n;
const amountPerPeriod = 1_000_000n;
const periodLengthS = 86_400n;
const startTs = now;
const expiryTs = now + periodLengthS * 30n;
const [userAta] = await findAssociatedTokenPda({
mint: tokenMint,
owner: userSigner.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const [subscriptionAuthorityPda] = await findSubscriptionAuthorityPda({
user: userSigner.address,
tokenMint,
});
const [delegationPda] = await findRecurringDelegationPda({
subscriptionAuthority: subscriptionAuthorityPda,
delegator: userSigner.address,
delegatee,
nonce,
});
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
.createRecurringDelegation({
tokenMint,
delegatee,
nonce,
amountPerPeriod,
periodLengthS,
startTs,
expiryTs,
})
.sendTransaction();

Transferir desde la Delegación

El delegado firma cada transferencia. El programa verifica el período actual y rechaza las transferencias que excedan el límite restante del período.

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

Revocar la Delegación

El delegador puede revocar la delegación recurrente en cualquier momento. Revocar cierra la PDA de delegación y devuelve su alquiler al firmante.

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

Notas

  • amountPerPeriod está en unidades base. Para un token de 6 decimales, 1_000_000 significa 1 token.
  • El programa rechaza las transferencias que superan la asignación restante del período actual.
  • Una vez que comienza el siguiente período, el monto extraído se reinicia.
  • expiryTs es un límite absoluto: una vez que se supera, las transferencias fallan y el patrocinador puede recuperar rent. No hay período de gracia de gasto.
  • Establece startTs en 0 para iniciar la delegación cuando la transacción se confirme en la cadena en lugar de en un momento fijo. Esto amplía la ventana para que el usuario firme y se incorpore. Al hacer esto, expiryTs debe ser distinto de cero: una delegación de inicio en confirmación tampoco puede configurarse para que nunca expire.
  • El usuario firma las transacciones de configuración y revocación. El delegado firma las transferencias.

Is this page helpful?

Tabla de Contenidos

Editar Página