ПлатежіПідписки

План підписки

План підписки дозволяє продавцю опублікувати умови виставлення рахунків, які користувачі можуть прийняти. Після того, як користувач підписується, продавець або затверджений збирач може стягувати до суми плану кожен розрахунковий період.

Цей посібник показує повний процес як окремі блоки. Продавець створює план, підписник приймає його, а продавець або збирач отримує платежі з отриманого 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?

Зміст

Редагувати сторінку