100x-sdk 1.0.1

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.
@@ -0,0 +1,455 @@
1
+ const { ComputeBudgetProgram, PublicKey, Transaction, Keypair, SystemProgram, SYSVAR_RENT_PUBKEY } = require('@solana/web3.js');
2
+ const { TOKEN_PROGRAM_ID, getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, ASSOCIATED_TOKEN_PROGRAM_ID } = require('@solana/spl-token');
3
+ const anchor = require('@coral-xyz/anchor');
4
+ // 统一使用 buffer 包,所有平台一致
5
+ const { Buffer } = require('buffer');
6
+
7
+ // Metaplex Token Metadata 程序ID
8
+ const METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
9
+
10
+ /**
11
+ * Token Module
12
+ * Handles token creation, queries, balance and other operations
13
+ */
14
+ class TokenModule {
15
+ constructor(sdk) {
16
+ this.sdk = sdk;
17
+ }
18
+
19
+ /**
20
+ * 创建新代币
21
+ * @param {Object} params - 创建参数
22
+ * @param {Keypair} params.mint - 代币mint keypair
23
+ * @param {string} params.name - 代币名称
24
+ * @param {string} params.symbol - 代币符号
25
+ * @param {string} params.uri - 元数据URI
26
+ * @param {PublicKey} params.payer - 创建者公钥(付款方)
27
+ *
28
+ * === 第二阶段新增:高级版池子可选参数(5个参数必须全部提供或全部不提供)===
29
+ * @param {anchor.BN} [params.customLpSol] - 自定义流动池SOL数量(lamports,9位精度)
30
+ * - 不传或传null:创建普通版池子,使用默认值30 SOL
31
+ * - 传入值:创建高级版池子,需在 10 SOL ~ 1000 SOL 范围内
32
+ * - ⚠️ 必须与其他4个 custom 参数同时提供
33
+ *
34
+ * @param {anchor.BN} [params.customLpToken] - 自定义流动池Token数量(最小单位,9位精度)
35
+ * - 不传或传null:使用默认值10.73亿 Token
36
+ * - 传入值:需在 1亿 ~ 100亿 Token 范围内
37
+ *
38
+ * @param {number} [params.customBorrowRatio] - 自定义借贷池代币占比(5-30表示5%-30%)
39
+ * - 不传或传null:使用默认值20%
40
+ * - 传入值:需在 5 ~ 30 范围内
41
+ *
42
+ * @param {number} [params.customBorrowDuration] - 自定义借贷时长(秒)
43
+ * - 不传或传null:使用Params账户配置的默认值
44
+ * - 传入值:需在 3天(259200秒) ~ 6个月(15552000秒) 范围内
45
+ *
46
+ * @param {number} [params.customFee] - 自定义手续费率(单位:基点 basis points)
47
+ * - 不传或传null:使用Params账户配置的默认手续费
48
+ * - 传入值:需在 1000 ~ 5000 范围内(表示 1% ~ 5%)
49
+ * - 示例:2000 表示 2%
50
+ * - 借贷手续费会自动上浮20%(如设置2000,则 swap_fee=2000,borrow_fee=2400)
51
+ *
52
+ * @returns {Promise<Object>} 包含transaction、signers和账户信息的对象
53
+ *
54
+ * @example
55
+ * // 创建普通版代币(使用默认参数)
56
+ * const result = await sdk.token.create({
57
+ * mint: mintKeypair,
58
+ * name: "My Token",
59
+ * symbol: "MTK",
60
+ * uri: "https://example.com/metadata.json",
61
+ * payer: wallet.publicKey
62
+ * });
63
+ *
64
+ * @example
65
+ * // 创建高级版代币(自定义流动池参数,必须提供全部5个参数)
66
+ * const anchor = require('@coral-xyz/anchor');
67
+ * const result = await sdk.token.create({
68
+ * mint: mintKeypair,
69
+ * name: "Advanced Token",
70
+ * symbol: "ADV",
71
+ * uri: "https://example.com/metadata.json",
72
+ * payer: wallet.publicKey,
73
+ * customLpSol: new anchor.BN('60000000000'), // 60 SOL
74
+ * customLpToken: new anchor.BN('1073000000000000000'), // 10.73亿 Token
75
+ * customBorrowRatio: 15, // 15%
76
+ * customBorrowDuration: 7 * 24 * 3600, // 7天
77
+ * customFee: 2000 // 2% (2000 basis points)
78
+ * });
79
+ */
80
+ async create({
81
+ mint,
82
+ name,
83
+ symbol,
84
+ uri,
85
+ payer,
86
+ // 高级版池子可选参数(5个参数必须全部提供或全部不提供)
87
+ customLpSol = null,
88
+ customLpToken = null,
89
+ customBorrowRatio = null,
90
+ customBorrowDuration = null,
91
+ customFee = null
92
+ }) {
93
+ console.log('Token Module - Create:', {
94
+ mint: mint.publicKey.toString(),
95
+ name,
96
+ symbol,
97
+ uri,
98
+ payer: payer.toString(),
99
+ // 高级版池子参数日志
100
+ poolType: (customLpSol === null && customLpToken === null &&
101
+ customBorrowRatio === null && customBorrowDuration === null &&
102
+ customFee === null)
103
+ ? 'Standard (default params)'
104
+ : 'Advanced (custom params)',
105
+ customLpSol: customLpSol?.toString() || 'null',
106
+ customLpToken: customLpToken?.toString() || 'null',
107
+ customBorrowRatio: customBorrowRatio ?? 'null',
108
+ customBorrowDuration: customBorrowDuration ?? 'null',
109
+ customFee: customFee ?? 'null'
110
+ });
111
+
112
+ // Calculate borrowing liquidity pool account address (borrowing_curve)
113
+ const [curveAccount] = PublicKey.findProgramAddressSync(
114
+ [
115
+ Buffer.from("borrowing_curve"),
116
+ mint.publicKey.toBuffer(),
117
+ ],
118
+ this.sdk.programId
119
+ );
120
+
121
+ // Calculate liquidity pool token account address (pool_token)
122
+ const [poolTokenAccount] = PublicKey.findProgramAddressSync(
123
+ [
124
+ Buffer.from("pool_token"),
125
+ mint.publicKey.toBuffer(),
126
+ ],
127
+ this.sdk.programId
128
+ );
129
+
130
+ // Calculate liquidity pool SOL account address (pool_sol)
131
+ const [poolSolAccount] = PublicKey.findProgramAddressSync(
132
+ [
133
+ Buffer.from("pool_sol"),
134
+ mint.publicKey.toBuffer(),
135
+ ],
136
+ this.sdk.programId
137
+ );
138
+
139
+ // Calculate order book accounts (new)
140
+ const [upOrderbook] = PublicKey.findProgramAddressSync(
141
+ [
142
+ Buffer.from("up_orderbook"),
143
+ mint.publicKey.toBuffer(),
144
+ ],
145
+ this.sdk.programId
146
+ );
147
+
148
+ const [downOrderbook] = PublicKey.findProgramAddressSync(
149
+ [
150
+ Buffer.from("down_orderbook"),
151
+ mint.publicKey.toBuffer(),
152
+ ],
153
+ this.sdk.programId
154
+ );
155
+
156
+ // Calculate Metaplex metadata account address
157
+ const [metadataAccount] = PublicKey.findProgramAddressSync(
158
+ [
159
+ Buffer.from("metadata"),
160
+ METADATA_PROGRAM_ID.toBuffer(),
161
+ mint.publicKey.toBuffer(),
162
+ ],
163
+ METADATA_PROGRAM_ID
164
+ );
165
+
166
+ console.log('Calculated account addresses:');
167
+ console.log(' Borrowing liquidity pool account:', curveAccount.toString());
168
+ console.log(' Liquidity pool token account:', poolTokenAccount.toString());
169
+ console.log(' Liquidity pool SOL account:', poolSolAccount.toString());
170
+ console.log(' Up orderbook:', upOrderbook.toString());
171
+ console.log(' Down orderbook:', downOrderbook.toString());
172
+ console.log(' Metadata account:', metadataAccount.toString());
173
+ console.log(' Params account:', this.sdk.paramsAccount?.toString() || 'Not set');
174
+
175
+ // Validate required configuration
176
+ if (!this.sdk.paramsAccount) {
177
+ throw new Error('SDK paramsAccount not configured, please provide paramsAccount configuration during initialization');
178
+ }
179
+
180
+ // Create compute budget instruction
181
+ const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
182
+ units: 400000
183
+ });
184
+
185
+ // 构建创建代币指令(传入5个自定义参数)
186
+ const createIx = await this.sdk.program.methods
187
+ .createToken(
188
+ name,
189
+ symbol,
190
+ uri,
191
+ customLpSol, // Option<u64>
192
+ customLpToken, // Option<u64>
193
+ customBorrowRatio, // Option<u8>
194
+ customBorrowDuration, // Option<u32>
195
+ customFee // Option<u16> - 新增参数
196
+ )
197
+ .accounts({
198
+ payer: payer,
199
+ mintAccount: mint.publicKey,
200
+ curveAccount: curveAccount,
201
+ poolTokenAccount: poolTokenAccount,
202
+ poolSolAccount: poolSolAccount,
203
+ upOrderbook: upOrderbook,
204
+ downOrderbook: downOrderbook,
205
+ metadata: metadataAccount,
206
+ metadataProgram: METADATA_PROGRAM_ID,
207
+ params: this.sdk.paramsAccount,
208
+ tokenProgram: TOKEN_PROGRAM_ID,
209
+ systemProgram: SystemProgram.programId,
210
+ rent: SYSVAR_RENT_PUBKEY,
211
+ })
212
+ .instruction();
213
+
214
+ // Create transaction and add instructions
215
+ const transaction = new Transaction();
216
+ transaction.add(modifyComputeUnits);
217
+ transaction.add(createIx);
218
+
219
+ console.log('Token creation transaction built, signers required:', [payer.toString(), mint.publicKey.toString()]);
220
+
221
+ return {
222
+ transaction,
223
+ signers: [mint], // mint keypair needs to be a signer
224
+ accounts: {
225
+ mint: mint.publicKey,
226
+ curveAccount,
227
+ poolTokenAccount,
228
+ poolSolAccount,
229
+ upOrderbook,
230
+ downOrderbook,
231
+ metadataAccount,
232
+ payer
233
+ }
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Create token and buy in one transaction
239
+ * 将 create 和 buy 两个指令合并到一个交易中,一次签名提交
240
+ *
241
+ * @param {Object} params - Creation and buy parameters
242
+ * @param {Keypair} params.mint - Token mint keypair
243
+ * @param {string} params.name - Token name
244
+ * @param {string} params.symbol - Token symbol
245
+ * @param {string} params.uri - Metadata URI
246
+ * @param {PublicKey} params.payer - Creator public key (payer)
247
+ * @param {anchor.BN} params.buyTokenAmount - Amount of tokens to buy
248
+ * @param {anchor.BN} params.maxSolAmount - Maximum SOL to spend
249
+ *
250
+ * === 第二阶段新增:高级版池子可选参数(5个参数必须全部提供或全部不提供)===
251
+ * @param {anchor.BN} [params.customLpSol] - 自定义流动池SOL数量(lamports,9位精度)
252
+ * @param {anchor.BN} [params.customLpToken] - 自定义流动池Token数量(最小单位,9位精度)
253
+ * @param {number} [params.customBorrowRatio] - 自定义借贷池代币占比(5-30表示5%-30%)
254
+ * @param {number} [params.customBorrowDuration] - 自定义借贷时长(秒)
255
+ * @param {number} [params.customFee] - 自定义手续费率(1000-5000 basis points,表示1%-5%)
256
+ *
257
+ * @param {Object} options - Optional parameters
258
+ * @param {number} options.computeUnits - Compute units limit, default 1800000
259
+ * @returns {Promise<Object>} Object containing transaction, signers and account info
260
+ */
261
+ async createAndBuy({
262
+ mint,
263
+ name,
264
+ symbol,
265
+ uri,
266
+ payer,
267
+ buyTokenAmount,
268
+ maxSolAmount,
269
+ // 高级版池子可选参数(5个参数必须全部提供或全部不提供)
270
+ customLpSol = null,
271
+ customLpToken = null,
272
+ customBorrowRatio = null,
273
+ customBorrowDuration = null,
274
+ customFee = null
275
+ }, options = {}) {
276
+ const { computeUnits = 1800000 } = options;
277
+
278
+ console.log('Token Module - CreateAndBuy:', {
279
+ mint: mint.publicKey.toString(),
280
+ name,
281
+ symbol,
282
+ uri,
283
+ payer: payer.toString(),
284
+ buyTokenAmount: buyTokenAmount.toString(),
285
+ maxSolAmount: maxSolAmount.toString()
286
+ });
287
+
288
+ // 1. 参数验证
289
+ if (!anchor.BN.isBN(buyTokenAmount) || !anchor.BN.isBN(maxSolAmount)) {
290
+ throw new Error('buyTokenAmount and maxSolAmount must be anchor.BN type');
291
+ }
292
+
293
+ // 2. 调用 create 方法获取 create 交易(传递所有自定义参数)
294
+ console.log('Step 1: Building create transaction...');
295
+ const createResult = await this.create({
296
+ mint,
297
+ name,
298
+ symbol,
299
+ uri,
300
+ payer,
301
+ // 传递自定义流动池参数(5个参数)
302
+ customLpSol,
303
+ customLpToken,
304
+ customBorrowRatio,
305
+ customBorrowDuration,
306
+ customFee
307
+ });
308
+
309
+ // 3. 从 params 账户读取手续费接收地址
310
+ // 因为此时 curve_account 还未创建,无法从链上读取
311
+ console.log('Step 2: Fetching fee recipient accounts from params...');
312
+
313
+ // 直接从 SDK 配置中获取手续费接收账户(这些在 SDK 初始化时已经设置)
314
+ // 避免使用 program.account.params.fetch() 因为可能有 provider 配置问题
315
+ const feeRecipientAccount = this.sdk.feeRecipient;
316
+ const baseFeeRecipientAccount = this.sdk.baseFeeRecipient;
317
+
318
+ // 验证这些账户已配置
319
+ if (!feeRecipientAccount || !baseFeeRecipientAccount) {
320
+ throw new Error('Fee recipient accounts not configured in SDK options');
321
+ }
322
+
323
+ console.log('Fee recipient accounts:');
324
+ console.log(' Partner fee recipient:', feeRecipientAccount.toString());
325
+ console.log(' Base fee recipient:', baseFeeRecipientAccount.toString());
326
+
327
+ // 4. 准备 buy 所需的额外账户
328
+ console.log('Step 3: Calculating buy-related accounts...');
329
+ const mintPubkey = mint.publicKey;
330
+
331
+ // 计算用户代币账户
332
+ const userTokenAccount = await getAssociatedTokenAddress(
333
+ mintPubkey,
334
+ payer
335
+ );
336
+
337
+ // 计算 cooldown PDA
338
+ const [cooldownPDA] = PublicKey.findProgramAddressSync(
339
+ [
340
+ Buffer.from('trade_cooldown'),
341
+ mintPubkey.toBuffer(),
342
+ payer.toBuffer()
343
+ ],
344
+ this.sdk.programId
345
+ );
346
+
347
+ // 计算 orderbook PDAs (复用 create 中计算的值)
348
+ const [upOrderbook] = PublicKey.findProgramAddressSync(
349
+ [Buffer.from('up_orderbook'), mintPubkey.toBuffer()],
350
+ this.sdk.programId
351
+ );
352
+
353
+ const [downOrderbook] = PublicKey.findProgramAddressSync(
354
+ [Buffer.from('down_orderbook'), mintPubkey.toBuffer()],
355
+ this.sdk.programId
356
+ );
357
+
358
+ console.log('Buy-related accounts:');
359
+ console.log(' User token account:', userTokenAccount.toString());
360
+ console.log(' Cooldown PDA:', cooldownPDA.toString());
361
+
362
+ // 5. 检查用户代币账户是否存在,创建 ATA 指令
363
+ console.log('Step 4: Checking if user token account exists...');
364
+ const userTokenAccountInfo = await this.sdk.connection.getAccountInfo(userTokenAccount);
365
+ const createAtaIx = userTokenAccountInfo === null
366
+ ? createAssociatedTokenAccountInstruction(
367
+ payer,
368
+ userTokenAccount,
369
+ payer,
370
+ mintPubkey,
371
+ TOKEN_PROGRAM_ID,
372
+ ASSOCIATED_TOKEN_PROGRAM_ID
373
+ )
374
+ : null;
375
+
376
+ if (createAtaIx) {
377
+ console.log(' User token account does not exist, will create it');
378
+ } else {
379
+ console.log(' User token account already exists');
380
+ }
381
+
382
+ // 6. 构建 buy 指令
383
+ console.log('Step 5: Building buy instruction...');
384
+ const buyIx = await this.sdk.program.methods
385
+ .buy(buyTokenAmount, maxSolAmount)
386
+ .accounts({
387
+ payer: payer,
388
+ mintAccount: mintPubkey,
389
+ curveAccount: createResult.accounts.curveAccount,
390
+ poolTokenAccount: createResult.accounts.poolTokenAccount,
391
+ poolSolAccount: createResult.accounts.poolSolAccount,
392
+ upOrderbook: upOrderbook,
393
+ downOrderbook: downOrderbook,
394
+ userTokenAccount: userTokenAccount,
395
+ tokenProgram: TOKEN_PROGRAM_ID,
396
+ systemProgram: SystemProgram.programId,
397
+ rent: SYSVAR_RENT_PUBKEY,
398
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
399
+ feeRecipientAccount: feeRecipientAccount,
400
+ baseFeeRecipientAccount: baseFeeRecipientAccount,
401
+ cooldown: cooldownPDA
402
+ })
403
+ .instruction();
404
+
405
+ // 7. 合并交易:create + buy
406
+ console.log('Step 6: Merging create and buy transactions...');
407
+ const transaction = new Transaction();
408
+
409
+ // 设置计算单元限制
410
+ const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
411
+ units: computeUnits
412
+ });
413
+ transaction.add(modifyComputeUnits);
414
+
415
+ // 添加 create 交易的所有指令(跳过 create 中的计算单元指令)
416
+ createResult.transaction.instructions.forEach(ix => {
417
+ // 跳过 create 交易中的计算单元指令(我们已经添加了)
418
+ if (ix.programId.equals(ComputeBudgetProgram.programId)) {
419
+ return;
420
+ }
421
+ transaction.add(ix);
422
+ });
423
+
424
+ // 添加 ATA 创建指令(如果需要)
425
+ if (createAtaIx) {
426
+ transaction.add(createAtaIx);
427
+ }
428
+
429
+ // 添加 buy 指令
430
+ transaction.add(buyIx);
431
+
432
+ console.log('CreateAndBuy transaction built successfully:');
433
+ console.log(' Total instructions:', transaction.instructions.length);
434
+ console.log(' Compute units:', computeUnits);
435
+ console.log(' Signers required:', [payer.toString(), mint.publicKey.toString()]);
436
+
437
+ // 8. 返回合并后的交易
438
+ return {
439
+ transaction,
440
+ signers: [mint], // mint keypair 需要签名
441
+ accounts: {
442
+ // create 的账户
443
+ ...createResult.accounts,
444
+ // buy 的账户
445
+ userTokenAccount,
446
+ cooldown: cooldownPDA,
447
+ feeRecipientAccount,
448
+ baseFeeRecipientAccount
449
+ }
450
+ };
451
+ }
452
+
453
+ }
454
+
455
+ module.exports = TokenModule;