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.

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 của gói hiện tại. PDA đăng ký được tạo ra từ PDA 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 tiền thanh toán

Người bán hoặc người rút tiền được phép ký xác nhận việc thu tiền. Khi gói sử dụng danh sách đích cho phép, 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 bỏ đánh dấu đăng ký là kết thúc. Thu hồi đóng PDA đăng ký sau khi thời hạn hủy đã trôi qua. 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();

Ghi chú

  • amount được tính theo đơn vị cơ bản. Đối với token có 6 chữ số thập phân, 5_000_000 có nghĩa là 5 token.
  • TypeScript SDK tự động lấy các điều khoản gói hiện tại trong quá trình subscribe khi bạn không cung cấp chúng.
  • Rust SubscribeBuilder cần các điều khoản gói dự kiến. Hãy lấy và giải mã tài khoản gói trước, sau đó truyền các trường đó qua SubscribeData.
  • Chỉ người bán 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. Người bán hoặc bên đượ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