pump-trader 1.1.4 → 1.1.5

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/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ interface BondingCurveState {
33
33
  realSolReserves: bigint;
34
34
  tokenTotalSupply: bigint;
35
35
  complete: boolean;
36
+ quoteMint?: PublicKey;
36
37
  isMayhemMode?: boolean;
37
38
  isCashbackCoin?: boolean;
38
39
  }
@@ -116,7 +117,9 @@ export declare class PumpTrader {
116
117
  price: number;
117
118
  completed: boolean;
118
119
  }>;
119
- getAmmPrice(mint: PublicKey): Promise<number>;
120
+ getAmmPrice(mint: PublicKey, quoteMint?: PublicKey): Promise<number>;
121
+ private getEffectiveQuoteMint;
122
+ private getMintDecimals;
120
123
  /**
121
124
  * 查询代币余额
122
125
  * @param tokenAddr - 代币地址(可选),如果不传则返回所有代币
package/dist/index.js CHANGED
@@ -304,6 +304,10 @@ class PumpTrader {
304
304
  offset += 1;
305
305
  const creator = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
306
306
  offset += 32;
307
+ if (offset + 32 <= data.length - 2) {
308
+ state.quoteMint = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
309
+ offset += 32;
310
+ }
307
311
  state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
308
312
  offset += 1;
309
313
  state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
@@ -336,19 +340,21 @@ class PumpTrader {
336
340
  async getPriceAndStatus(tokenAddr) {
337
341
  const mint = new web3_js_1.PublicKey(tokenAddr);
338
342
  const { state } = await this.loadBonding(mint);
343
+ const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
339
344
  if (state.complete) {
340
- const price = await this.getAmmPrice(mint);
345
+ const price = await this.getAmmPrice(mint, quoteMint);
341
346
  return { price, completed: true };
342
347
  }
343
348
  const oneToken = BigInt(1_000_000);
344
- const solOut = this.calcSell(oneToken, state);
345
- const price = Number(solOut) / 1e9;
349
+ const quoteOut = this.calcSell(oneToken, state);
350
+ const quoteDecimals = await this.getMintDecimals(quoteMint);
351
+ const price = Number(quoteOut) / 10 ** quoteDecimals;
346
352
  return { price, completed: false };
347
353
  }
348
- async getAmmPrice(mint) {
354
+ async getAmmPrice(mint, quoteMint = SOL_MINT) {
349
355
  const [poolCreator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool-authority"), mint.toBuffer()], PROGRAM_IDS.PUMP);
350
356
  const indexBuffer = new bn_js_1.default(0).toArrayLike(Buffer, "le", 2);
351
- const [pool] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), SOL_MINT.toBuffer()], PROGRAM_IDS.PUMP_AMM);
357
+ const [pool] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), quoteMint.toBuffer()], PROGRAM_IDS.PUMP_AMM);
352
358
  const acc = await this.connection.getAccountInfo(pool);
353
359
  if (!acc)
354
360
  throw new Error("Pool not found");
@@ -359,6 +365,23 @@ class PumpTrader {
359
365
  ]);
360
366
  return quoteInfo.value.uiAmount / baseInfo.value.uiAmount;
361
367
  }
368
+ getEffectiveQuoteMint(quoteMint) {
369
+ if (!quoteMint || quoteMint.equals(web3_js_1.PublicKey.default)) {
370
+ return SOL_MINT;
371
+ }
372
+ return quoteMint;
373
+ }
374
+ async getMintDecimals(mint) {
375
+ if (mint.equals(SOL_MINT)) {
376
+ return 9;
377
+ }
378
+ const mintInfo = await this.connection.getParsedAccountInfo(mint);
379
+ const parsedData = mintInfo.value?.data;
380
+ if (parsedData && "parsed" in parsedData) {
381
+ return parsedData.parsed.info.decimals;
382
+ }
383
+ throw new Error(`Unable to determine mint decimals for ${mint.toBase58()}`);
384
+ }
362
385
  /* ---------- 余额查询 ---------- */
