pump-trader 1.1.5 → 1.1.8

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/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  TransactionInstruction,
6
6
  SystemProgram,
7
7
  ComputeBudgetProgram,
8
- Keypair
8
+ Keypair,
9
9
  } from "@solana/web3.js";
10
10
 
11
11
  import {
@@ -17,7 +17,7 @@ import {
17
17
  getTokenMetadata,
18
18
  TOKEN_2022_PROGRAM_ID,
19
19
  TOKEN_PROGRAM_ID,
20
- getMint
20
+ getMint,
21
21
  } from "@solana/spl-token";
22
22
 
23
23
  import BN from "bn.js";
@@ -30,28 +30,30 @@ const PROGRAM_IDS = {
30
30
  PUMP_AMM: new PublicKey("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"),
31
31
  METADATA: new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
32
32
  FEE: new PublicKey("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ"),
33
- EVENT_AUTHORITY: new PublicKey("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1")
33
+ EVENT_AUTHORITY: new PublicKey(
34
+ "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1",
35
+ ),
34
36
  };
35
37
 
36
38
  const SOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
37
39
 
38
40
  const SEEDS = {
39
41
  FEE_CONFIG: new Uint8Array([
40
- 1, 86, 224, 246, 147, 102, 90, 207, 68, 219, 21, 104, 191, 23, 91, 170,
41
- 81, 137, 203, 151, 245, 210, 255, 59, 101, 93, 43, 182, 253, 109, 24, 176
42
+ 1, 86, 224, 246, 147, 102, 90, 207, 68, 219, 21, 104, 191, 23, 91, 170, 81,
43
+ 137, 203, 151, 245, 210, 255, 59, 101, 93, 43, 182, 253, 109, 24, 176,
42
44
  ]),
43
45
  AMM_FEE_CONFIG: Buffer.from([
44
- 12, 20, 222, 252, 130, 94, 198, 118, 148, 37, 8, 24, 187, 101, 64, 101,
45
- 244, 41, 141, 49, 86, 213, 113, 180, 212, 248, 9, 12, 24, 233, 168, 99
46
+ 12, 20, 222, 252, 130, 94, 198, 118, 148, 37, 8, 24, 187, 101, 64, 101, 244,
47
+ 41, 141, 49, 86, 213, 113, 180, 212, 248, 9, 12, 24, 233, 168, 99,
46
48
  ]),
47
49
  GLOBAL: Buffer.from("global"),
48
- BONDING: Buffer.from("bonding-curve")
50
+ BONDING: Buffer.from("bonding-curve"),
49
51
  };
50
52
 
51
53
  const DISCRIMINATORS = {
52
54
  BUY: Buffer.from([102, 6, 61, 18, 1, 218, 235, 234]),
53
55
  SELL: Buffer.from([51, 230, 133, 164, 1, 127, 131, 173]),
54
- TRADE_EVENT: Buffer.from([189, 219, 127, 211, 78, 230, 97, 238])
56
+ TRADE_EVENT: Buffer.from([189, 219, 127, 211, 78, 230, 97, 238]),
55
57
  };
56
58
 
57
59
  const AMM_FEE_BPS = 100n; // 1%
@@ -64,7 +66,7 @@ const PUMP_NEW_FEE_RECIPIENTS = [
64
66
  "5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6",
65
67
  "EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL",
66
68
  "5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD",
67
- "A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"
69
+ "A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW",
68
70
  ].map((value) => new PublicKey(value));
69
71
 
70
72
  /* ================= 工具函数 ================= */
@@ -84,7 +86,9 @@ const readU32 = (buf, offsetObj) => {
84
86
 
85
87
  const readString = (buf, offsetObj) => {
86
88
  const len = readU32(buf, offsetObj);
87
- const str = buf.slice(offsetObj.offset, offsetObj.offset + len).toString("utf8");
89
+ const str = buf
90
+ .slice(offsetObj.offset, offsetObj.offset + len)
91
+ .toString("utf8");
88
92
  offsetObj.offset += len;
89
93
  return str;
90
94
  };
@@ -94,10 +98,14 @@ const readString = (buf, offsetObj) => {
94
98
  function parseMetadataAccount(data) {
95
99
  const offsetObj = { offset: 1 }; // 跳过 key
96
100
 
97
- const updateAuthority = new PublicKey(data.slice(offsetObj.offset, offsetObj.offset + 32));
101
+ const updateAuthority = new PublicKey(
102
+ data.slice(offsetObj.offset, offsetObj.offset + 32),
103
+ );
98
104
  offsetObj.offset += 32;
99
105
 
100
- const mint = new PublicKey(data.slice(offsetObj.offset, offsetObj.offset + 32));
106
+ const mint = new PublicKey(
107
+ data.slice(offsetObj.offset, offsetObj.offset + 32),
108
+ );
101
109
  offsetObj.offset += 32;
102
110
 
103
111
  const name = readString(data, offsetObj);
@@ -109,13 +117,13 @@ function parseMetadataAccount(data) {
109
117
  mint: mint.toBase58(),
110
118
  name,
111
119
  symbol,
112
- uri
120
+ uri,
113
121
  };
114
122
  }
115
123
 
116
124
  function parsePoolKeys(data) {
117
125
  if (!data || data.length < 280) {
118
- throw new Error('Invalid pool account data');
126
+ throw new Error("Invalid pool account data");
119
127
  }
120
128
 
121
129
  let offset = 8; // 跳过 discriminator
@@ -152,7 +160,8 @@ function parsePoolKeys(data) {
152
160
 
153
161
  const isMayhemMode = data.readUInt8(offset) === 1;
154
162
  offset += 1;
155
- const isCashbackCoin = offset < data.length ? data.readUInt8(offset) === 1 : false;
163
+ const isCashbackCoin =
164
+ offset < data.length ? data.readUInt8(offset) === 1 : false;
156
165
 
157
166
  return {
158
167
  creator,
@@ -163,7 +172,7 @@ function parsePoolKeys(data) {
163
172
  poolQuoteTokenAccount,
164
173
  coinCreator,
165
174
  isMayhemMode,
166
- isCashbackCoin
175
+ isCashbackCoin,
167
176
  };
168
177
  }
169
178
 
@@ -173,7 +182,10 @@ export class PumpTrader {
173
182
  constructor(rpc, privateKey) {
174
183
  this.connection = new Connection(rpc, "confirmed");
175
184
  this.wallet = Keypair.fromSecretKey(bs58.decode(privateKey));
176
- this.global = PublicKey.findProgramAddressSync([SEEDS.GLOBAL], PROGRAM_IDS.PUMP)[0];
185
+ this.global = PublicKey.findProgramAddressSync(
186
+ [SEEDS.GLOBAL],
187
+ PROGRAM_IDS.PUMP,
188
+ )[0];
177
189
  this.globalState = null;
178
190
  this.tokenProgramCache = new Map(); // 缓存token program检测结果
179
191
  }
@@ -195,29 +207,59 @@ export class PumpTrader {
195
207
 
196
208
  try {
197
209
  // 首先尝试获取 TOKEN_2022 的代币信息
198
- const mintData = await getMint(this.connection, mint, "confirmed", TOKEN_2022_PROGRAM_ID);
210
+ const mintData = await getMint(
211
+ this.connection,
212
+ mint,
213
+ "confirmed",
214
+ TOKEN_2022_PROGRAM_ID,
215
+ );
199
216
  const result = {
200
217
  type: "TOKEN_2022_PROGRAM_ID",
201
- programId: TOKEN_2022_PROGRAM_ID
218
+ programId: TOKEN_2022_PROGRAM_ID,
202
219
  };
203
220
  this.tokenProgramCache.set(tokenAddr, result);
204
221
  return result;
205
222
  } catch (e) {
206
223
  try {
207
224
  // 如果失败,尝试标准 TOKEN_PROGRAM_ID
208
- const mintData = await getMint(this.connection, mint, "confirmed", TOKEN_PROGRAM_ID);
225
+ const mintData = await getMint(
226
+ this.connection,
227
+ mint,
228
+ "confirmed",
229
+ TOKEN_PROGRAM_ID,
230
+ );
209
231
  const result = {
210
232
  type: "TOKEN_PROGRAM_ID",
211
- programId: TOKEN_PROGRAM_ID
233
+ programId: TOKEN_PROGRAM_ID,
212
234
  };
213
235
  this.tokenProgramCache.set(tokenAddr, result);
214
236
  return result;
215
237
  } catch (error) {
216
- throw new Error(`Failed to detect token program for ${tokenAddr}: ${error}`);
238
+ throw new Error(
239
+ `Failed to detect token program for ${tokenAddr}: ${error}`,
240
+ );
217
241
  }
218
242
  }
219
243
  }
220
244
 
245
+ async detectQuoteTokenProgram(quoteMint) {
246
+ const quoteAddr = quoteMint.toBase58();
247
+ if (this.tokenProgramCache.has(quoteAddr)) {
248
+ return this.tokenProgramCache.get(quoteAddr).programId;
249
+ }
250
+ try {
251
+ await getMint(
252
+ this.connection,
253
+ quoteMint,
254
+ "confirmed",
255
+ TOKEN_2022_PROGRAM_ID,
256
+ );
257
+ return TOKEN_2022_PROGRAM_ID;
258
+ } catch {
259
+ return TOKEN_PROGRAM_ID;
260
+ }
261
+ }
262
+
221
263
  /* ---------- 内盘/外盘检测 ---------- */
222
264
 
223
265
  /**
@@ -282,7 +324,7 @@ export class PumpTrader {
282
324
  initialVirtualSolReserves: readU64(),
283
325
  initialRealTokenReserves: readU64(),
284
326
  tokenTotalSupply: readU64(),
285
- feeBasisPoints: readU64()
327
+ feeBasisPoints: readU64(),
286
328
  };
287
329
 
288
330
  return this.globalState;
@@ -293,14 +335,14 @@ export class PumpTrader {
293
335
  getBondingPda(mint) {
294
336
  return PublicKey.findProgramAddressSync(
295
337
  [SEEDS.BONDING, mint.toBuffer()],
296
- PROGRAM_IDS.PUMP
338
+ PROGRAM_IDS.PUMP,
297
339
  )[0];
298
340
  }
299
341
 
300
342
  deriveBondingCurveV2(mint) {
301
343
  return PublicKey.findProgramAddressSync(
302
344
  [Buffer.from("bonding-curve-v2"), mint.toBuffer()],
303
- PROGRAM_IDS.PUMP
345
+ PROGRAM_IDS.PUMP,
304
346
  )[0];
305
347
  }
306
348
 
@@ -316,7 +358,11 @@ export class PumpTrader {
316
358
  { pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
317
359
  { pubkey: args.mint, isSigner: false, isWritable: false },
318
360
  { pubkey: args.bonding, isSigner: false, isWritable: true },
319
- { pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
361
+ {
362
+ pubkey: args.associatedBondingCurve,
363
+ isSigner: false,
364
+ isWritable: true,
365
+ },
320
366
  { pubkey: args.userAta, isSigner: false, isWritable: true },
321
367
  { pubkey: args.wallet, isSigner: true, isWritable: true },
322
368
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
@@ -324,12 +370,16 @@ export class PumpTrader {
324
370
  { pubkey: args.creatorVault, isSigner: false, isWritable: true },
325
371
  { pubkey: args.eventAuthority, isSigner: false, isWritable: false },
326
372
  { pubkey: args.pumpProgram, isSigner: false, isWritable: false },
327
- { pubkey: args.globalVolumeAccumulator, isSigner: false, isWritable: false },
373
+ {
374
+ pubkey: args.globalVolumeAccumulator,
375
+ isSigner: false,
376
+ isWritable: false,
377
+ },
328
378
  { pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true },
329
379
  { pubkey: args.feeConfig, isSigner: false, isWritable: false },
330
380
  { pubkey: args.feeProgram, isSigner: false, isWritable: false },
331
381
  { pubkey: args.bondingCurveV2, isSigner: false, isWritable: false },
332
- { pubkey: args.feeRecipient, isSigner: false, isWritable: true }
382
+ { pubkey: args.feeRecipient, isSigner: false, isWritable: true },
333
383
  ];
334
384
  }
335
385
 
@@ -340,7 +390,11 @@ export class PumpTrader {
340
390
  { pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
341
391
  { pubkey: args.mint, isSigner: false, isWritable: false },
342
392
  { pubkey: args.bonding, isSigner: false, isWritable: true },
343
- { pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
393
+ {
394
+ pubkey: args.associatedBondingCurve,
395
+ isSigner: false,
396
+ isWritable: true,
397
+ },
344
398
  { pubkey: args.userAta, isSigner: false, isWritable: true },
345
399
  { pubkey: args.wallet, isSigner: true, isWritable: true },
346
400
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
@@ -349,16 +403,20 @@ export class PumpTrader {
349
403
  { pubkey: args.eventAuthority, isSigner: false, isWritable: false },
350
404
  { pubkey: args.pumpProgram, isSigner: false, isWritable: false },
351
405
  { pubkey: args.feeConfig, isSigner: false, isWritable: false },
352
- { pubkey: args.feeProgram, isSigner: false, isWritable: false }
406
+ { pubkey: args.feeProgram, isSigner: false, isWritable: false },
353
407
  ];
354
408
 
355
409
  if (args.isCashbackCoin) {
356
- keys.push({ pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true });
410
+ keys.push({
411
+ pubkey: args.userVolumeAccumulator,
412
+ isSigner: false,
413
+ isWritable: true,
414
+ });
357
415
  }
358
416
 
359
417
  keys.push(
360
418
  { pubkey: args.bondingCurveV2, isSigner: false, isWritable: false },
361
- { pubkey: args.feeRecipient, isSigner: false, isWritable: true }
419
+ { pubkey: args.feeRecipient, isSigner: false, isWritable: true },
362
420
  );
363
421
 
364
422
  return keys;
@@ -383,12 +441,6 @@ export class PumpTrader {
383
441
 
384
442
  const creator = new PublicKey(data.slice(offset, offset + 32));
385
443
  offset += 32;
386
-
387
- if (offset + 32 <= data.length - 2) {
388
- state.quoteMint = new PublicKey(data.slice(offset, offset + 32));
389
- offset += 32;
390
- }
391
-
392
444
  state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
393
445
  offset += 1;
394
446
  state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
@@ -400,25 +452,29 @@ export class PumpTrader {
400
452
 
401
453
  calcBuy(solIn, state) {
402
454
  const newVirtualSol = state.virtualSolReserves + solIn;
403
- const newVirtualToken = (state.virtualSolReserves * state.virtualTokenReserves) / newVirtualSol;
455
+ const newVirtualToken =
456
+ (state.virtualSolReserves * state.virtualTokenReserves) / newVirtualSol;
404
457
  return state.virtualTokenReserves - newVirtualToken;
405
458
  }
406
459
 
407
460
  calcSell(tokenIn, state) {
408
461
  const newVirtualToken = state.virtualTokenReserves + tokenIn;
409
- const newVirtualSol = (state.virtualSolReserves * state.virtualTokenReserves) / newVirtualToken;
462
+ const newVirtualSol =
463
+ (state.virtualSolReserves * state.virtualTokenReserves) / newVirtualToken;
410
464
  return state.virtualSolReserves - newVirtualSol;
411
465
  }
412
466
 
413
467
  calculateAmmBuyOutput(quoteIn, reserves) {
414
- const quoteInAfterFee = (quoteIn * (BPS_DENOMINATOR - AMM_FEE_BPS)) / BPS_DENOMINATOR;
468
+ const quoteInAfterFee =
469
+ (quoteIn * (BPS_DENOMINATOR - AMM_FEE_BPS)) / BPS_DENOMINATOR;
415
470
  const numerator = reserves.baseAmount * quoteInAfterFee;
416
471
  const denominator = reserves.quoteAmount + quoteInAfterFee;
417
472
  return numerator / denominator;
418
473
  }
419
474
 
420
475
  calculateAmmSellOutput(baseIn, reserves) {
421
- const baseInAfterFee = (baseIn * (BPS_DENOMINATOR - AMM_FEE_BPS)) / BPS_DENOMINATOR;
476
+ const baseInAfterFee =
477
+ (baseIn * (BPS_DENOMINATOR - AMM_FEE_BPS)) / BPS_DENOMINATOR;
422
478
  const numerator = reserves.quoteAmount * baseInAfterFee;
423
479
  const denominator = reserves.baseAmount + baseInAfterFee;
424
480
  return numerator / denominator;
@@ -429,30 +485,34 @@ export class PumpTrader {
429
485
  async getPriceAndStatus(tokenAddr) {
430
486
  const mint = new PublicKey(tokenAddr);
431
487
  const { state } = await this.loadBonding(mint);
432
- const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
433
488
 
434
489
  if (state.complete) {
435
- const price = await this.getAmmPrice(mint, quoteMint);
490
+ const price = await this.getAmmPrice(mint);
436
491
  return { price, completed: true };
437
492
  }
438
493
 
439
494
  const oneToken = BigInt(1_000_000);
440
- const quoteOut = this.calcSell(oneToken, state);
441
- const quoteDecimals = await this.getMintDecimals(quoteMint);
442
- const price = Number(quoteOut) / 10 ** quoteDecimals;
495
+ const solOut = this.calcSell(oneToken, state);
496
+ const price = Number(solOut) / 1e9;
443
497
  return { price, completed: false };
444
498
  }
445
499
 
446
- async getAmmPrice(mint, quoteMint = SOL_MINT) {
500
+ async getAmmPrice(mint) {
447
501
  const [poolCreator] = PublicKey.findProgramAddressSync(
448
502
  [Buffer.from("pool-authority"), mint.toBuffer()],
449
- PROGRAM_IDS.PUMP
503
+ PROGRAM_IDS.PUMP,
450
504
  );
451
505
 
452
506
  const indexBuffer = new BN(0).toArrayLike(Buffer, "le", 2);
453
507
  const [pool] = PublicKey.findProgramAddressSync(
454
- [Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), quoteMint.toBuffer()],
455
- PROGRAM_IDS.PUMP_AMM
508
+ [
509
+ Buffer.from("pool"),
510
+ indexBuffer,
511
+ poolCreator.toBuffer(),
512
+ mint.toBuffer(),
513
+ SOL_MINT.toBuffer(),
514
+ ],
515
+ PROGRAM_IDS.PUMP_AMM,
456
516
  );
457
517
 
458
518
  const acc = await this.connection.getAccountInfo(pool);
@@ -461,34 +521,12 @@ export class PumpTrader {
461
521
  const poolKeys = parsePoolKeys(acc.data);
462
522
  const [baseInfo, quoteInfo] = await Promise.all([
463
523
  this.connection.getTokenAccountBalance(poolKeys.poolBaseTokenAccount),
464
- this.connection.getTokenAccountBalance(poolKeys.poolQuoteTokenAccount)
524
+ this.connection.getTokenAccountBalance(poolKeys.poolQuoteTokenAccount),
465
525
  ]);
466
526
 
467
527
  return quoteInfo.value.uiAmount / baseInfo.value.uiAmount;
468
528
  }
469
529
 
470
- getEffectiveQuoteMint(quoteMint) {
471
- if (!quoteMint || quoteMint.equals(PublicKey.default)) {
472
- return SOL_MINT;
473
- }
474
- return quoteMint;
475
- }
476
-
477
- async getMintDecimals(mint) {
478
- if (mint.equals(SOL_MINT)) {
479
- return 9;
480
- }
481
-
482
- const mintInfo = await this.connection.getParsedAccountInfo(mint);
483
- const parsedData = mintInfo.value?.data;
484
-
485
- if (parsedData && "parsed" in parsedData) {
486
- return parsedData.parsed.info.decimals;
487
- }
488
-
489
- throw new Error(`Unable to determine mint decimals for ${mint.toBase58()}`);
490
- }
491
-
492
530
  /* ---------- 余额查询 ---------- */
493
531
 
494
532
  /**
@@ -502,9 +540,12 @@ export class PumpTrader {
502
540
  const mint = new PublicKey(tokenAddr);
503
541
  const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(
504
542
  this.wallet.publicKey,
505
- { mint }
543
+ { mint },
544
+ );
545
+ return (
546
+ tokenAccounts.value[0]?.account.data.parsed.info.tokenAmount.uiAmount ||
547
+ 0
506
548
  );
507
- return tokenAccounts.value[0]?.account.data.parsed.info.tokenAmount.uiAmount || 0;
508
549
  } else {
509
550
  // 查询所有代币
510
551
  return this.getAllTokenBalances();
@@ -518,13 +559,13 @@ export class PumpTrader {
518
559
  async getAllTokenBalances() {
519
560
  const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(
520
561
  this.wallet.publicKey,
521
- { programId: TOKEN_PROGRAM_ID }
562
+ { programId: TOKEN_PROGRAM_ID },
522
563
  );
523
564
 
524
565
  const balances = tokenAccounts.value
525
566
  .map((account) => {
526
567
  const parsed = account.account.data.parsed;
527
- if (parsed.type !== 'account') return null;
568
+ if (parsed.type !== "account") return null;
528
569
 
529
570
  const tokenAmount = parsed.info.tokenAmount;
530
571
  if (Number(tokenAmount.amount) === 0) return null;
@@ -533,21 +574,22 @@ export class PumpTrader {
533
574
  mint: parsed.info.mint,
534
575
  amount: BigInt(tokenAmount.amount),
535
576
  decimals: tokenAmount.decimals,
536
- uiAmount: tokenAmount.uiAmount || 0
577
+ uiAmount: tokenAmount.uiAmount || 0,
537
578
  };
538
579
  })
539
580
  .filter((item) => item !== null);
540
581
 
541
582
  // 同时查询 TOKEN_2022_PROGRAM_ID
542
- const token2022Accounts = await this.connection.getParsedTokenAccountsByOwner(
543
- this.wallet.publicKey,
544
- { programId: TOKEN_2022_PROGRAM_ID }
545
- );
583
+ const token2022Accounts =
584
+ await this.connection.getParsedTokenAccountsByOwner(
585
+ this.wallet.publicKey,
586
+ { programId: TOKEN_2022_PROGRAM_ID },
587
+ );
546
588
 
547
589
  const token2022Balances = token2022Accounts.value
548
590
  .map((account) => {
549
591
  const parsed = account.account.data.parsed;
550
- if (parsed.type !== 'account') return null;
592
+ if (parsed.type !== "account") return null;
551
593
 
552
594
  const tokenAmount = parsed.info.tokenAmount;
553
595
  if (Number(tokenAmount.amount) === 0) return null;
@@ -556,7 +598,7 @@ export class PumpTrader {
556
598
  mint: parsed.info.mint,
557
599
  amount: BigInt(tokenAmount.amount),
558
600
  decimals: tokenAmount.decimals,
559
- uiAmount: tokenAmount.uiAmount || 0
601
+ uiAmount: tokenAmount.uiAmount || 0,
560
602
  };
561
603
  })
562
604
  .filter((item) => item !== null);
@@ -574,7 +616,7 @@ export class PumpTrader {
574
616
  mint: b.mint,
575
617
  amount: Number(b.amount),
576
618
  decimals: b.decimals,
577
- uiAmount: b.uiAmount
619
+ uiAmount: b.uiAmount,
578
620
  }));
579
621
 
580
622
  return uniqueBalances;
@@ -594,7 +636,7 @@ export class PumpTrader {
594
636
  this.wallet.publicKey,
595
637
  false,
596
638
  program,
597
- ASSOCIATED_TOKEN_PROGRAM_ID
639
+ ASSOCIATED_TOKEN_PROGRAM_ID,
598
640
  );
599
641
 
600
642
  const acc = await this.connection.getAccountInfo(ata);
@@ -606,8 +648,8 @@ export class PumpTrader {
606
648
  this.wallet.publicKey,
607
649
  mint,
608
650
  program,
609
- ASSOCIATED_TOKEN_PROGRAM_ID
610
- )
651
+ ASSOCIATED_TOKEN_PROGRAM_ID,
652
+ ),
611
653
  );
612
654
  }
613
655
 
@@ -620,7 +662,7 @@ export class PumpTrader {
620
662
  owner,
621
663
  false,
622
664
  TOKEN_PROGRAM_ID,
623
- ASSOCIATED_TOKEN_PROGRAM_ID
665
+ ASSOCIATED_TOKEN_PROGRAM_ID,
624
666
  );
625
667
 
626
668
  const acc = await this.connection.getAccountInfo(wsolAta);
@@ -633,18 +675,18 @@ export class PumpTrader {
633
675
  owner,
634
676
  SOL_MINT,
635
677
  TOKEN_PROGRAM_ID,
636
- ASSOCIATED_TOKEN_PROGRAM_ID
637
- )
678
+ ASSOCIATED_TOKEN_PROGRAM_ID,
679
+ ),
638
680
  );
639
681
  }
640
682
 
641
- if (mode === 'buy') {
683
+ if (mode === "buy") {
642
684
  tx.add(
643
685
  SystemProgram.transfer({
644
686
  fromPubkey: owner,
645
687
  toPubkey: wsolAta,
646
- lamports: Number(lamports)
647
- })
688
+ lamports: Number(lamports),
689
+ }),
648
690
  );
649
691
  tx.add(createSyncNativeInstruction(wsolAta));
650
692
  }
@@ -658,7 +700,9 @@ export class PumpTrader {
658
700
  if (!priorityOpt?.enableRandom || !priorityOpt.randomRange) {
659
701
  return priorityOpt.base;
660
702
  }
661
- return priorityOpt.base + Math.floor(Math.random() * priorityOpt.randomRange);
703
+ return (
704
+ priorityOpt.base + Math.floor(Math.random() * priorityOpt.randomRange)
705
+ );
662
706
  }
663
707
 
664
708
  calcSlippage({ tradeSize, reserve, slippageOpt }) {
@@ -706,25 +750,47 @@ export class PumpTrader {
706
750
 
707
751
  /**
708
752
  * 统一的自动买入接口,自动判断内盘/外盘
753
+ * @param {boolean} [useV2=false] - use buy_v2 instruction (supports USDC quote)
754
+ * @param {PublicKey} [quoteMint=SOL_MINT] - quote mint (SOL_MINT for SOL-paired, USDC mint for USDC-paired)
709
755
  */
710
- async autoBuy(tokenAddr, totalSolIn, tradeOpt) {
756
+ async autoBuy(
757
+ tokenAddr,
758
+ totalSolIn,
759
+ tradeOpt,
760
+ useV2 = false,
761
+ quoteMint = SOL_MINT,
762
+ ) {
711
763
  const mode = await this.getTradeMode(tokenAddr);
712
764
  if (mode === "bonding") {
765
+ if (useV2) {
766
+ return this.buyV2(tokenAddr, totalSolIn, tradeOpt, quoteMint);
767
+ }
713
768
  return this.buy(tokenAddr, totalSolIn, tradeOpt);
714
769
  } else {
715
- return this.ammBuy(tokenAddr, totalSolIn, tradeOpt);
770
+ return this.ammBuy(tokenAddr, totalSolIn, tradeOpt, quoteMint);
716
771
  }
717
772
  }
718
773
 
719
774
  /**
720
775
  * 统一的自动卖出接口,自动判断内盘/外盘
776
+ * @param {boolean} [useV2=false] - use sell_v2 instruction
777
+ * @param {PublicKey} [quoteMint=SOL_MINT] - quote mint
721
778
  */
722
- async autoSell(tokenAddr, totalTokenIn, tradeOpt) {
779
+ async autoSell(
780
+ tokenAddr,
781
+ totalTokenIn,
782
+ tradeOpt,
783
+ useV2 = false,
784
+ quoteMint = SOL_MINT,
785
+ ) {
723
786
  const mode = await this.getTradeMode(tokenAddr);
724
787
  if (mode === "bonding") {
788
+ if (useV2) {
789
+ return this.sellV2(tokenAddr, totalTokenIn, tradeOpt, quoteMint);
790
+ }
725
791
  return this.sell(tokenAddr, totalTokenIn, tradeOpt);
726
792
  } else {
727
- return this.ammSell(tokenAddr, totalTokenIn, tradeOpt);
793
+ return this.ammSell(tokenAddr, totalTokenIn, tradeOpt, quoteMint);
728
794
  }
729
795
  }
730
796
 
@@ -745,27 +811,30 @@ export class PumpTrader {
745
811
  bonding,
746
812
  true,
747
813
  tokenProgram.programId,
748
- ASSOCIATED_TOKEN_PROGRAM_ID
814
+ ASSOCIATED_TOKEN_PROGRAM_ID,
749
815
  );
750
816
 
751
817
  const [creatorVault] = PublicKey.findProgramAddressSync(
752
818
  [Buffer.from("creator-vault"), creator.toBuffer()],
753
- PROGRAM_IDS.PUMP
819
+ PROGRAM_IDS.PUMP,
754
820
  );
755
821
 
756
822
  const [globalVolumeAccumulator] = PublicKey.findProgramAddressSync(
757
823
  [Buffer.from("global_volume_accumulator")],
758
- PROGRAM_IDS.PUMP
824
+ PROGRAM_IDS.PUMP,
759
825
  );
760
826
 
761
827
  const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
762
- [Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
763
- PROGRAM_IDS.PUMP
828
+ [
829
+ Buffer.from("user_volume_accumulator"),
830
+ this.wallet.publicKey.toBuffer(),
831
+ ],
832
+ PROGRAM_IDS.PUMP,
764
833
  );
765
834
 
766
835
  const [feeConfig] = PublicKey.findProgramAddressSync(
767
836
  [Buffer.from("fee_config"), SEEDS.FEE_CONFIG],
768
- PROGRAM_IDS.FEE
837
+ PROGRAM_IDS.FEE,
769
838
  );
770
839
  const feeRecipient = this.pickFeeRecipient();
771
840
 
@@ -776,14 +845,14 @@ export class PumpTrader {
776
845
  const slippageBps = this.calcSlippage({
777
846
  tradeSize: solIn,
778
847
  reserve: state.virtualSolReserves,
779
- slippageOpt: tradeOpt.slippage
848
+ slippageOpt: tradeOpt.slippage,
780
849
  });
781
850
  const maxSol = (solIn * BigInt(10_000 + slippageBps)) / 10_000n;
782
851
  const priority = this.genPriority(tradeOpt.priority);
783
852
 
784
853
  const tx = new Transaction().add(
785
854
  ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
786
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority })
855
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority }),
787
856
  );
788
857
 
789
858
  const userAta = await this.ensureAta(tx, mint, tokenProgram.programId);
@@ -808,32 +877,39 @@ export class PumpTrader {
808
877
  feeProgram: PROGRAM_IDS.FEE,
809
878
  bondingCurveV2,
810
879
  feeRecipient,
811
- tokenProgramId: tokenProgram.programId
880
+ tokenProgramId: tokenProgram.programId,
812
881
  }),
813
- data: Buffer.concat([DISCRIMINATORS.BUY, u64(tokenOut), u64(maxSol)])
814
- })
882
+ data: Buffer.concat([
883
+ DISCRIMINATORS.BUY,
884
+ u64(tokenOut),
885
+ u64(maxSol),
886
+ ]),
887
+ }),
815
888
  );
