ÖdemelerAbonelikler

Abonelik Planı

Abonelik planı, bir satıcının kullanıcıların kabul edebileceği faturalandırma koşullarını yayınlamasına olanak tanır. Bir kullanıcı abone olduktan sonra, satıcı veya onaylanmış bir tahsildar her faturalandırma döneminde plan tutarına kadar tahsilat yapabilir.

Bu kılavuz, tam akışı yapı taşları olarak göstermektedir. Satıcı bir plan oluşturur, abone bunu kabul eder ve satıcı veya tahsildar ortaya çıkan abonelik PDA'sından ödemeleri tahsil eder.

Kurulum

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

Plan Oluşturma

Satıcı, planın sahibidir. Plan PDA'sı, satıcı adresinden ve planId'den türetilir.

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ı Güncelleme

Satıcı, oluşturulduktan sonra değiştirilebilir plan alanlarını güncelleyebilir. Mevcut aboneler kabul ettikleri koşulları korurken, yeni aboneler mevcut plan koşullarını kabul eder.

Birkaç kural geçerlidir:

  • Sonlu bir endTs yalnızca kısaltılabilir, hiçbir zaman uzatılamaz veya temizlenemez (PlanEndTsCannotExtend).
  • Sunset planında, ele geçirilmiş bir çekiciyi iptal etmek için çekicileri kaldırabilirsiniz (yeni küme, mevcut kümenin bir alt kümesi olmalıdır); durum, endTs ve meta veriler dondurulmuş kalır.
  • Düzenlemeler, endTs değişmediği sürece bir planın son faturalandırma döneminde de geçerlidir.
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();

Abone Ol

Abone, mevcut plan koşullarını kabul eder. Abonelik PDA'sı, plan PDA'sından ve abone adresinden türetilir.

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

Ödeme Tahsil Et

Ödemeyi merchant veya beyaz listedeki bir çekici imzalar. Plan bir hedef izin listesi kullandığında, alıcı token account sahibi destinations listesinde yer almalıdır.

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

İptal Et ve İptal Yetki Kaldır

İptal etmek, aboneliği sona erecek şekilde işaretler. Yetki kaldırma ise iptal süresinin dolmasının ardından abonelik PDA'sını kapatır. Abone her iki işlemi de imzalar.

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

Aboneliği Sürdür

İptal edilmiş bir abonelik, yetkisi kaldırılmadan önce yeniden etkinleştirilebilir. Yetki kaldırıldıktan sonra abonelik hesabı kapatılır ve abonenin yeniden abone olması gerekir. Sürdürme işlemi, aboneden planın mint'i için SubscriptionAuthority gerektirir; program bu bilgiyi (sahip, mint ve init_id) doğrular ve bilgi güncel değilse ya da yeniden başlatılmışsa reddeder.

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

Notlar

  • amount temel birimler cinsindendir. 6 ondalık basamaklı bir token için 5_000_000, 5 token anlamına gelir.
  • TypeScript SDK, subscribe sırasında plan koşullarını atladığınızda bunları canlı olarak çeker.
  • Rust SubscribeBuilder, beklenen plan koşullarına ihtiyaç duyar. Önce plan hesabını çekip çözümleyin, ardından bu alanları SubscribeData aracılığıyla iletin.
  • Yalnızca merchant veya pullers listesinde yer alan bir cüzdan ödeme toplayabilir.
  • Abone, kurulum, iptal ve yetki kaldırma işlemlerini imzalar. Merchant veya onaylı toplayıcı ise ödeme toplama işlemlerini imzalar.

Is this page helpful?

İçindekiler

Sayfayı Düzenle
© 2026 Solana Vakfı. Tüm hakları saklıdır.