サブスクリプションプランは、販売者がユーザーが承諾できる請求条件を公開できるようにします。ユーザーがサブスクライブすると、販売者または承認されたプーラーは、各請求期間にプラン金額まで回収できます。
このガイドでは、全体的なフローをビルディングブロックとして示します。販売者がプランを作成し、サブスクライバーがそれを承諾し、販売者またはプーラーが結果として生成されるサブスクリプション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プランでは、プラーを削除することができます(新しいセットは現在のセットのサブセットである必要があります)。これにより、侵害されたプラーへのアクセスを取り消すことができます。ただし、ステータス、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,});
支払いの回収
マーチャントまたはホワイトリストに登録されたプラーが回収に署名します。プランが宛先許可リストを使用している場合、受信者の token
account のオーナーが 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が必要です(オーナー、ミント、およびinit_id)。古くなっているか再初期化されている場合は拒否されます。
await subscriberClient.subscriptions.instructions.resumeSubscription({subscriber: subscriberSigner,planPda,tokenMint,}).sendTransaction();
注意事項
amountは基本単位で表されます。小数点以下6桁のトークンの場合、5_000_000は5トークンを意味します。- TypeScript
SDKは、省略した場合に
subscribe中にライブのプラン条件を取得します。 - Rustの
SubscribeBuilderには期待されるプラン条件が必要です。まずプランアカウントを取得してデコードし、SubscribeDataを通じてそれらのフィールドを渡してください。 - マーチャントまたは
pullersに登録されているウォレットのみが支払いを収集できます。 - サブスクライバーはセットアップ、キャンセル、および失効トランザクションに署名します。マーチャントまたは承認済みプラーが収集トランザクションに署名します。
Is this page helpful?