Um plano de assinatura permite que um comerciante publique termos de cobrança que os usuários podem aceitar. Após um usuário assinar, o comerciante ou um cobrador aprovado pode coletar até o valor do plano a cada período de cobrança.
Este guia mostra o fluxo completo como blocos de construção. O comerciante cria um plano, o assinante o aceita, e o comerciante ou cobrador coleta pagamentos do PDA de assinatura resultante.
Instalar
pnpm add @solana/subscriptions @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token
Criar um Plano
O comerciante é o proprietário do plano. O PDA do plano é derivado do endereço
do comerciante e 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,});
Atualizar um Plano
O comerciante pode atualizar campos mutáveis do plano após a criação. Assinantes existentes mantêm os termos que aceitaram, enquanto novos assinantes aceitam os termos atuais do plano.
Algumas regras se aplicam:
- Um
endTsfinito só pode ser encurtado, nunca estendido ou removido (PlanEndTsCannotExtend). - Em um plano
Sunsetvocê pode remover pullers (o novo conjunto deve ser um subconjunto do atual) para revogar um puller comprometido; o status,endTse os metadados permanecem congelados. - As edições funcionam durante o período de cobrança final de um plano, desde
que o
endTsnão seja alterado.
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();
Assinar
O assinante aceita os termos do plano atual. O PDA de assinatura é derivado do PDA do plano e do endereço do assinante.
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,});
Coletar um Pagamento
O comerciante ou um puller autorizado assina a cobrança. Quando o plano utiliza
uma lista de destinos permitidos, o proprietário do token account receptor deve
estar listado em 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 e Revogar
Cancelar marca a subscrição como encerrando. Revogar fecha a PDA da subscrição após o prazo de expiração do cancelamento ter decorrido. O subscritor assina ambas as transações.
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();
Retomar uma Subscrição
Uma subscrição cancelada pode ser reativada antes de ser revogada. Uma vez
revogada, a conta de subscrição é encerrada e o subscritor deve
subscrever novamente. Retomar requer o SubscriptionAuthority do
subscritor para o mint do plano, que o programa valida (proprietário, mint e
init_id) e rejeita se estiver desatualizado ou reinicializado.
await subscriberClient.subscriptions.instructions.resumeSubscription({subscriber: subscriberSigner,planPda,tokenMint,}).sendTransaction();
Notas
amountestá em unidades base. Para um token de 6 decimais,5_000_000significa5tokens.- O SDK TypeScript obtém os termos do plano em tempo real durante
subscribequando os omite. - O
SubscribeBuilderem Rust necessita dos termos esperados do plano. Obtenha e descodifique a conta do plano primeiro, em seguida passe esses campos através deSubscribeData. - Apenas o comerciante ou uma carteira listada em
pullerspode cobrar pagamentos. - O subscritor assina as transações de configuração, cancelamento e revogação. O comerciante ou o cobrador aprovado assina as transações de cobrança.
Is this page helpful?