multistake 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,13 +1,8 @@
1
1
  {
2
2
  "name": "multistake",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "TypeScript SDK for MultiStake - Single Token Staking System",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "tsc && cp src/multistake.json dist/multistake.json",
9
- "prepublish": "npm run build"
10
- },
5
+ "main": "src/index.ts",
11
6
  "keywords": [
12
7
  "solana",
13
8
  "anchor",
package/src/sdk.ts ADDED
@@ -0,0 +1,353 @@
1
+ import * as anchor from "@coral-xyz/anchor";
2
+ import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
3
+ import {
4
+ Connection,
5
+ PublicKey,
6
+ Keypair,
7
+ SystemProgram,
8
+ SYSVAR_RENT_PUBKEY,
9
+ Transaction,
10
+ } from "@solana/web3.js";
11
+ import {
12
+ TOKEN_PROGRAM_ID,
13
+ getAssociatedTokenAddress,
14
+ getOrCreateAssociatedTokenAccount,
15
+ createMint,
16
+ } from "@solana/spl-token";
17
+ import { Multistake } from "./types/multistake";
18
+ import IDL from "./multistake.json";
19
+ import {
20
+ PoolConfig,
21
+ PoolInfo,
22
+ TokenInfo,
23
+ } from "./types";
24
+ import { createAssociatedTokenAccountInstruction } from "@solana/spl-token";
25
+
26
+ /**
27
+ * AnySwap SDK - 单币质押系统
28
+ */
29
+ export class MultiStakeSDK {
30
+ private program: Program<Multistake>;
31
+ private provider: AnchorProvider;
32
+
33
+ constructor(
34
+ program: Program<Multistake>,
35
+ provider?: AnchorProvider
36
+ ) {
37
+ this.program = program;
38
+ this.provider = provider || (program.provider as AnchorProvider);
39
+ }
40
+
41
+ /**
42
+ * 使用内置 IDL 创建 SDK 实例
43
+ */
44
+ static create(
45
+ provider: AnchorProvider
46
+ ): MultiStakeSDK {
47
+ const program = new Program(IDL as any, provider) as Program<Multistake>;
48
+ return new MultiStakeSDK(program, provider);
49
+ }
50
+
51
+ /**
52
+ * 获取 Program 实例
53
+ */
54
+ getProgram(): Program<Multistake> {
55
+ return this.program;
56
+ }
57
+
58
+ /**
59
+ * 获取 Provider 实例
60
+ */
61
+ getProvider(): AnchorProvider {
62
+ return this.provider;
63
+ }
64
+
65
+ /**
66
+ * 派生 Pool Authority PDA
67
+ */
68
+ derivePoolAuthority(pool: PublicKey): [PublicKey, number] {
69
+ return PublicKey.findProgramAddressSync(
70
+ [new TextEncoder().encode("anyswap_authority"), pool.toBytes()],
71
+ this.program.programId
72
+ );
73
+ }
74
+
75
+ /**
76
+ * 派生 Pool Vault PDA
77
+ */
78
+ derivePoolVault(pool: PublicKey): [PublicKey, number] {
79
+ return PublicKey.findProgramAddressSync(
80
+ [new TextEncoder().encode("pool_vault"), pool.toBytes()],
81
+ this.program.programId
82
+ );
83
+ }
84
+
85
+ /**
86
+ * 创建 Pool
87
+ * @param mainTokenMint 主币 mint 地址
88
+ * @param admin Pool 管理员
89
+ * @param payer 支付账户
90
+ * @param config Pool 配置
91
+ * @returns Pool 公钥和交易签名
92
+ */
93
+ async createPool(
94
+ mainTokenMint: PublicKey,
95
+ config: PoolConfig = { feeNumerator: 3, feeDenominator: 1000 }
96
+ ): Promise<{ pool: PublicKey; signature: string }> {
97
+ const pool = Keypair.generate();
98
+ const wallet = this.provider.publicKey;
99
+ const [poolAuthority] = this.derivePoolAuthority(pool.publicKey);
100
+ const [poolVault] = this.derivePoolVault(pool.publicKey);
101
+
102
+ const poolSize = 24704;
103
+ const lamports = await this.provider.connection.getMinimumBalanceForRentExemption(poolSize);
104
+
105
+ const createPoolAccountIx = SystemProgram.createAccount({
106
+ fromPubkey: wallet,
107
+ newAccountPubkey: pool.publicKey,
108
+ lamports,
109
+ space: poolSize,
110
+ programId: this.program.programId,
111
+ });
112
+
113
+ const signature = await this.program.methods
114
+ .createPool(new BN(config.feeNumerator), new BN(config.feeDenominator))
115
+ .accountsPartial({
116
+ pool: pool.publicKey,
117
+ poolAuthority,
118
+ mainTokenMint,
119
+ poolVault,
120
+ admin: wallet,
121
+ payer: wallet,
122
+ })
123
+ .preInstructions([createPoolAccountIx])
124
+ .signers([pool])
125
+ .rpc();
126
+
127
+ return { pool: pool.publicKey, signature };
128
+ }
129
+
130
+ /**
131
+ * 添加质押类型到 Pool
132
+ * @param pool Pool 公钥
133
+ * @returns LP mint 公钥和交易签名
134
+ */
135
+ async addTokenToPool(
136
+ pool: PublicKey
137
+ ): Promise<{ lpMint: PublicKey; signature: string }> {
138
+ const lpMint = Keypair.generate();
139
+ const wallet = this.provider.publicKey;
140
+ const [poolAuthority] = this.derivePoolAuthority(pool);
141
+
142
+ const signature = await this.program.methods
143
+ .addTokenToPool()
144
+ .accountsPartial({
145
+ pool,
146
+ poolAuthority,
147
+ lpMint: lpMint.publicKey,
148
+ admin: wallet,
149
+ payer: wallet,
150
+ })
151
+ .signers([lpMint])
152
+ .rpc();
153
+
154
+ return { lpMint: lpMint.publicKey, signature };
155
+ }
156
+
157
+ /**
158
+ * 从 Pool 移除质押类型
159
+ * @param pool Pool 公钥
160
+ * @param lpMint LP mint 公钥
161
+ * @param admin 管理员
162
+ * @returns 交易签名
163
+ */
164
+ async removeTokenFromPool(
165
+ pool: PublicKey,
166
+ lpMint: PublicKey,
167
+ admin: Keypair
168
+ ): Promise<string> {
169
+ const signature = await this.program.methods
170
+ .removeTokenFromPool()
171
+ .accounts({
172
+ pool,
173
+ lpMint,
174
+ admin: admin.publicKey,
175
+ })
176
+ .signers([admin])
177
+ .rpc();
178
+
179
+ return signature;
180
+ }
181
+
182
+ async modifyTokenWeight(
183
+ pool: PublicKey,
184
+ weights: BN[],
185
+ tokenMints: PublicKey[],
186
+ admin: Keypair
187
+ ): Promise<string> {
188
+ const signature = await this.program.methods
189
+ .modifyTokenWeight(weights)
190
+ .accounts({
191
+ pool,
192
+ admin: admin.publicKey,
193
+ })
194
+ .remainingAccounts(
195
+ tokenMints.map((mint) => ({
196
+ pubkey: mint,
197
+ isSigner: false,
198
+ isWritable: false,
199
+ }))
200
+ )
201
+ .signers([admin])
202
+ .rpc();
203
+
204
+ return signature;
205
+ }
206
+
207
+ /**
208
+ * 质押主币,铸造 LP 凭证
209
+ */
210
+ async stake(
211
+ pool: PublicKey,
212
+ itemIndex: number,
213
+ lpMint: PublicKey,
214
+ amount: BN
215
+ ): Promise<string> {
216
+ const wallet = this.provider.publicKey;
217
+ const [poolVault] = this.derivePoolVault(pool);
218
+
219
+ // Convert amount to BN with proper decimals (9 decimals for SOL/WSOL)
220
+ const amountBN = new BN(amount)
221
+
222
+ // Get pool info to get main token mint
223
+ const poolInfo = await this.getPoolInfo(pool);
224
+ const mainTokenMint = poolInfo.poolMint;
225
+
226
+ const userMainToken = await getAssociatedTokenAddress(mainTokenMint, wallet);
227
+
228
+ // Get or create user's LP token account
229
+ const userLpToken = await getAssociatedTokenAddress(lpMint, wallet);
230
+
231
+ // Check if accounts exist, if not, create them
232
+ const preInstructions = [];
233
+
234
+ // Check user main token account
235
+ const mainTokenAccountInfo = await this.provider.connection.getAccountInfo(userMainToken);
236
+ if (!mainTokenAccountInfo) {
237
+ preInstructions.push(
238
+ createAssociatedTokenAccountInstruction(
239
+ wallet,
240
+ userMainToken,
241
+ wallet,
242
+ mainTokenMint
243
+ )
244
+ );
245
+ }
246
+
247
+ // Check user LP token account
248
+ const lpTokenAccountInfo = await this.provider.connection.getAccountInfo(userLpToken);
249
+ if (!lpTokenAccountInfo) {
250
+ preInstructions.push(
251
+ createAssociatedTokenAccountInstruction(
252
+ wallet,
253
+ userLpToken,
254
+ wallet,
255
+ lpMint
256
+ )
257
+ );
258
+ }
259
+
260
+ const signature = await this.program.methods
261
+ .stake(itemIndex, amountBN)
262
+ .accountsPartial({
263
+ pool,
264
+ poolVault,
265
+ lpMint,
266
+ userMainToken,
267
+ userLpToken,
268
+ user: wallet,
269
+ })
270
+ .preInstructions(preInstructions)
271
+ .rpc();
272
+
273
+ return signature;
274
+ }
275
+
276
+ /**
277
+ * 销毁 LP 凭证,赎回主币
278
+ */
279
+ async unstake(
280
+ pool: PublicKey,
281
+ itemIndex: number,
282
+ lpMint: PublicKey,
283
+ lpAmount: BN
284
+ ): Promise<string> {
285
+ const wallet = this.provider.publicKey;
286
+ const [poolVault] = this.derivePoolVault(pool);
287
+
288
+ // Get pool info to get main token mint
289
+ const poolInfo = await this.getPoolInfo(pool);
290
+ const mainTokenMint = poolInfo.poolMint;
291
+
292
+ const userMainToken = await getAssociatedTokenAddress(
293
+ mainTokenMint,
294
+ wallet
295
+ );
296
+
297
+ const userLpToken = await getAssociatedTokenAddress(
298
+ lpMint,
299
+ wallet
300
+ );
301
+
302
+ const signature = await this.program.methods
303
+ .unstake(itemIndex, lpAmount)
304
+ .accountsPartial({
305
+ pool,
306
+ poolVault,
307
+ lpMint,
308
+ userLpToken,
309
+ userMainToken,
310
+ user: wallet,
311
+ })
312
+ .rpc();
313
+
314
+ return signature;
315
+ }
316
+
317
+ /**
318
+ * 获取 Pool 信息
319
+ */
320
+ async getPoolInfo(pool: PublicKey): Promise<PoolInfo & { items: TokenInfo[] }> {
321
+ const poolAccount = await this.program.account.pool.fetch(pool);
322
+ let poolItems: TokenInfo[] = [];
323
+ for (let i = 0; i < poolAccount.tokenCount; i++) {
324
+ const token = poolAccount.tokens[i];
325
+ if (token.mintAccount && token.mintAccount.toString() !== PublicKey.default.toString()) {
326
+ poolItems.push({
327
+ mintAccount: token.mintAccount,
328
+ mintAmount: token.mintAmount,
329
+ weight: token.weight
330
+ });
331
+ }
332
+ }
333
+ return {
334
+ admin: poolAccount.admin,
335
+ poolVault: poolAccount.poolVault,
336
+ poolMint: poolAccount.poolMint,
337
+ tokenCount: poolAccount.tokenCount,
338
+ feeNumerator: poolAccount.feeNumerator,
339
+ feeDenominator: poolAccount.feeDenominator,
340
+ items: poolItems,
341
+ };
342
+ }
343
+
344
+ /**
345
+ * 获取 Pool 中所有的 LP mint
346
+ */
347
+ async getPoolLpMints(pool: PublicKey): Promise<PublicKey[]> {
348
+ const poolInfo = await this.getPoolInfo(pool);
349
+ return poolInfo.items.map((item) => item.mintAccount);
350
+ }
351
+ }
352
+
353
+ export type { PoolInfo, TokenInfo };