تتيح خطة الاشتراك للتاجر نشر شروط الفوترة التي يمكن للمستخدمين قبولها. بعد اشتراك المستخدم، يمكن للتاجر أو السّاحب المُعتمد تحصيل ما يصل إلى مبلغ الخطة في كل فترة فوترة.
يعرض هذا الدليل التدفق الكامل كوحدات بناء. ينشئ التاجر خطة، ويقبلها المشترك، ثم يقوم التاجر أو السّاحب بتحصيل المدفوعات من حساب 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عند حذفها. - يحتاج
SubscribeBuilderفي Rust إلى شروط الخطة المتوقعة. احرص على جلب حساب الخطة وفك ترميزه أولًا، ثم مرِّر تلك الحقول عبرSubscribeData. - يمكن للتاجر فقط أو أي محفظة مدرجة في
pullersتحصيل المدفوعات. - يوقّع المشترك معاملات الإعداد والإلغاء والسحب. أما التاجر أو المحصّل المعتمد فيوقّع معاملات التحصيل.
Is this page helpful?