816
889
 
817
890
  const { blockhash, lastValidBlockHeight } =
818
- await this.connection.getLatestBlockhash('finalized');
891
+ await this.connection.getLatestBlockhash("finalized");
819
892
  tx.recentBlockhash = blockhash;
820
893
  tx.feePayer = this.wallet.publicKey;
821
894
  tx.sign(this.wallet);
822
895
 
823
- const signature = await this.connection.sendRawTransaction(tx.serialize(), {
824
- skipPreflight: false,
825
- maxRetries: 2
826
- });
896
+ const signature = await this.connection.sendRawTransaction(
897
+ tx.serialize(),
898
+ {
899
+ skipPreflight: false,
900
+ maxRetries: 2,
901
+ },
902
+ );
827
903
 
828
904
  pendingTransactions.push({
829
905
  signature,
830
906
  lastValidBlockHeight,
831
- index: i
907
+ index: i,
832
908
  });
833
909
  } catch (e) {
834
910
  failedTransactions.push({
835
911
  index: i,
836
- error: e.message
912
+ error: e.message,
837
913
  });
838
914
  }
839
915
  }
@@ -852,12 +928,15 @@ export class PumpTrader {
852
928
  if (state.complete) throw new Error("Bonding curve already completed");
853
929
 
854
930
  const totalSolOut = this.calcSell(totalTokenIn, state);
855
- const tokenChunks = totalSolOut <= tradeOpt.maxSolPerTx
856
- ? [totalTokenIn]
857
- : this.splitIntoN(
858
- totalTokenIn,
859
- Number((totalSolOut + tradeOpt.maxSolPerTx - 1n) / tradeOpt.maxSolPerTx)
860
- );
931
+ const tokenChunks =
932
+ totalSolOut <= tradeOpt.maxSolPerTx
933
+ ? [totalTokenIn]
934
+ : this.splitIntoN(
935
+ totalTokenIn,
936
+ Number(
937
+ (totalSolOut + tradeOpt.maxSolPerTx - 1n) / tradeOpt.maxSolPerTx,
938
+ ),
939
+ );
861
940
 
862
941
  const pendingTransactions = []; // 待确认的交易
863
942
  const failedTransactions = []; // 发送失败的交易
@@ -867,7 +946,7 @@ export class PumpTrader {
867
946
  bonding,
868
947
  true,
869
948
  tokenProgram.programId,
870
- ASSOCIATED_TOKEN_PROGRAM_ID
949
+ ASSOCIATED_TOKEN_PROGRAM_ID,
871
950
  );
872
951
 
873
952
  const userAta = getAssociatedTokenAddressSync(
@@ -875,21 +954,24 @@ export class PumpTrader {
875
954
  this.wallet.publicKey,
876
955
  false,
877
956
  tokenProgram.programId,
878
- ASSOCIATED_TOKEN_PROGRAM_ID
957
+ ASSOCIATED_TOKEN_PROGRAM_ID,
879
958
  );
880
959
 
881
960
  const [creatorVault] = PublicKey.findProgramAddressSync(
882
961
  [Buffer.from("creator-vault"), creator.toBuffer()],
883
- PROGRAM_IDS.PUMP
962
+ PROGRAM_IDS.PUMP,
884
963
  );
885
964
 
886
965
  const [feeConfig] = PublicKey.findProgramAddressSync(
887
966
  [Buffer.from("fee_config"), SEEDS.FEE_CONFIG],
888
- PROGRAM_IDS.FEE
967
+ PROGRAM_IDS.FEE,
889
968
  );
890
969
  const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
891
- [Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
892
- PROGRAM_IDS.PUMP
970
+ [
971
+ Buffer.from("user_volume_accumulator"),
972
+ this.wallet.publicKey.toBuffer(),
973
+ ],
974
+ PROGRAM_IDS.PUMP,
893
975
  );
894
976
  const feeRecipient = this.pickFeeRecipient();
895
977
 
@@ -900,14 +982,14 @@ export class PumpTrader {
900
982
  const slippageBps = this.calcSlippage({
901
983
  tradeSize: tokenIn,
902
984
  reserve: state.virtualTokenReserves,
903
- slippageOpt: tradeOpt.slippage
985
+ slippageOpt: tradeOpt.slippage,
904
986
  });
905
987
  const minSol = (solOut * BigInt(10_000 - slippageBps)) / 10_000n;
906
988
  const priority = this.genPriority(tradeOpt.priority);
907
989
 
908
990
  const tx = new Transaction().add(
909
991
  ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
910
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority })
992
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority }),
911
993
  );
