Un plan de suscripción permite a un comerciante publicar términos de facturación que los usuarios pueden aceptar. Después de que un usuario se suscribe, el comerciante o un extractor aprobado puede cobrar hasta el monto del plan en cada período de facturación.
Esta guía muestra el flujo completo como bloques de construcción. El comerciante crea un plan, el suscriptor lo acepta, y el comerciante o extractor cobra los pagos desde el PDA de suscripción resultante.
Instalación
pnpm add @solana/subscriptions @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token
Crear un Plan
El comerciante es propietario del plan. El PDA del plan se deriva de la
dirección del comerciante y planId.
import { address, createClient } from '@solana/kit';import { solanaLocalRpc } from '@solana/kit-plugin-rpc';import { signer } from '@solana/kit-plugin-signer';import { findPlanPda, subscriptionsProgram } from '@solana/subscriptions';const merchantClient = createClient().use(signer(merchantSigner)).use(solanaLocalRpc({ rpcUrl: 'http://127.0.0.1:8899' })).use(subscriptionsProgram());const planId = 1n;const tokenMint = address('TOKEN_MINT_ADDRESS_HERE');const amount = 5_000_000n;const periodHours = 720n;const metadataUri = 'https://example.com/plan.json';const destinations = [merchantSigner.address];const pullers = [address('PULLER_WALLET_ADDRESS_HERE')];await merchantClient.subscriptions.instructions.createPlan({planId,mint: tokenMint,amount,periodHours,endTs: 0n,destinations,pullers,metadataUri,}).sendTransaction();const [planPda] = await findPlanPda({owner: merchantSigner.address,planId,});
Actualizar un Plan
El comerciante puede actualizar los campos mutables del plan después de su creación. Los suscriptores existentes mantienen los términos que aceptaron, mientras que los nuevos suscriptores aceptan los términos actuales del plan.
import { PlanStatus } from '@solana/subscriptions';const updatedMetadataUri = 'https://example.com/updated-plan.json';const updatedPullers = [address('NEW_PULLER_WALLET_ADDRESS_HERE')];await merchantClient.subscriptions.instructions.updatePlan({owner: merchantSigner,planPda,status: PlanStatus.Active,endTs: 0n,pullers: updatedPullers,metadataUri: updatedMetadataUri,}).sendTransaction();
Suscribirse
El suscriptor acepta los términos actuales del plan. El PDA de suscripción se deriva del PDA del plan y la dirección del suscriptor.
import { 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,findSubscriptionAuthorityPda,findSubscriptionDelegationPda,subscriptionsProgram,} from '@solana/subscriptions';const subscriberClient = createClient().use(signer(subscriberSigner)).use(solanaLocalRpc({ rpcUrl: 'http://127.0.0.1:8899' })).use(subscriptionsProgram());const [subscriberAta] = await findAssociatedTokenPda({mint: tokenMint,owner: subscriberSigner.address,tokenProgram: TOKEN_PROGRAM_ADDRESS,});const [subscriptionAuthorityPda] = await findSubscriptionAuthorityPda({user: subscriberSigner.address,tokenMint,});const subscriptionAuthority = await fetchMaybeSubscriptionAuthority(subscriberClient.rpc,subscriptionAuthorityPda,);if (!subscriptionAuthority.exists) {await subscriberClient.subscriptions.instructions.initSubscriptionAuthority({tokenMint,tokenProgram: TOKEN_PROGRAM_ADDRESS,userAta: subscriberAta,}).sendTransaction();}await subscriberClient.subscriptions.instructions.subscribe({merchant: merchantSigner.address,planId,tokenMint,}).sendTransaction();const [subscriptionPda] = await findSubscriptionDelegationPda({planPda,subscriber: subscriberSigner.address,});
Cobrar un Pago
El comerciante o un extractor autorizado firma la cobranza. Cuando el plan
utiliza una lista de destinos permitidos, el propietario de la cuenta de tokens
receptora debe estar incluido en destinations.
const receiverAta = address('MERCHANT_TOKEN_ACCOUNT_ADDRESS_HERE');await merchantClient.subscriptions.instructions.transferSubscription({caller: merchantOrPullerSigner,delegator: subscriberSigner.address,tokenMint,subscriptionPda,planPda,amount: 200_000n,receiverAta,tokenProgram: TOKEN_PROGRAM_ADDRESS,}).sendTransaction();
Cancelar y Revocar
Cancelar marca la suscripción como finalizada. Revocar cierra el PDA de suscripción después de que haya transcurrido el período de vencimiento de la cancelación. El suscriptor firma ambas transacciones.
await subscriberClient.subscriptions.instructions.cancelSubscription({subscriber: subscriberSigner,planPda,subscriptionPda,}).sendTransaction();// Run this after the cancelled subscription's expiresAtTs has elapsed.await subscriberClient.subscriptions.instructions.revokeSubscription({authority: subscriberSigner,planPda,subscriptionPda,}).sendTransaction();
Notas
amountestá en unidades base. Para un token de 6 decimales,5_000_000significa5tokens.- El SDK de TypeScript obtiene los términos del plan en tiempo real durante
subscribecuando los omites. - El
SubscribeBuilderde Rust necesita los términos del plan esperados. Primero obtén y decodifica la cuenta del plan, luego pasa esos campos a través deSubscribeData. - Solo el comerciante o una billetera listada en
pullerspuede cobrar pagos. - El suscriptor firma las transacciones de configuración, cancelación y revocación. El comerciante o el extractor aprobado firma las transacciones de cobro.
Is this page helpful?