Ein Abonnementplan ermöglicht es einem Händler, Abrechnungsbedingungen zu veröffentlichen, die Nutzer akzeptieren können. Nachdem ein Nutzer abonniert hat, kann der Händler oder ein autorisierter Einzieher bis zum Planbetrag in jeder Abrechnungsperiode einziehen.
Diese Anleitung zeigt den vollständigen Ablauf als Bausteine. Der Händler erstellt einen Plan, der Abonnent akzeptiert ihn, und der Händler oder Einzieher zieht Zahlungen aus dem resultierenden Abonnement-PDA ein.
Installation
pnpm add @solana/subscriptions @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token
Plan erstellen
Der Händler ist Eigentümer des Plans. Der Plan-PDA wird von der Händleradresse
und planId abgeleitet.
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,});
Plan aktualisieren
Der Händler kann veränderbare Planfelder nach der Erstellung aktualisieren. Bestehende Abonnenten behalten die von ihnen akzeptierten Bedingungen bei, während neue Abonnenten die aktuellen Planbedingungen akzeptieren.
Es gelten einige Regeln:
- Eine endliche
endTskann nur verkürzt, niemals verlängert oder gelöscht werden (PlanEndTsCannotExtend). - Bei einem
Sunset-Plan können Sie Puller entfernen (die neue Gruppe muss eine Teilmenge der aktuellen sein), um einen kompromittierten Puller zu sperren; Status,endTsund Metadaten bleiben eingefroren. - Änderungen sind während der letzten Abrechnungsperiode eines Plans möglich,
solange
endTsunverändert bleibt.
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();
Abonnieren
Der Abonnent akzeptiert die aktuellen Planbedingungen. Die Abonnement-PDA wird aus der Plan-PDA und der Abonnentenadresse abgeleitet.
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,});
Eine Zahlung einziehen
Der Händler oder ein autorisierter Puller unterzeichnet den Einzug. Wenn der
Plan eine Ziel-Zulassungsliste verwendet, muss der Inhaber des Empfänger-token
account in destinations aufgeführt sein.
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();
Abbrechen und Widerrufen
Das Abbrechen markiert das Abonnement als auslaufend. Das Widerrufen schließt das Abonnement-PDA, nachdem die Ablaufzeit der Kündigung verstrichen ist. Der Abonnent signiert beide Transaktionen.
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();
Ein Abonnement Fortsetzen
Ein gekündigtes Abonnement kann reaktiviert werden, bevor es widerrufen wird.
Nach dem Widerruf wird das Abonnement-Konten geschlossen und der Abonnent muss
erneut abonnieren. Für die Fortsetzung benötigt der Abonnent
SubscriptionAuthority für die Mint des Plans, den das Programm validiert
(Inhaber, Mint und init_id) und ablehnt, wenn er veraltet oder neu
initialisiert ist.
await subscriberClient.subscriptions.instructions.resumeSubscription({subscriber: subscriberSigner,planPda,tokenMint,}).sendTransaction();
Hinweise
amountist in Basiseinheiten. Bei einem Token mit 6 Dezimalstellen bedeutet5_000_0005Token.- Das TypeScript-SDK ruft aktuelle Planbedingungen während
subscribeab, wenn diese weggelassen werden. - Das Rust-
SubscribeBuilderbenötigt die erwarteten Planbedingungen. Rufen Sie zunächst das Plan-Konten ab und dekodieren Sie es, und übergeben Sie dann diese Felder überSubscribeData. - Nur der Händler oder eine in
pullersaufgeführte Wallet kann Zahlungen einziehen. - Der Abonnent signiert Einrichtungs-, Abbruch- und Widerrufstransaktionen. Der Händler oder ein autorisierter Einzieher signiert Einzugstransaktionen.
Is this page helpful?