912
994
 
913
995
  tx.add(
@@ -930,14 +1012,14 @@ export class PumpTrader {
930
1012
  feeRecipient,
931
1013
  isCashbackCoin: !!state.isCashbackCoin,
932
1014
  userVolumeAccumulator,
933
- tokenProgramId: tokenProgram.programId
1015
+ tokenProgramId: tokenProgram.programId,
934
1016
  }),
935
1017
  data: Buffer.concat([
936
1018
  DISCRIMINATORS.SELL,
937
1019
  u64(tokenIn),
938
- u64(minSol > 0n ? minSol : 1n)
939
- ])
940
- })
1020
+ u64(minSol > 0n ? minSol : 1n),
1021
+ ]),
1022
+ }),
941
1023
  );
942
1024
 
943
1025
  const { blockhash, lastValidBlockHeight } =
@@ -946,16 +1028,18 @@ export class PumpTrader {
946
1028
  tx.feePayer = this.wallet.publicKey;
947
1029
  tx.sign(this.wallet);
948
1030
 
949
- const signature = await this.connection.sendRawTransaction(tx.serialize());
1031
+ const signature = await this.connection.sendRawTransaction(
1032
+ tx.serialize(),
1033
+ );
950
1034
  pendingTransactions.push({
951
1035
  signature,
952
1036
  lastValidBlockHeight,
953
- index: i
1037
+ index: i,
954
1038
  });
955
1039
  } catch (e) {
956
1040
  failedTransactions.push({
957
1041
  index: i,
958
- error: e.message
1042
+ error: e.message,
959
1043
  });
960
1044
  }
