drama-pm-client
v0.3.1
Published
TypeScript client for Drama Prediction Market
Maintainers
Readme
Drama PM Client SDK
TypeScript 客户端 SDK,用于与 Drama 预测市场 Solana 智能合约交互。
特性
- ✅ 完整的类型支持 - 使用 TypeScript 编写,提供完整的类型定义
- ✅ 自动 ATA 管理 - 自动检测和创建关联代币账户 (Associated Token Account)
- ✅ 简洁的 API - 提供简单易用的方法接口
- ✅ 灵活的交易构建 - 支持获取单个指令或完整交易
- ✅ PDA 计算工具 - 导出所有 PDA 派生函数
- ✅ 错误处理 - 完善的错误处理机制
安装
npm install drama-pm-client
# 或
yarn add drama-pm-client快速开始
import { Connection, PublicKey } from "@solana/web3.js";
import { DramaPmClient } from "drama-pm-client";
import { BN } from "@coral-xyz/anchor";
// 初始化连接和客户端
const connection = new Connection("https://api.devnet.solana.com");
const client = new DramaPmClient(connection);
// 创建市场
const createMarketTx = await client.buildCreateMarketTx({
admin: adminPublicKey,
marketId: new BN(1),
yesPrice: new BN(1_200_000), // 1.2 USDC
noPrice: new BN(800_000), // 0.8 USDC
endTime: new BN(Date.now() / 1000 + 3600), // 1小时后
bettingToken: usdcMint,
});
// 下注 (自动创建 ATA)
const placeBetTx = await client.buildPlaceBetTx({
user: userPublicKey,
admin: adminPublicKey,
marketId: new BN(1),
amount: new BN(1_000_000), // 1 USDC
outcome: "Yes",
bettingToken: usdcMint,
createAta: true, // 自动创建 ATA
});API 文档
DramaPmClient
主客户端类,提供所有合约交互方法。
构造函数
constructor(connection: Connection, wallet?: anchor.Wallet)connection: Solana RPC 连接wallet: (可选) Anchor 钱包,用于读取操作
方法
createMarket()
创建新的预测市场。
async createMarket(params: CreateMarketParams): Promise<TransactionInstruction>参数:
interface CreateMarketParams {
admin: PublicKey; // 市场管理员
marketId: number | BN; // 唯一市场 ID
yesPrice: number | BN; // YES 选项价格 (原始单位)
noPrice: number | BN; // NO 选项价格 (原始单位)
endTime: number | BN; // 市场结束时间 (Unix 时间戳)
bettingToken: PublicKey; // 投注代币 Mint 地址
}返回: TransactionInstruction
示例:
const ix = await client.createMarket({
admin: admin.publicKey,
marketId: new BN(123),
yesPrice: new BN(1_200_000),
noPrice: new BN(800_000),
endTime: new BN(Math.floor(Date.now() / 1000) + 3600),
bettingToken: usdcMint,
});buildCreateMarketTx()
构建完整的创建市场交易。
async buildCreateMarketTx(params: CreateMarketParams): Promise<Transaction>返回可直接发送的完整交易对象。
placeBet()
创建下注指令 (不包含 ATA 创建)。
async placeBet(params: PlaceBetParams): Promise<TransactionInstruction>参数:
interface PlaceBetParams {
user: PublicKey; // 用户公钥
admin: PublicKey; // 市场管理员
marketId: number | BN; // 市场 ID
amount: number | BN; // 下注金额 (原始单位)
outcome: "Yes" | "No"; // 下注选项
bettingToken: PublicKey; // 投注代币 Mint
createAta?: boolean; // (buildPlaceBetTx 专用) 是否自动创建 ATA
}返回: TransactionInstruction
buildPlaceBetTx()
构建完整的下注交易,支持自动创建 ATA。
async buildPlaceBetTx(params: PlaceBetParams): Promise<Transaction>特性:
- 自动检查 ATA 是否存在
- 如果
createAta: true且 ATA 不存在,自动添加创建指令 - 返回完整的交易对象
示例:
// 自动处理 ATA 创建
const tx = await client.buildPlaceBetTx({
user: user.publicKey,
admin: admin.publicKey,
marketId: new BN(123),
amount: new BN(2_000_000), // 2 USDC
outcome: "Yes",
bettingToken: usdcMint,
createAta: true, // 自动创建 ATA
});
await sendAndConfirmTransaction(connection, tx, [user]);claimRewards()
创建领取奖励指令。
async claimRewards(params: ClaimRewardsParams): Promise<TransactionInstruction>参数:
interface ClaimRewardsParams {
user: PublicKey; // 用户公钥
admin: PublicKey; // 市场管理员
marketId: number | BN; // 市场 ID
bettingToken: PublicKey; // 投注代币 Mint
winningOutcome: "Yes" | "No"; // 获胜选项
}buildClaimRewardsTx()
构建完整的领取奖励交易。
async buildClaimRewardsTx(params: ClaimRewardsParams): Promise<Transaction>refund()
创建退款指令 (当市场被标记为退款状态时)。
async refund(params: RefundParams): Promise<TransactionInstruction>参数:
interface RefundParams {
user: PublicKey; // 用户公钥
admin: PublicKey; // 市场管理员
marketId: number | BN; // 市场 ID
bettingToken: PublicKey; // 投注代币 Mint
outcome: "Yes" | "No"; // 要退款的选项
}buildRefundTx()
构建完整的退款交易。
async buildRefundTx(params: RefundParams): Promise<Transaction>resolveMarket()
创建决算市场指令 (仅管理员)。
async resolveMarket(
admin: PublicKey,
marketId: number | BN,
winningOutcome: "Yes" | "No" | null
): Promise<TransactionInstruction>参数:
admin: 管理员公钥marketId: 市场 IDwinningOutcome: 获胜选项,null表示退款
buildResolveMarketTx()
构建完整的决算市场交易。
async buildResolveMarketTx(
admin: PublicKey,
marketId: number | BN,
winningOutcome: "Yes" | "No" | null
): Promise<Transaction>closeMarket()
创建关闭市场指令 (仅管理员)。
async closeMarket(
admin: PublicKey,
marketId: number | BN
): Promise<TransactionInstruction>buildCloseMarketTx()
构建完整的关闭市场交易。
async buildCloseMarketTx(
admin: PublicKey,
marketId: number | BN
): Promise<Transaction>getMarketAccount()
获取市场账户数据。
async getMarketAccount(admin: PublicKey, marketId: number | BN)返回: 市场账户数据对象
示例:
const market = await client.getMarketAccount(admin.publicKey, new BN(123));
console.log("Status:", market.status);
console.log("Total YES supply:", market.totalYesSupply.toString());
console.log("Total NO supply:", market.totalNoSupply.toString());ataExists()
检查关联代币账户是否存在。
async ataExists(ata: PublicKey): Promise<boolean>createAtaInstruction()
创建 ATA 初始化指令。
createAtaInstruction(
payer: PublicKey,
owner: PublicKey,
mint: PublicKey
): TransactionInstruction工具函数
SDK 导出了所有 PDA 计算函数:
import {
getMarketPda,
getYesMintPda,
getNoMintPda,
getVaultPda,
getMarketPdas, // 一次性获取所有 PDA
} from "drama-pm-client";
// 计算单个 PDA
const marketPda = getMarketPda(programId, admin, marketId);
// 一次性获取所有 PDA
const { market, yesMint, noMint, vault } = getMarketPdas(
programId,
admin,
marketId
);SDK 优化说明
相比初始版本,SDK 进行了以下优化:
1. 接口参数化
- ✅ 使用 TypeScript 接口定义参数,提高代码可读性
- ✅ 统一的参数结构,减少函数签名复杂度
2. 自动 ATA 管理
- ✅
buildPlaceBetTx()支持自动检测和创建 ATA - ✅ 提供
ataExists()检查方法 - ✅ 提供
createAtaInstruction()手动创建 ATA
3. 双层 API 设计
- ✅ 指令级方法:
createMarket(),placeBet()等 - ✅ 交易级方法:
buildCreateMarketTx(),buildPlaceBetTx()等 - ✅ 灵活满足不同使用场景
4. PDA 工具优化
- ✅ 提供
getMarketPdas()一次性获取所有 PDA - ✅ 导出所有 PDA 计算函数供外部使用
- ✅ 内部使用 PDA 缓存减少重复计算
5. 错误处理改进
- ✅ 使用
accountsPartial()替代accounts(),更安全 - ✅ ATA 存在性检查,避免重复创建错误
- ✅ 完整的 TypeScript 类型检查
6. 对齐测试代码
- ✅ 参数顺序和命名与测试代码一致
- ✅ ATA 创建模式与测试代码相同
- ✅ 支持与测试代码相同的使用模式
使用模式对比
模式 1: 完整交易构建 (推荐)
// SDK 自动处理 ATA 创建
const tx = await client.buildPlaceBetTx({
user: user.publicKey,
admin: admin.publicKey,
marketId: new BN(1),
amount: new BN(1_000_000),
outcome: "Yes",
bettingToken: usdcMint,
createAta: true,
});
await sendAndConfirmTransaction(connection, tx, [user]);模式 2: 手动组合指令
import { Transaction } from "@solana/web3.js";
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
const tx = new Transaction();
const pdas = getMarketPdas(programId, admin.publicKey, marketId);
const userOutcomeToken = getAssociatedTokenAddressSync(
pdas.yesMint,
user.publicKey
);
// 检查并创建 ATA
if (!(await client.ataExists(userOutcomeToken))) {
const createAtaIx = client.createAtaInstruction(
user.publicKey,
user.publicKey,
pdas.yesMint
);
tx.add(createAtaIx);
}
// 添加下注指令
const placeBetIx = await client.placeBet({
user: user.publicKey,
admin: admin.publicKey,
marketId: new BN(1),
amount: new BN(1_000_000),
outcome: "Yes",
bettingToken: usdcMint,
});
tx.add(placeBetIx);
await sendAndConfirmTransaction(connection, tx, [user]);模式 3: 仅获取指令
// 适用于需要自定义交易构建的场景
const ix = await client.placeBet({
user: user.publicKey,
admin: admin.publicKey,
marketId: new BN(1),
amount: new BN(1_000_000),
outcome: "Yes",
bettingToken: usdcMint,
});
// 添加到自定义交易
const customTx = new Transaction();
customTx.add(someOtherIx);
customTx.add(ix);
customTx.add(anotherIx);完整示例
查看 app/ 目录下的完整 demo 应用,展示了:
- ✅ 市场创建
- ✅ 多用户下注
- ✅ 市场关闭和决算
- ✅ 奖励领取
- ✅ 完整的错误处理
运行 demo:
cd app
npm install
npm run dev类型定义
export type Outcome = "Yes" | "No";
export interface CreateMarketParams {
admin: PublicKey;
marketId: number | BN;
yesPrice: number | BN;
noPrice: number | BN;
endTime: number | BN;
bettingToken: PublicKey;
}
export interface PlaceBetParams {
user: PublicKey;
admin: PublicKey;
marketId: number | BN;
amount: number | BN;
outcome: Outcome;
bettingToken: PublicKey;
createAta?: boolean;
}
export interface ClaimRewardsParams {
user: PublicKey;
admin: PublicKey;
marketId: number | BN;
bettingToken: PublicKey;
winningOutcome: Outcome;
}
export interface RefundParams {
user: PublicKey;
admin: PublicKey;
marketId: number | BN;
bettingToken: PublicKey;
outcome: Outcome;
}许可证
MIT
贡献
欢迎提交 Issue 和 Pull Request!
