PembayaranLangganan

Paket Langganan

Paket langganan memungkinkan pedagang menerbitkan ketentuan penagihan yang dapat diterima oleh pengguna. Setelah pengguna berlangganan, pedagang atau penarik yang disetujui dapat mengumpulkan hingga jumlah paket setiap periode penagihan.

Panduan ini menunjukkan alur lengkap sebagai blok bangunan. Pedagang membuat paket, pelanggan menerimanya, dan pedagang atau penarik mengumpulkan pembayaran dari PDA langganan yang dihasilkan.

Instalasi

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

Membuat Paket

Pedagang memiliki paket tersebut. PDA paket diturunkan dari alamat pedagang dan 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,
});

Memperbarui Paket

Pedagang dapat memperbarui kolom paket yang dapat diubah setelah pembuatan. Pelanggan yang sudah ada tetap mempertahankan ketentuan yang telah mereka terima, sementara pelanggan baru menerima ketentuan paket saat ini.

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

Berlangganan

Pelanggan menerima ketentuan paket saat ini. PDA langganan diturunkan dari PDA paket dan alamat pelanggan.

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

Mengumpulkan Pembayaran

Pedagang atau penarik yang masuk daftar putih menandatangani pengumpulan. Ketika paket menggunakan daftar izin tujuan, pemilik token account penerima harus terdaftar dalam 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();

Membatalkan Dan Mencabut

Pembatalan menandai langganan sebagai berakhir. Pencabutan menutup PDA langganan setelah masa berlaku pembatalan telah lewat. Pelanggan menandatangani kedua transaksi.

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

Catatan

  • amount dalam unit dasar. Untuk token 6-desimal, 5_000_000 berarti 5 token.
  • TypeScript SDK mengambil ketentuan paket secara langsung selama subscribe ketika Anda tidak menyertakannya.
  • Rust SubscribeBuilder memerlukan ketentuan paket yang diharapkan. Ambil dan decode akun paket terlebih dahulu, lalu teruskan field tersebut melalui SubscribeData.
  • Hanya merchant atau dompet yang terdaftar di pullers yang dapat mengumpulkan pembayaran.
  • Subscriber menandatangani transaksi setup, cancel, dan revoke. Merchant atau puller yang disetujui menandatangani transaksi pengumpulan.

Is this page helpful?

Daftar Isi

Edit Halaman
© 2026 Yayasan Solana. Semua hak dilindungi.