961
1045
  }
@@ -965,12 +1049,16 @@ export class PumpTrader {
965
1049
 
966
1050
  /* ---------- 外盘交易 ---------- */
967
1051
 
968
- async ammBuy(tokenAddr, totalSolIn, tradeOpt) {
1052
+ async ammBuy(tokenAddr, totalSolIn, tradeOpt, quoteMint = SOL_MINT) {
969
1053
  const mint = new PublicKey(tokenAddr);
970
- const poolInfo = await this.getAmmPoolInfo(mint);
1054
+ const poolInfo = await this.getAmmPoolInfo(mint, quoteMint);
971
1055
  const reserves = await this.getAmmPoolReserves(poolInfo.poolKeys);
972
1056
  const solChunks = this.splitByMax(totalSolIn, tradeOpt.maxSolPerTx);
973
1057
  const tokenProgram = await this.detectTokenProgram(tokenAddr);
1058
+ const isSolQuote = quoteMint.equals(SOL_MINT);
1059
+ const quoteTokenProgramId = isSolQuote
1060
+ ? TOKEN_PROGRAM_ID
1061
+ : await this.detectQuoteTokenProgram(quoteMint);
974
1062
  const pendingTransactions = [];
975
1063
  const failedTransactions = [];
976
1064
 
@@ -981,23 +1069,29 @@ export class PumpTrader {
981
1069
  const slippageBps = this.calcSlippage({
982
1070
  tradeSize: solIn,
983
1071
  reserve: reserves.quoteAmount,
984
- slippageOpt: tradeOpt.slippage
1072
+ slippageOpt: tradeOpt.slippage,
985
1073
  });
986
1074
  const maxQuoteIn = (solIn * BigInt(10_000 + slippageBps)) / 10_000n;
987
1075
  const priority = this.genPriority(tradeOpt.priority);
988
1076
 
989
1077
  const tx = new Transaction().add(
990
1078
  ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }),
991
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority })
1079
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority }),
992
1080
  );
