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 +4 -1
- package/dist/index.js +28 -5
- package/index.js +35 -5
- package/index.ts +35 -5
- package/package.json +1 -1
- package/tests/instruction-accounts.test.ts +92 -0
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
|
|
345
|
-
const
|
|
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(),
|
|
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
|
|
434
|
-
const
|
|
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(),
|
|
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
|
|
572
|
-
const
|
|
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(),
|
|
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
|
@@ -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
|
+
});
|