ΠληρωμέςΣυνδρομές

Πρόγραμμα Συνδρομής

Ένα πρόγραμμα συνδρομής επιτρέπει σε έναν έμπορο να δημοσιεύσει όρους χρέωσης που μπορούν να αποδεχτούν οι χρήστες. Αφού ένας χρήστης εγγραφεί, ο έμπορος ή ένας εγκεκριμένος συλλέκτης μπορεί να εισπράξει έως και το ποσό του προγράμματος σε κάθε περίοδο χρέωσης.

Αυτός ο οδηγός παρουσιάζει την πλήρη ροή ως δομικά στοιχεία. Ο έμπορος δημιουργεί ένα πρόγραμμα, ο συνδρομητής το αποδέχεται και ο έμπορος ή ο συλλέκτης εισπράττει πληρωμές από το αποτελούμενο PDA συνδρομής.

Εγκατάσταση

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

Δημιουργία Προγράμματος

Ο έμπορος κατέχει το πρόγραμμα. Το PDA του προγράμματος προκύπτει από τη διεύθυνση του εμπόρου και το 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,
});

Ενημέρωση Προγράμματος

Ο έμπορος μπορεί να ενημερώσει τα μεταβλητά πεδία του προγράμματος μετά τη δημιουργία. Οι υπάρχοντες συνδρομητές διατηρούν τους όρους που αποδέχτηκαν, ενώ οι νέοι συνδρομητές αποδέχονται τους τρέχοντες όρους του προγράμματος.

Ισχύουν μερικοί κανόνες:

  • Ένα πεπερασμένο endTs μπορεί μόνο να συντομευτεί, ποτέ να επεκταθεί ή να διαγραφεί (PlanEndTsCannotExtend).
  • Σε ένα πλάνο Sunset μπορείτε να αφαιρέσετε pullers (το νέο σύνολο πρέπει να είναι υποσύνολο του τρέχοντος) για να ανακαλέσετε έναν παραβιασμένο puller· η κατάσταση, το endTs και τα μεταδεδομένα παραμένουν δεσμευμένα.
  • Οι επεξεργασίες λειτουργούν κατά την τελευταία περίοδο χρέωσης ενός πλάνου, εφόσον το endTs παραμένει αμετάβλητο.
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();

Εγγραφή

Ο συνδρομητής αποδέχεται τους τρέχοντες όρους του πλάνου. Το PDA συνδρομής προκύπτει από το PDA του πλάνου και τη διεύθυνση του συνδρομητή.

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,
});

Είσπραξη Πληρωμής

Ο έμπορος ή ένας εξουσιοδοτημένος puller υπογράφει την είσπραξη. Όταν το πλάνο χρησιμοποιεί λίστα επιτρεπόμενων προορισμών, ο κάτοχος του token account του παραλήπτη πρέπει να figurerer αναφέρεται στο 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();

Ακύρωση και Ανάκληση

Η ακύρωση σημειώνει τη συνδρομή ως λήγουσα. Η ανάκληση κλείνει το PDA της συνδρομής αφού παρέλθει η προθεσμία λήξης της ακύρωσης. Ο συνδρομητής υπογράφει και τις δύο συναλλαγές.

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();

Επαναφορά Συνδρομής

Μια ακυρωμένη συνδρομή μπορεί να επανενεργοποιηθεί πριν ανακληθεί. Μόλις ανακληθεί, ο λογαριασμός συνδρομής κλείνει και ο συνδρομητής πρέπει να εγγραφεί εκ νέου. Η επαναφορά απαιτεί το SubscriptionAuthority του συνδρομητή για το mint του πλάνου, το οποίο το πρόγραμμα επικυρώνει (ιδιοκτήτης, mint και init_id) και απορρίπτει αν είναι παρωχημένο ή έχει επανεκκινηθεί.

await subscriberClient.subscriptions.instructions
.resumeSubscription({
subscriber: subscriberSigner,
planPda,
tokenMint,
})
.sendTransaction();

Σημειώσεις

  • Το amount είναι σε βασικές μονάδες. Για ένα token 6 δεκαδικών, το 5_000_000 σημαίνει 5 tokens.
  • Το TypeScript SDK ανακτά τους ενεργούς όρους πλάνου κατά τη διάρκεια του subscribe όταν τους παραλείπετε.
  • Το SubscribeBuilder της Rust χρειάζεται τους αναμενόμενους όρους πλάνου. Ανακτήστε και αποκωδικοποιήστε πρώτα τον λογαριασμό πλάνου και στη συνέχεια διαβιβάστε αυτά τα πεδία μέσω του SubscribeData.
  • Μόνο ο έμπορος ή ένα πορτοφόλι που αναφέρεται στο pullers μπορεί να εισπράξει πληρωμές.
  • Ο συνδρομητής υπογράφει τις συναλλαγές εγκατάστασης, ακύρωσης και ανάκλησης. Ο έμπορος ή ο εγκεκριμένος συλλέκτης υπογράφει τις συναλλαγές είσπραξης.

Is this page helpful?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας
© 2026 Ίδρυμα Solana. Με επιφύλαξη παντός δικαιώματος.