993
1081
 
994
- const userBaseAta = await this.ensureAta(tx, poolInfo.poolKeys.baseMint, tokenProgram.programId);
995
- const userQuoteAta = await this.ensureWSOLAta(
1082
+ const userBaseAta = await this.ensureAta(
996
1083
  tx,
997
- this.wallet.publicKey,
998
- "buy",
999
- maxQuoteIn
1084
+ poolInfo.poolKeys.baseMint,
1085
+ tokenProgram.programId,
1000
1086
  );
1087
+ const userQuoteAta = isSolQuote
1088
+ ? await this.ensureWSOLAta(
1089
+ tx,
1090
+ this.wallet.publicKey,
1091
+ "buy",
1092
+ maxQuoteIn,
1093
+ )
1094
+ : await this.ensureAta(tx, quoteMint, quoteTokenProgramId);
1001
1095
 
1002
1096
  const buyIx = this.createAmmBuyInstruction(
1003
1097
  poolInfo,
@@ -1005,38 +1099,43 @@ export class PumpTrader {
1005
1099
  userQuoteAta,
1006
1100
  baseAmountOut,
1007
1101
  maxQuoteIn,
1008
- tokenProgram.programId
1102
+ tokenProgram.programId,
1009
1103
  );
1010
1104
 
1011
1105
  tx.add(buyIx);
1012
- tx.add(
1013
- createCloseAccountInstruction(
1014
- userQuoteAta,
1015
- this.wallet.publicKey,
1016
- this.wallet.publicKey
1017
- )
1018
- );
1106
+ if (isSolQuote) {
1107
+ tx.add(
1108
+ createCloseAccountInstruction(
1109
+ userQuoteAta,
1110
+ this.wallet.publicKey,
1111
+ this.wallet.publicKey,
1112
+ ),
1113
+ );
1114
+ }
1019
1115
 
1020
1116
  const { blockhash, lastValidBlockHeight } =
1021
- await this.connection.getLatestBlockhash('finalized');
1117
+ await this.connection.getLatestBlockhash("finalized");
1022
1118
  tx.recentBlockhash = blockhash;
1023
1119
  tx.feePayer = this.wallet.publicKey;
1024
1120
  tx.sign(this.wallet);
1025
1121
 
1026
- const signature = await this.connection.sendRawTransaction(tx.serialize(), {
1027
- skipPreflight: false,
1028
- maxRetries: 2
1029
- });
1122
+ const signature = await this.connection.sendRawTransaction(
1123
+ tx.serialize(),
1124
+ {
1125
+ skipPreflight: false,
1126
+ maxRetries: 2,
1127
+ },
1128
+ );
1030
1129
 
1031
1130
  pendingTransactions.push({
1032
1131
  signature,
1033
1132
  lastValidBlockHeight,
1034
- index: i
1133
+ index: i,
1035
1134
  });
1036
1135
  } catch (e) {
1037
1136
  failedTransactions.push({
1038
1137
  index: i,
1039
- error: e.message
1138
+ error: e.message,
1040
1139
  });
1041
1140
  }
1042
1141
  }
@@ -1044,19 +1143,26 @@ export class PumpTrader {
1044
1143
  return { pendingTransactions, failedTransactions };
1045
1144
  }
1046
1145
 
1047
- async ammSell(tokenAddr, totalTokenIn, tradeOpt) {
1146
+ async ammSell(tokenAddr, totalTokenIn, tradeOpt, quoteMint = SOL_MINT) {
1048
1147
  const mint = new PublicKey(tokenAddr);
1049
- const poolInfo = await this.getAmmPoolInfo(mint);
1148
+ const poolInfo = await this.getAmmPoolInfo(mint, quoteMint);
1050
1149
  const reserves = await this.getAmmPoolReserves(poolInfo.poolKeys);
1051
1150
  const totalSolOut = this.calculateAmmSellOutput(totalTokenIn, reserves);
1052
1151
  const tokenProgram = await this.detectTokenProgram(tokenAddr);
1053
-
1054
- const tokenChunks = totalSolOut <= tradeOpt.maxSolPerTx
1055
- ? [totalTokenIn]
1056
- : this.splitIntoN(
1057
- totalTokenIn,
1058
- Number((totalSolOut + tradeOpt.maxSolPerTx - 1n) / tradeOpt.maxSolPerTx)
1059
- );
1152
+ const isSolQuote = quoteMint.equals(SOL_MINT);
1153
+ const quoteTokenProgramId = isSolQuote
1154
+ ? TOKEN_PROGRAM_ID
1155
+ : await this.detectQuoteTokenProgram(quoteMint);
1156
+
1157
+ const tokenChunks =
1158
+ totalSolOut <= tradeOpt.maxSolPerTx
1159
+ ? [totalTokenIn]
1160
+ : this.splitIntoN(
1161
+ totalTokenIn,
1162
+ Number(
1163
+ (totalSolOut + tradeOpt.maxSolPerTx - 1n) / tradeOpt.maxSolPerTx,
1164
+ ),
1165
+ );
1060
1166
 
1061
1167
  const pendingTransactions = [];
1062
1168
  const failedTransactions = [];
@@ -1068,18 +1174,24 @@ export class PumpTrader {
1068
1174
  const slippageBps = this.calcSlippage({
1069
1175
  tradeSize: tokenIn,
1070
1176
  reserve: reserves.baseAmount,
1071
- slippageOpt: tradeOpt.slippage
1177
+ slippageOpt: tradeOpt.slippage,
1072
1178
  });
1073
1179
  const minQuoteOut = (solOut * BigInt(10_000 - slippageBps)) / 10_000n;
1074
1180
  const priority = this.genPriority(tradeOpt.priority);
1075
1181
 
1076
1182
  const tx = new Transaction().add(
1077
1183
  ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }),
1078
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority })
1184
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority }),
1079
1185
  );
1080
1186
 
1081
- const userBaseAta = await this.ensureAta(tx, poolInfo.poolKeys.baseMint, tokenProgram.programId);
1082
- const userQuoteAta = await this.ensureWSOLAta(tx, this.wallet.publicKey, "sell");
1187
+ const userBaseAta = await this.ensureAta(
1188
+ tx,
1189
+ poolInfo.poolKeys.baseMint,
1190
+ tokenProgram.programId,
1191
+ );
1192
+ const userQuoteAta = isSolQuote
1193
+ ? await this.ensureWSOLAta(tx, this.wallet.publicKey, "sell")
1194
+ : await this.ensureAta(tx, quoteMint, quoteTokenProgramId);
1083
1195
 
