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 +2 -7
- package/src/sdk.ts +353 -0
- package/src/types/multistake.ts +796 -0
- package/src/types.ts +35 -0
- package/dist/index.js +0 -2
- package/dist/sdk.d.ts +0 -88
- package/dist/sdk.js +0 -247
- package/dist/types/multistake.d.ts +0 -796
- package/dist/types/multistake.js +0 -1
- package/dist/types.d.ts +0 -49
- package/dist/types.js +0 -1
- /package/{dist/index.d.ts → src/index.ts} +0 -0
- /package/{dist → src}/multistake.json +0 -0
package/package.json
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "multistake",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "TypeScript SDK for MultiStake - Single Token Staking System",
|
|
5
|
-
"main": "
|
|
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 };
|