Thanh toánĐăng ký

Gói Đăng Ký

Gói đăng ký cho phép người bán công bố các điều khoản thanh toán mà người dùng có thể chấp nhận. Sau khi người dùng đăng ký, người bán hoặc bên được ủy quyền có thể thu tiền lên đến số tiền trong gói cho mỗi kỳ thanh toán.

Hướng dẫn này trình bày toàn bộ quy trình dưới dạng các khối xây dựng. Người bán tạo gói, người đăng ký chấp nhận gói đó, và người bán hoặc bên được ủy quyền thu tiền từ PDA đăng ký được tạo ra.

Cài Đặt

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

Tạo Gói

Người bán sở hữu gói. PDA của gói được tạo từ địa chỉ người bán và 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,
});

Cập Nhật Gói

Người bán có thể cập nhật các trường có thể thay đổi của gói sau khi tạo. Những người đăng ký hiện tại vẫn giữ nguyên các điều khoản họ đã chấp nhận, trong khi người đăng ký mới sẽ chấp nhận các điều khoản hiện tại của gói.

Một số quy tắc áp dụng:

  • Một endTs hữu hạn chỉ có thể được rút ngắn, không bao giờ được gia hạn hoặc xóa (PlanEndTsCannotExtend).
  • Trong gói Sunset, bạn có thể xóa các puller (tập hợp mới phải là tập con của tập hợp hiện tại) để thu hồi quyền của một puller bị xâm phạm; trạng thái, endTs và siêu dữ liệu vẫn bị đóng băng.
  • Các chỉnh sửa có hiệu lực trong kỳ thanh toán cuối cùng của gói miễn là endTs không thay đổi.
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();

Đăng Ký

Người đăng ký chấp nhận các điều khoản gói hiện tại. PDA đăng ký được suy ra từ PDA của gói và địa chỉ người đăng ký.

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

Thu Thanh Toán

Người bán hoặc một puller được đưa vào danh sách trắng sẽ ký xác nhận thu tiền. Khi gói sử dụng danh sách cho phép đích, chủ sở hữu của token account nhận phải được liệt kê trong 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();

Hủy Và Thu Hồi

Hủy đánh dấu gói đăng ký là sắp kết thúc. Thu hồi đóng PDA của gói đăng ký sau khi thời hạn hủy đã hết. Người đăng ký ký cả hai giao dịch.

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

Tiếp Tục Gói Đăng Ký

Một gói đăng ký đã hủy có thể được kích hoạt lại trước khi bị thu hồi. Sau khi bị thu hồi, tài khoản đăng ký sẽ bị đóng và người đăng ký phải đăng ký lại. Tiếp tục yêu cầu SubscriptionAuthority của người đăng ký cho mint của gói, mà chương trình xác thực (chủ sở hữu, mint và init_id) và từ chối nếu đã cũ hoặc được khởi tạo lại.

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

Lưu Ý

  • amount tính theo đơn vị cơ sở. Với token có 6 chữ số thập phân, 5_000_000 có nghĩa là 5 token.
  • TypeScript SDK lấy các điều khoản gói trực tiếp trong quá trình subscribe khi bạn bỏ qua chúng.
  • SubscribeBuilder của Rust cần các điều khoản gói dự kiến. Tải và giải mã tài khoản gói trước, sau đó truyền các trường đó qua SubscribeData.
  • Chỉ merchant hoặc ví được liệt kê trong pullers mới có thể thu thanh toán.
  • Người đăng ký ký các giao dịch thiết lập, hủy và thu hồi. Merchant hoặc puller được phê duyệt ký các giao dịch thu tiền.

Is this page helpful?

Mục lục

Chỉnh sửa trang