1084
1196
  const sellIx = this.createAmmSellInstruction(
1085
1197
  poolInfo,
@@ -1087,38 +1199,43 @@ export class PumpTrader {
1087
1199
  userQuoteAta,
1088
1200
  tokenIn,
1089
1201
  minQuoteOut,
1090
- tokenProgram.programId
1202
+ tokenProgram.programId,
1091
1203
  );
1092
1204
 
1093
1205
  tx.add(sellIx);
1094
- tx.add(
1095
- createCloseAccountInstruction(
1096
- userQuoteAta,
1097
- this.wallet.publicKey,
1098
- this.wallet.publicKey
1099
- )
1100
- );
1206
+ if (isSolQuote) {
1207
+ tx.add(
1208
+ createCloseAccountInstruction(
1209
+ userQuoteAta,
1210
+ this.wallet.publicKey,
1211
+ this.wallet.publicKey,
1212
+ ),
1213
+ );
1214
+ }
1101
1215
 
1102
1216
  const { blockhash, lastValidBlockHeight } =
1103
- await this.connection.getLatestBlockhash('finalized');
1217
+ await this.connection.getLatestBlockhash("finalized");
1104
1218
  tx.recentBlockhash = blockhash;
1105
1219
  tx.feePayer = this.wallet.publicKey;
1106
1220
  tx.sign(this.wallet);
1107
1221
 
1108
- const signature = await this.connection.sendRawTransaction(tx.serialize(), {
1109
- skipPreflight: false,
1110
- maxRetries: 2
1111
- });
1222
+ const signature = await this.connection.sendRawTransaction(
1223
+ tx.serialize(),
1224
+ {
1225
+ skipPreflight: false,
1226
+ maxRetries: 2,
1227
+ },
1228
+ );
1112
1229
 
1113
1230
  pendingTransactions.push({
1114
1231
  signature,
1115
1232
  lastValidBlockHeight,
1116
- index: i
1233
+ index: i,
1117
1234
  });
1118
1235
  } catch (e) {
1119
1236
  failedTransactions.push({
1120
1237
  index: i,
1121
- error: e.message
1238
+ error: e.message,
1122
1239
  });
1123
1240
  }
1124
1241
  }