363
386
  /**
364
387
  * 查询代币余额
package/index.js CHANGED
@@ -383,6 +383,12 @@ export class PumpTrader {
383
383
 
384
384
  const creator = new PublicKey(data.slice(offset, offset + 32));
385
385
  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
+
386
392
  state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
387
393
  offset += 1;
388
394
  state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
@@ -423,19 +429,21 @@ export class PumpTrader {
423
429
  async getPriceAndStatus(tokenAddr) {
424
430
  const mint = new PublicKey(tokenAddr);
425
431
  const { state } = await this.loadBonding(mint);
432
+ const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
426
433
 
427
434
  if (state.complete) {
428
- const price = await this.getAmmPrice(mint);
435
+ const price = await this.getAmmPrice(mint, quoteMint);
429
436
  return { price, completed: true };
430
437
  }
431
438
 
432
439
  const oneToken = BigInt(1_000_000);
433
- const solOut = this.calcSell(oneToken, state);
434
- const price = Number(solOut) / 1e9;
440
+ const quoteOut = this.calcSell(oneToken, state);
441
+ const quoteDecimals = await this.getMintDecimals(quoteMint);
442
+ const price = Number(quoteOut) / 10 ** quoteDecimals;
435
443
  return { price, completed: false };
436
444
  }
437
445
 
438
- async getAmmPrice(mint) {
446
+ async getAmmPrice(mint, quoteMint = SOL_MINT) {
439
447
  const [poolCreator] = PublicKey.findProgramAddressSync(
440
448
  [Buffer.from("pool-authority"), mint.toBuffer()],
441
449
  PROGRAM_IDS.PUMP
@@ -443,7 +451,7 @@ export class PumpTrader {
443
451
 
444
452
  const indexBuffer = new BN(0).toArrayLike(Buffer, "le", 2);
445
453
  const [pool] = PublicKey.findProgramAddressSync(
446
- [Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), SOL_MINT.toBuffer()],
454
+ [Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), quoteMint.toBuffer()],
447
455
  PROGRAM_IDS.PUMP_AMM
448
456
  );
449
457
 
@@ -459,6 +467,28 @@ export class PumpTrader {
459
467
  return quoteInfo.value.uiAmount / baseInfo.value.uiAmount;
460
468
  }
461
469
 
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
+
462
492
  /* ---------- 余额查询 ---------- */
463
493
 
464
494
  /**
package/index.ts CHANGED
@@ -64,6 +64,7 @@ interface BondingCurveState {
64
64
  realSolReserves: bigint;
65
65
  tokenTotalSupply: bigint;
66
66
  complete: boolean;
67
+ quoteMint?: PublicKey;
67
68
  isMayhemMode?: boolean;
68
69
  isCashbackCoin?: boolean;
69
70
  }
@@ -521,6 +522,11 @@ export class PumpTrader {
521
522
  const creator = new PublicKey(data.slice(offset, offset + 32));
522
523
  offset += 32;
523
524
 
525
+ if (offset + 32 <= data.length - 2) {
526
+ state.quoteMint = new PublicKey(data.slice(offset, offset + 32));
527
+ offset += 32;
528
+ }
529
+
524
530
  state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
525
531
  offset += 1;
526
532
  state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
@@ -561,19 +567,21 @@ export class PumpTrader {
561
567
  async getPriceAndStatus(tokenAddr: string): Promise<{ price: number; completed: boolean }> {
562
568
  const mint = new PublicKey(tokenAddr);
563
569
  const { state } = await this.loadBonding(mint);
570
+ const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
564
571
 
565
572
  if (state.complete) {
566
- const price = await this.getAmmPrice(mint);
573
+ const price = await this.getAmmPrice(mint, quoteMint);
567
574
  return { price, completed: true };
568
575
  }
569
576
 
570
577
  const oneToken = BigInt(1_000_000);
571
- const solOut = this.calcSell(oneToken, state);
572
- const price = Number(solOut) / 1e9;
578
+ const quoteOut = this.calcSell(oneToken, state);
579
+ const quoteDecimals = await this.getMintDecimals(quoteMint);
580
+ const price = Number(quoteOut) / 10 ** quoteDecimals;
573
581
  return { price, completed: false };
574
582
  }
575
583
 
576
- async getAmmPrice(mint: PublicKey): Promise<number> {
584
+ async getAmmPrice(mint: PublicKey, quoteMint: PublicKey = SOL_MINT): Promise<number> {
577
585
  const [poolCreator] = PublicKey.findProgramAddressSync(
578
586
  [Buffer.from("pool-authority"), mint.toBuffer()],
579
587
  PROGRAM_IDS.PUMP
@@ -581,7 +589,7 @@ export class PumpTrader {
581
589
 
582
590
  const indexBuffer = new BN(0).toArrayLike(Buffer, "le", 2);
583
591
  const [pool] = PublicKey.findProgramAddressSync(
584
- [Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), SOL_MINT.toBuffer()],
592
+ [Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), quoteMint.toBuffer()],
585
593
  PROGRAM_IDS.PUMP_AMM
586
594
  );
587
595
 
@@ -597,6 +605,28 @@ export class PumpTrader {
597
605
  return quoteInfo.value.uiAmount! / baseInfo.value.uiAmount!;
598
606
  }
599
607
 
608
+ private getEffectiveQuoteMint(quoteMint?: PublicKey): PublicKey {
609
+ if (!quoteMint || quoteMint.equals(PublicKey.default)) {
610
+ return SOL_MINT;
611
+ }
612
+ return quoteMint;
613
+ }
614
+
615
+ private async getMintDecimals(mint: PublicKey): Promise<number> {
616
+ if (mint.equals(SOL_MINT)) {
617
+ return 9;
618
+ }
619
+
620
+ const mintInfo = await this.connection.getParsedAccountInfo(mint);
621
+ const parsedData = mintInfo.value?.data;
622
+
623
+ if (parsedData && "parsed" in parsedData) {
624
+ return parsedData.parsed.info.decimals;
625
+ }
626
+
627
+ throw new Error(`Unable to determine mint decimals for ${mint.toBase58()}`);
628
+ }
629
+
600
630
  /* ---------- 余额查询 ---------- */