@@ -1128,10 +1245,10 @@ export class PumpTrader {
1128
1245
 
1129
1246
  /* ---------- AMM 池信息 ---------- */
1130
1247
 
1131
- async getAmmPoolInfo(mint) {
1248
+ async getAmmPoolInfo(mint, quoteMint = SOL_MINT) {
1132
1249
  const [poolAuthority] = PublicKey.findProgramAddressSync(
1133
1250
  [Buffer.from("pool-authority"), mint.toBuffer()],
1134
- PROGRAM_IDS.PUMP
1251
+ PROGRAM_IDS.PUMP,
1135
1252
  );
1136
1253
 
1137
1254
  const [pool] = PublicKey.findProgramAddressSync(
@@ -1140,9 +1257,9 @@ export class PumpTrader {
1140
1257
  new BN(0).toArrayLike(Buffer, "le", 2),
1141
1258
  poolAuthority.toBuffer(),
1142
1259
  mint.toBuffer(),
1143
- SOL_MINT.toBuffer()
1260
+ quoteMint.toBuffer(),
1144
1261
  ],
1145
- PROGRAM_IDS.PUMP_AMM
1262
+ PROGRAM_IDS.PUMP_AMM,
1146
1263
  );
1147
1264
 
1148
1265
  const acc = await this.connection.getAccountInfo(pool);
@@ -1152,13 +1269,17 @@ export class PumpTrader {
1152
1269
 
1153
1270
  const [globalConfigPda] = PublicKey.findProgramAddressSync(
1154
1271
  [Buffer.from("global_config")],
1155
- PROGRAM_IDS.PUMP_AMM
1272
+ PROGRAM_IDS.PUMP_AMM,
1156
1273
  );
1157
1274
 
1158
- const globalConfigAcc = await this.connection.getAccountInfo(globalConfigPda);
1275
+ const globalConfigAcc =
1276
+ await this.connection.getAccountInfo(globalConfigPda);
1159
1277
  if (!globalConfigAcc) throw new Error("Global config not found");
1160
1278
 
1161
- const globalConfig = this.parseAmmGlobalConfig(globalConfigAcc.data, globalConfigPda);
1279
+ const globalConfig = this.parseAmmGlobalConfig(
1280
+ globalConfigAcc.data,
1281
+ globalConfigPda,
1282
+ );
1162
1283
 
1163
1284
  return { pool, poolAuthority, poolKeys, globalConfig };
1164
1285
  }
@@ -1175,7 +1296,9 @@ export class PumpTrader {
1175
1296
 
1176
1297
  const protocolFeeRecipients = [];
1177
1298
  for (let i = 0; i < 8; i++) {
1178
- protocolFeeRecipients.push(new PublicKey(data.slice(offset, offset + 32)));
1299
+ protocolFeeRecipients.push(
1300
+ new PublicKey(data.slice(offset, offset + 32)),
1301
+ );
1179
1302
  offset += 32;
1180
1303
  }
1181
1304
 
@@ -1185,38 +1308,45 @@ export class PumpTrader {
1185
1308
  async getAmmPoolReserves(poolKeys) {
1186
1309
  const [baseInfo, quoteInfo] = await Promise.all([
1187
1310
  this.connection.getTokenAccountBalance(poolKeys.poolBaseTokenAccount),
1188
- this.connection.getTokenAccountBalance(poolKeys.poolQuoteTokenAccount)
1311
+ this.connection.getTokenAccountBalance(poolKeys.poolQuoteTokenAccount),
1189
1312
  ]);
1190
1313
 
1191
1314
  return {
1192
1315
  baseAmount: BigInt(baseInfo.value.amount),
1193
1316
  quoteAmount: BigInt(quoteInfo.value.amount),
1194
1317
  baseDecimals: baseInfo.value.decimals,
1195
- quoteDecimals: quoteInfo.value.decimals
1318
+ quoteDecimals: quoteInfo.value.decimals,
1196
1319
  };
1197
1320
  }
1198
1321
 
1199
1322
  deriveAmmPoolV2(baseMint) {
1200
1323
  return PublicKey.findProgramAddressSync(
1201
1324
  [Buffer.from("pool-v2"), baseMint.toBuffer()],
1202
- PROGRAM_IDS.PUMP_AMM
1325
+ PROGRAM_IDS.PUMP_AMM,
1203
1326
  )[0];
1204
1327
  }
1205
1328
 
1206
1329
  /* ---------- AMM 指令构建 ---------- */
1207
1330
 
1208
- createAmmBuyInstruction(poolInfo, userBaseAta, userQuoteAta, baseAmountOut, maxQuoteAmountIn, tokenProgramId) {
1331
+ createAmmBuyInstruction(
1332
+ poolInfo,
1333
+ userBaseAta,
1334
+ userQuoteAta,
1335
+ baseAmountOut,
1336
+ maxQuoteAmountIn,
1337
+ tokenProgramId,
1338
+ ) {
1209
1339
  const { pool, poolKeys, globalConfig } = poolInfo;
1210
1340
  const poolV2 = this.deriveAmmPoolV2(poolKeys.baseMint);
1211
1341
 
1212
1342
  const [eventAuthority] = PublicKey.findProgramAddressSync(
1213
1343
  [Buffer.from("__event_authority")],
1214
- PROGRAM_IDS.PUMP_AMM
1344
+ PROGRAM_IDS.PUMP_AMM,
1215
1345
  );
1216
1346
 
1217
1347
  const [coinCreatorVaultAuthority] = PublicKey.findProgramAddressSync(
1218
1348
  [Buffer.from("creator_vault"), poolKeys.coinCreator.toBuffer()],
1219
- PROGRAM_IDS.PUMP_AMM
1349
+ PROGRAM_IDS.PUMP_AMM,
1220
1350
  );
1221
1351
 
1222
1352
  const coinCreatorVaultAta = getAssociatedTokenAddressSync(
@@ -1224,22 +1354,25 @@ export class PumpTrader {
1224
1354
  coinCreatorVaultAuthority,
1225
1355
  true,
1226
1356
  TOKEN_PROGRAM_ID,
1227
- ASSOCIATED_TOKEN_PROGRAM_ID
1357
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1228
1358
  );
1229
1359
 
1230
1360
  const [globalVolumeAccumulator] = PublicKey.findProgramAddressSync(
1231
1361
  [Buffer.from("global_volume_accumulator")],
1232
- PROGRAM_IDS.PUMP_AMM
1362
+ PROGRAM_IDS.PUMP_AMM,
1233
1363
  );
1234
1364
 
1235
1365
  const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
1236
- [Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
1237
- PROGRAM_IDS.PUMP_AMM
1366
+ [
1367
+ Buffer.from("user_volume_accumulator"),
1368
+ this.wallet.publicKey.toBuffer(),
1369
+ ],
1370
+ PROGRAM_IDS.PUMP_AMM,
1238
1371
  );
1239
1372
 
1240
1373
  const [feeConfig] = PublicKey.findProgramAddressSync(
1241
1374
  [Buffer.from("fee_config"), SEEDS.AMM_FEE_CONFIG],
1242
- PROGRAM_IDS.FEE
1375
+ PROGRAM_IDS.FEE,
1243
1376
  );
1244
1377
 
1245
1378
  const protocolFeeRecipient = globalConfig.protocolFeeRecipients[0];
@@ -1248,7 +1381,7 @@ export class PumpTrader {
1248
1381
  protocolFeeRecipient,
1249
1382
  true,
1250
1383
  TOKEN_PROGRAM_ID,
1251
- ASSOCIATED_TOKEN_PROGRAM_ID
1384
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1252
1385
  );
1253
1386
  const newFeeRecipient = this.pickFeeRecipient();
1254
1387
  const newFeeRecipientTokenAccount = getAssociatedTokenAddressSync(
@@ -1256,7 +1389,7 @@ export class PumpTrader {
1256
1389
  newFeeRecipient,
1257
1390
  true,
1258
1391
  TOKEN_PROGRAM_ID,
1259
- ASSOCIATED_TOKEN_PROGRAM_ID
1392
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1260
1393
  );
1261
1394
 
1262
1395
  const remainingKeys = [];
@@ -1266,14 +1399,22 @@ export class PumpTrader {
1266
1399
  userVolumeAccumulator,
1267
1400
  true,
1268
1401
  TOKEN_PROGRAM_ID,
1269
- ASSOCIATED_TOKEN_PROGRAM_ID
1402
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1270
1403
  );
1271
- remainingKeys.push({ pubkey: userVolumeAccumulatorWsolAta, isSigner: false, isWritable: true });
1404
+ remainingKeys.push({
1405
+ pubkey: userVolumeAccumulatorWsolAta,
1406
+ isSigner: false,
1407
+ isWritable: true,
1408
+ });
1272
1409
  }
1273
1410
  remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
1274
1411
  remainingKeys.push(
1275
1412
  { pubkey: newFeeRecipient, isSigner: false, isWritable: false },
1276
- { pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true }
1413
+ {
1414
+ pubkey: newFeeRecipientTokenAccount,
1415
+ isSigner: false,
1416
+ isWritable: true,
1417
+ },
1277
1418
  );
1278
1419
 
1279
1420
  return new TransactionInstruction({
@@ -1286,45 +1427,72 @@ export class PumpTrader {
1286
1427
  { pubkey: poolKeys.quoteMint, isSigner: false, isWritable: false },
1287
1428
  { pubkey: userBaseAta, isSigner: false, isWritable: true },
1288
1429
  { pubkey: userQuoteAta, isSigner: false, isWritable: true },
1289
- { pubkey: poolKeys.poolBaseTokenAccount, isSigner: false, isWritable: true },
1290
- { pubkey: poolKeys.poolQuoteTokenAccount, isSigner: false, isWritable: true },
1430
+ {
1431
+ pubkey: poolKeys.poolBaseTokenAccount,
1432
+ isSigner: false,
1433
+ isWritable: true,
1434
+ },
1435
+ {
1436
+ pubkey: poolKeys.poolQuoteTokenAccount,
1437
+ isSigner: false,
1438
+ isWritable: true,
1439
+ },
1291
1440
  { pubkey: protocolFeeRecipient, isSigner: false, isWritable: false },
1292
- { pubkey: protocolFeeRecipientTokenAccount, isSigner: false, isWritable: true },
1441
+ {
1442
+ pubkey: protocolFeeRecipientTokenAccount,
1443
+ isSigner: false,
1444
+ isWritable: true,
1445
+ },
1293
1446
  { pubkey: tokenProgramId, isSigner: false, isWritable: false },
1294
1447
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1295
1448
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1296
- { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1449
+ {
1450
+ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
1451
+ isSigner: false,
1452
+ isWritable: false,
1453
+ },
1297
1454
  { pubkey: eventAuthority, isSigner: false, isWritable: false },
1298
1455
  { pubkey: PROGRAM_IDS.PUMP_AMM, isSigner: false, isWritable: false },
1299
1456
  { pubkey: coinCreatorVaultAta, isSigner: false, isWritable: true },
1300
- { pubkey: coinCreatorVaultAuthority, isSigner: false, isWritable: false },
1457
+ {
1458
+ pubkey: coinCreatorVaultAuthority,
1459
+ isSigner: false,
1460
+ isWritable: false,
1461
+ },
1301
1462
  { pubkey: globalVolumeAccumulator, isSigner: false, isWritable: false },
1302
1463
  { pubkey: userVolumeAccumulator, isSigner: false, isWritable: true },
1303
1464
  { pubkey: feeConfig, isSigner: false, isWritable: false },
1304
1465
  { pubkey: PROGRAM_IDS.FEE, isSigner: false, isWritable: false },
1305
- ...remainingKeys
1466
+ ...remainingKeys,
1306
1467
  ],
1307
1468
  data: Buffer.concat([
1308
1469
  DISCRIMINATORS.BUY,
1309
1470
  u64(baseAmountOut),
1310
1471
  u64(maxQuoteAmountIn),
1311
- Buffer.from([1, 1])
1312
- ])
1472
+ Buffer.from([1, 1]),
1473
+ ]),
1313
1474
  });
1314
1475
  }
1315
1476
 
1316
- createAmmSellInstruction(poolInfo, userBaseAta, userQuoteAta, baseAmountIn, minQuoteAmountOut, tokenProgramId) {
1477
+ createAmmSellInstruction(
1478
+ poolInfo,
1479
+ userBaseAta,
1480
+ userQuoteAta,
1481
+ baseAmountIn,
1482
+ minQuoteAmountOut,
1483
+ tokenProgramId,
1484
+ ) {
1317
1485
  const { pool, poolKeys, globalConfig } = poolInfo;
1318
1486
  const poolV2 = this.deriveAmmPoolV2(poolKeys.baseMint);
1319
1487
 
1320
1488
  const [eventAuthority] = PublicKey.findProgramAddressSync(
1321
1489
  [Buffer.from("__event_authority")],
1322
- PROGRAM_IDS.PUMP_AMM
1490
+ PROGRAM_IDS.PUMP_AMM,
1323
1491
  );
1324
1492
 
1325
1493
  const [coinCreatorVaultAuthority] = PublicKey.findProgramAddressSync(
1326
1494
  [Buffer.from("creator_vault"), poolKeys.coinCreator.toBuffer()],
1327
- PROGRAM_IDS.PUMP_AMM
1495
+ PROGRAM_IDS.PUMP_AMM,
1328
1496
  );
1329
1497
 
1330
1498
  const coinCreatorVaultAta = getAssociatedTokenAddressSync(
@@ -1332,12 +1500,12 @@ export class PumpTrader {
1332
1500
  coinCreatorVaultAuthority,
1333
1501
  true,
1334
1502
  TOKEN_PROGRAM_ID,
1335
- ASSOCIATED_TOKEN_PROGRAM_ID
1503
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1336
1504
  );
1337
1505
 
1338
1506
  const [feeConfig] = PublicKey.findProgramAddressSync(
1339
1507
  [Buffer.from("fee_config"), SEEDS.AMM_FEE_CONFIG],
1340
- PROGRAM_IDS.FEE
1508
+ PROGRAM_IDS.FEE,
1341
1509
  );
1342
1510
 
1343
1511
  const protocolFeeRecipient = globalConfig.protocolFeeRecipients[0];
@@ -1346,7 +1514,7 @@ export class PumpTrader {
1346
1514
  protocolFeeRecipient,
1347
1515
  true,
1348
1516
  TOKEN_PROGRAM_ID,
1349
- ASSOCIATED_TOKEN_PROGRAM_ID
1517
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1350
1518
  );
1351
1519
  const newFeeRecipient = this.pickFeeRecipient();
1352
1520
  const newFeeRecipientTokenAccount = getAssociatedTokenAddressSync(
@@ -1354,12 +1522,15 @@ export class PumpTrader {
1354
1522
  newFeeRecipient,
1355
1523
  true,
1356
1524
  TOKEN_PROGRAM_ID,
1357
- ASSOCIATED_TOKEN_PROGRAM_ID
1525
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1358
1526
  );
1359
1527
 
1360
1528
  const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
1361
- [Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
1362
- PROGRAM_IDS.PUMP_AMM
1529
+ [
1530
+ Buffer.from("user_volume_accumulator"),
1531
+ this.wallet.publicKey.toBuffer(),
1532
+ ],
1533
+ PROGRAM_IDS.PUMP_AMM,
1363
1534
  );
1364
1535
 
1365
1536
  const userVolumeAccumulatorWsolAta = getAssociatedTokenAddressSync(
@@ -1367,20 +1538,28 @@ export class PumpTrader {
1367
1538
  userVolumeAccumulator,
1368
1539
  true,
1369
1540
  TOKEN_PROGRAM_ID,
1370
- ASSOCIATED_TOKEN_PROGRAM_ID
1541
+ ASSOCIATED_TOKEN_PROGRAM_ID,
1371
1542
  );
1372
1543
 
1373
1544
  const remainingKeys = [];
1374
1545
  if (poolKeys.isCashbackCoin) {
1375
1546
  remainingKeys.push(
1376
- { pubkey: userVolumeAccumulatorWsolAta, isSigner: false, isWritable: true },
1377
- { pubkey: userVolumeAccumulator, isSigner: false, isWritable: true }
1547
+ {
1548
+ pubkey: userVolumeAccumulatorWsolAta,
1549
+ isSigner: false,
1550
+ isWritable: true,
1551
+ },
1552
+ { pubkey: userVolumeAccumulator, isSigner: false, isWritable: true },
1378
1553
  );
1379
1554
  }
1380
1555
  remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
1381
1556
  remainingKeys.push(
1382
1557
  { pubkey: newFeeRecipient, isSigner: false, isWritable: false },
1383
- { pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true }
1558
+ {
1559
+ pubkey: newFeeRecipientTokenAccount,
1560
+ isSigner: false,
1561
+ isWritable: true,
1562
+ },
1384
1563
  );
1385
1564
 
1386
1565
  return new TransactionInstruction({
@@ -1393,65 +1572,93 @@ export class PumpTrader {
1393
1572
  { pubkey: poolKeys.quoteMint, isSigner: false, isWritable: false },
1394
1573
  { pubkey: userBaseAta, isSigner: false, isWritable: true },
1395
1574
  { pubkey: userQuoteAta, isSigner: false, isWritable: true },
1396
- { pubkey: poolKeys.poolBaseTokenAccount, isSigner: false, isWritable: true },
1397
- { pubkey: poolKeys.poolQuoteTokenAccount, isSigner: false, isWritable: true },
1575
+ {
1576
+ pubkey: poolKeys.poolBaseTokenAccount,
1577
+ isSigner: false,
1578
+ isWritable: true,
1579
+ },
1580
+ {
1581
+ pubkey: poolKeys.poolQuoteTokenAccount,
1582
+ isSigner: false,
1583
+ isWritable: true,
1584
+ },
1398
1585
  { pubkey: protocolFeeRecipient, isSigner: false, isWritable: false },
1399
- { pubkey: protocolFeeRecipientTokenAccount, isSigner: false, isWritable: true },
1586
+ {
1587
+ pubkey: protocolFeeRecipientTokenAccount,
1588
+ isSigner: false,
1589
+ isWritable: true,
1590
+ },
1400
1591
  { pubkey: tokenProgramId, isSigner: false, isWritable: false },
1401
1592
  { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1402
1593
  { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1403
- { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1594
+ {
1595
+ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
1596
+ isSigner: false,
1597
+ isWritable: false,
1598
+ },
1404
1599
  { pubkey: eventAuthority, isSigner: false, isWritable: false },
1405
1600
  { pubkey: PROGRAM_IDS.PUMP_AMM, isSigner: false, isWritable: false },
1406
1601
  { pubkey: coinCreatorVaultAta, isSigner: false, isWritable: true },
1407
- { pubkey: coinCreatorVaultAuthority, isSigner: false, isWritable: false },
1602
+ {
1603
+ pubkey: coinCreatorVaultAuthority,
1604
+ isSigner: false,
1605
+ isWritable: false,
1606
+ },
1408
1607
  { pubkey: feeConfig, isSigner: false, isWritable: false },
1409
1608
  { pubkey: PROGRAM_IDS.FEE, isSigner: false, isWritable: false },
1410
- ...remainingKeys
1609
+ ...remainingKeys,
1411
1610
  ],
1412
1611
  data: Buffer.concat([
1413
1612
  DISCRIMINATORS.SELL,
1414
1613
  u64(baseAmountIn),
1415
- u64(minQuoteAmountOut > 0n ? minQuoteAmountOut : 1n)
1416
- ])
1614
+ u64(minQuoteAmountOut > 0n ? minQuoteAmountOut : 1n),
1615
+ ]),
1417
1616
  });
1418
1617
  }
1419
1618
 
1420
1619
  /* ---------- 交易确认 ---------- */
1421
1620
 
1422
- async confirmTransactionWithPolling(signature, lastValidBlockHeight, maxAttempts = 5, delayMs = 2000) {
1423
- console.log('✅ 交易已发送:', signature);
1424
- console.log('🔗 查看交易: https://solscan.io/tx/' + signature);
1621
+ async confirmTransactionWithPolling(
1622
+ signature,
1623
+ lastValidBlockHeight,
1624
+ maxAttempts = 5,
1625
+ delayMs = 2000,
1626
+ ) {
1627
+ console.log("✅ 交易已发送:", signature);
1628
+ console.log("🔗 查看交易: https://solscan.io/tx/" + signature);
1425
1629
 
1426
1630
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1427
- await new Promise(resolve => setTimeout(resolve, delayMs));
1631
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1428
1632
 
1429
1633
  try {
1430
1634
  console.log(`🔍 检查交易状态 (${attempt}/${maxAttempts})...`);
1431
1635
 
1432
1636
  const txInfo = await this.connection.getTransaction(signature, {
1433
- commitment: 'confirmed',
1434
- maxSupportedTransactionVersion: 0
1637
+ commitment: "confirmed",
1638
+ maxSupportedTransactionVersion: 0,
1435
1639
  });
1436
1640
 
1437
1641
  if (txInfo) {
1438
1642
  if (txInfo.meta?.err) {
1439
- console.error('❌ 交易失败:', txInfo.meta.err);
1440
- throw new Error('交易失败: ' + JSON.stringify(txInfo.meta.err));
1643
+ console.error("❌ 交易失败:", txInfo.meta.err);
1644
+ throw new Error("交易失败: " + JSON.stringify(txInfo.meta.err));
1441
1645
  }
1442
1646
 
1443
- console.log('✅ 交易已确认!');
1647
+ console.log("✅ 交易已确认!");
1444
1648
  return signature;
1445
1649
  }
1446
1650
 
1447
- const currentBlockHeight = await this.connection.getBlockHeight('finalized');
1651
+ const currentBlockHeight =
1652
+ await this.connection.getBlockHeight("finalized");
1448
1653
  if (currentBlockHeight > lastValidBlockHeight) {
1449
- console.log('⚠️ 交易已过期(超过有效区块高度)');
1450
- throw new Error('交易过期:未在有效区块高度内确认');
1654
+ console.log("⚠️ 交易已过期(超过有效区块高度)");
1655
+ throw new Error("交易过期:未在有效区块高度内确认");
1451
1656
  }
1452
-
1453
1657
  } catch (error) {
1454
- if (error.message?.includes('交易失败') || error.message?.includes('交易过期')) {
1658
+ if (
1659
+ error.message?.includes("交易失败") ||
1660
+ error.message?.includes("交易过期")
1661
+ ) {
1455
1662
  throw error;
1456
1663
  }
1457
1664
  console.log(`⚠️ 查询出错,继续重试: ${error.message}`);
@@ -1459,7 +1666,7 @@ export class PumpTrader {
1459
1666
  }
1460
1667
 
1461
1668
  throw new Error(
1462
- `交易确认超时(已尝试 ${maxAttempts} 次),签名: ${signature}。请手动检查交易状态。`
1669
+ `交易确认超时(已尝试 ${maxAttempts} 次),签名: ${signature}。请手动检查交易状态。`,
1463
1670
  );
1464
1671
  }
1465
1672
 
@@ -1472,7 +1679,10 @@ export class PumpTrader {
1472
1679
  for (const logLine of log.logs) {
1473
1680
  if (!logLine.startsWith("Program data: ")) continue;
1474
1681
 
1475
- const buf = Buffer.from(logLine.replace("Program data: ", ""), "base64");
1682
+ const buf = Buffer.from(
1683
+ logLine.replace("Program data: ", ""),
1684
+ "base64",
1685
+ );
1476
1686
 
1477
1687
  if (!buf.subarray(0, 8).equals(DISCRIMINATORS.TRADE_EVENT)) continue;
1478
1688
 
@@ -1498,11 +1708,11 @@ export class PumpTrader {
1498
1708
  isBuy,
1499
1709
  user: user.toBase58(),
1500
1710
  timestamp,
1501
- signature: log.signature
1711
+ signature: log.signature,
1502
1712
  });
1503
1713
  }
1504
1714
  },
1505
- "confirmed"
1715
+ "confirmed",
1506
1716
  );
1507
1717
  }
1508
1718
 
@@ -1515,18 +1725,22 @@ export class PumpTrader {
1515
1725
  const metadata = await getTokenMetadata(
1516
1726
  this.connection,
1517
1727
  mint,
1518
- TOKEN_2022_PROGRAM_ID
1728
+ TOKEN_2022_PROGRAM_ID,
1519
1729
  );
1520
1730
 
1521
1731
  return {
1522
1732
  name: metadata?.name || "",
1523
1733
  symbol: metadata?.symbol || "",
1524
- uri: metadata?.uri || ""
1734
+ uri: metadata?.uri || "",
1525
1735
  };
1526
1736
  } catch (e) {
1527
1737
  const metadataPda = PublicKey.findProgramAddressSync(
1528
- [Buffer.from("metadata"), PROGRAM_IDS.METADATA.toBuffer(), mint.toBuffer()],
1529
- PROGRAM_IDS.METADATA
1738
+ [
1739
+ Buffer.from("metadata"),
1740
+ PROGRAM_IDS.METADATA.toBuffer(),
1741
+ mint.toBuffer(),
1742
+ ],
1743
+ PROGRAM_IDS.METADATA,
1530
1744
  )[0];
1531
1745
 
1532
1746
  const acc = await this.connection.getAccountInfo(metadataPda);
@@ -1535,9 +1749,9 @@ export class PumpTrader {
1535
1749
  const meta = parseMetadataAccount(acc.data);
1536
1750
 
1537
1751
  return {
1538
- name: meta?.name?.replace(/\u0000/g, '') || "",
1539
- symbol: meta?.symbol?.replace(/\u0000/g, '') || "",
1540
- uri: meta?.uri?.replace(/\u0000/g, '') || ""
1752
+ name: meta?.name?.replace(/\u0000/g, "") || "",
1753
+ symbol: meta?.symbol?.replace(/\u0000/g, "") || "",
1754
+ uri: meta?.uri?.replace(/\u0000/g, "") || "",
1541
1755
  };
1542
1756
  }
1543
1757
  }