601
631
 
602
632
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pump-trader",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "PumpFun 交易库 - 自动判断 Token Program 和内盘/外盘",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,6 +8,7 @@ import { ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, TOKEN_PROGR
8
8
  import { PumpTrader } from "../index";
9
9
 
10
10
  const SOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
11
+ const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
11
12
  const FEE_RECIPIENTS = [
12
13
  "5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
13
14
  "9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7",
@@ -207,3 +208,94 @@ test("amm sell places cashback accounts before poolV2 and fee recipient tail", (
207
208
  ).toBase58());
208
209
  assert.equal(instruction.keys.at(-1)?.isWritable, true);
209
210
  });
211
+
212
+ test("loadBonding parses quote mint from v2 bonding curve accounts", async () => {
213
+ const trader = createTrader() as any;
214
+ const mint = Keypair.generate().publicKey;
215
+ const creator = Keypair.generate().publicKey;
216
+ const data = Buffer.alloc(115);
217
+
218
+ let offset = 8;
219
+ data.writeBigUInt64LE(11n, offset);
220
+ offset += 8;
221
+ data.writeBigUInt64LE(22n, offset);
222
+ offset += 8;
223
+ data.writeBigUInt64LE(33n, offset);
224
+ offset += 8;
225
+ data.writeBigUInt64LE(44n, offset);
226
+ offset += 8;
227
+ data.writeBigUInt64LE(55n, offset);
228
+ offset += 8;
229
+ data[offset] = 1;
230
+ offset += 1;
231
+ creator.toBuffer().copy(data, offset);
232
+ offset += 32;
233
+ USDC_MINT.toBuffer().copy(data, offset);
234
+ offset += 32;
235
+ data[offset] = 1;
236
+ offset += 1;
237
+ data[offset] = 0;
238
+
239
+ trader.connection.getAccountInfo = async () => ({ data });
240
+
241
+ const result = await trader.loadBonding(mint);
242
+
243
+ assert.equal(result.creator.toBase58(), creator.toBase58());
244
+ assert.equal(result.state.quoteMint?.toBase58(), USDC_MINT.toBase58());
245
+ assert.equal(result.state.isMayhemMode, true);
246
+ assert.equal(result.state.isCashbackCoin, false);
247
+ });
248
+
249
+ test("getPriceAndStatus uses quote mint decimals for incomplete bonding curves", async () => {
250
+ const trader = createTrader() as any;
251
+ trader.loadBonding = async () => ({
252
+ bonding: Keypair.generate().publicKey,
253
+ creator: Keypair.generate().publicKey,
254
+ state: {
255
+ complete: false,
256
+ quoteMint: USDC_MINT
257
+ }
258
+ });
259
+ trader.calcSell = () => 1_234_567n;
260
+ trader.connection.getParsedAccountInfo = async () => ({
261
+ value: {
262
+ data: {
263
+ parsed: {
264
+ info: {
265
+ decimals: 6
266
+ }
267
+ }
268
+ }
269
+ }
270
+ });
271
+
272
+ const result = await trader.getPriceAndStatus(Keypair.generate().publicKey.toBase58());
273
+
274
+ assert.equal(result.completed, false);
275
+ assert.equal(result.price, 1.234567);
276
+ });
277
+
278
+ test("getPriceAndStatus forwards quote mint to AMM pricing for completed curves", async () => {
279
+ const trader = createTrader() as any;
280
+ const calls: PublicKey[][] = [];
281
+
282
+ trader.loadBonding = async () => ({
283
+ bonding: Keypair.generate().publicKey,
284
+ creator: Keypair.generate().publicKey,
285
+ state: {
286
+ complete: true,
287
+ quoteMint: USDC_MINT
288
+ }
289
+ });
290
+ trader.getAmmPrice = async (...args: PublicKey[]) => {
291
+ calls.push(args);
292
+ return 0.42;
293
+ };
294
+
295
+ const result = await trader.getPriceAndStatus(Keypair.generate().publicKey.toBase58());
296
+
297
+ assert.equal(result.completed, true);
298
+ assert.equal(result.price, 0.42);
299
+ assert.equal(calls.length, 1);
300
+ assert.equal(calls[0][1]?.toBase58(), USDC_MINT.toBase58());
301
+ });