pump-trader 1.1.3 → 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 +7 -1
- package/dist/index.js +134 -46
- package/docs/plans/2026-04-29-pump-fee-recipient-design.md +34 -0
- package/docs/plans/2026-04-29-pump-fee-recipient.md +143 -0
- package/index.js +173 -52
- package/index.ts +206 -47
- package/package.json +2 -1
- package/tests/instruction-accounts.test.ts +301 -0
package/index.js
CHANGED
|
@@ -56,6 +56,16 @@ const DISCRIMINATORS = {
|
|
|
56
56
|
|
|
57
57
|
const AMM_FEE_BPS = 100n; // 1%
|
|
58
58
|
const BPS_DENOMINATOR = 10000n;
|
|
59
|
+
const PUMP_NEW_FEE_RECIPIENTS = [
|
|
60
|
+
"5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
|
|
61
|
+
"9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7",
|
|
62
|
+
"GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL",
|
|
63
|
+
"3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR",
|
|
64
|
+
"5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6",
|
|
65
|
+
"EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL",
|
|
66
|
+
"5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD",
|
|
67
|
+
"A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"
|
|
68
|
+
].map((value) => new PublicKey(value));
|
|
59
69
|
|
|
60
70
|
/* ================= 工具函数 ================= */
|
|
61
71
|
|
|
@@ -294,6 +304,66 @@ export class PumpTrader {
|
|
|
294
304
|
)[0];
|
|
295
305
|
}
|
|
296
306
|
|
|
307
|
+
pickFeeRecipient(index = 0) {
|
|
308
|
+
return PUMP_NEW_FEE_RECIPIENTS[index % PUMP_NEW_FEE_RECIPIENTS.length];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
buildBondingBuyKeys(args) {
|
|
312
|
+
const tokenProgramId = args.tokenProgramId ?? TOKEN_PROGRAM_ID;
|
|
313
|
+
|
|
314
|
+
return [
|
|
315
|
+
{ pubkey: args.global, isSigner: false, isWritable: false },
|
|
316
|
+
{ pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
|
|
317
|
+
{ pubkey: args.mint, isSigner: false, isWritable: false },
|
|
318
|
+
{ pubkey: args.bonding, isSigner: false, isWritable: true },
|
|
319
|
+
{ pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
|
|
320
|
+
{ pubkey: args.userAta, isSigner: false, isWritable: true },
|
|
321
|
+
{ pubkey: args.wallet, isSigner: true, isWritable: true },
|
|
322
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
323
|
+
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
|
324
|
+
{ pubkey: args.creatorVault, isSigner: false, isWritable: true },
|
|
325
|
+
{ pubkey: args.eventAuthority, isSigner: false, isWritable: false },
|
|
326
|
+
{ pubkey: args.pumpProgram, isSigner: false, isWritable: false },
|
|
327
|
+
{ pubkey: args.globalVolumeAccumulator, isSigner: false, isWritable: false },
|
|
328
|
+
{ pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true },
|
|
329
|
+
{ pubkey: args.feeConfig, isSigner: false, isWritable: false },
|
|
330
|
+
{ pubkey: args.feeProgram, isSigner: false, isWritable: false },
|
|
331
|
+
{ pubkey: args.bondingCurveV2, isSigner: false, isWritable: false },
|
|
332
|
+
{ pubkey: args.feeRecipient, isSigner: false, isWritable: true }
|
|
333
|
+
];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
buildBondingSellKeys(args) {
|
|
337
|
+
const tokenProgramId = args.tokenProgramId ?? TOKEN_PROGRAM_ID;
|
|
338
|
+
const keys = [
|
|
339
|
+
{ pubkey: args.global, isSigner: false, isWritable: false },
|
|
340
|
+
{ pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
|
|
341
|
+
{ pubkey: args.mint, isSigner: false, isWritable: false },
|
|
342
|
+
{ pubkey: args.bonding, isSigner: false, isWritable: true },
|
|
343
|
+
{ pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
|
|
344
|
+
{ pubkey: args.userAta, isSigner: false, isWritable: true },
|
|
345
|
+
{ pubkey: args.wallet, isSigner: true, isWritable: true },
|
|
346
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
347
|
+
{ pubkey: args.creatorVault, isSigner: false, isWritable: true },
|
|
348
|
+
{ pubkey: tokenProgramId, isSigner: false, isWritable: false },
|
|
349
|
+
{ pubkey: args.eventAuthority, isSigner: false, isWritable: false },
|
|
350
|
+
{ pubkey: args.pumpProgram, isSigner: false, isWritable: false },
|
|
351
|
+
{ pubkey: args.feeConfig, isSigner: false, isWritable: false },
|
|
352
|
+
{ pubkey: args.feeProgram, isSigner: false, isWritable: false }
|
|
353
|
+
];
|
|
354
|
+
|
|
355
|
+
if (args.isCashbackCoin) {
|
|
356
|
+
keys.push({ pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
keys.push(
|
|
360
|
+
{ pubkey: args.bondingCurveV2, isSigner: false, isWritable: false },
|
|
361
|
+
{ pubkey: args.feeRecipient, isSigner: false, isWritable: true }
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
return keys;
|
|
365
|
+
}
|
|
366
|
+
|
|
297
367
|
async loadBonding(mint) {
|
|
298
368
|
const bonding = this.getBondingPda(mint);
|
|
299
369
|
const acc = await this.connection.getAccountInfo(bonding);
|
|
@@ -313,6 +383,12 @@ export class PumpTrader {
|
|
|
313
383
|
|
|
314
384
|
const creator = new PublicKey(data.slice(offset, offset + 32));
|
|
315
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
|
+
|
|
316
392
|
state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
|
|
317
393
|
offset += 1;
|
|
318
394
|
state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
|
|
@@ -353,19 +429,21 @@ export class PumpTrader {
|
|
|
353
429
|
async getPriceAndStatus(tokenAddr) {
|
|
354
430
|
const mint = new PublicKey(tokenAddr);
|
|
355
431
|
const { state } = await this.loadBonding(mint);
|
|
432
|
+
const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
|
|
356
433
|
|
|
357
434
|
if (state.complete) {
|
|
358
|
-
const price = await this.getAmmPrice(mint);
|
|
435
|
+
const price = await this.getAmmPrice(mint, quoteMint);
|
|
359
436
|
return { price, completed: true };
|
|
360
437
|
}
|
|
361
438
|
|
|
362
439
|
const oneToken = BigInt(1_000_000);
|
|
363
|
-
const
|
|
364
|
-
const
|
|
440
|
+
const quoteOut = this.calcSell(oneToken, state);
|
|
441
|
+
const quoteDecimals = await this.getMintDecimals(quoteMint);
|
|
442
|
+
const price = Number(quoteOut) / 10 ** quoteDecimals;
|
|
365
443
|
return { price, completed: false };
|
|
366
444
|
}
|
|
367
445
|
|
|
368
|
-
async getAmmPrice(mint) {
|
|
446
|
+
async getAmmPrice(mint, quoteMint = SOL_MINT) {
|
|
369
447
|
const [poolCreator] = PublicKey.findProgramAddressSync(
|
|
370
448
|
[Buffer.from("pool-authority"), mint.toBuffer()],
|
|
371
449
|
PROGRAM_IDS.PUMP
|
|
@@ -373,7 +451,7 @@ export class PumpTrader {
|
|
|
373
451
|
|
|
374
452
|
const indexBuffer = new BN(0).toArrayLike(Buffer, "le", 2);
|
|
375
453
|
const [pool] = PublicKey.findProgramAddressSync(
|
|
376
|
-
[Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(),
|
|
454
|
+
[Buffer.from("pool"), indexBuffer, poolCreator.toBuffer(), mint.toBuffer(), quoteMint.toBuffer()],
|
|
377
455
|
PROGRAM_IDS.PUMP_AMM
|
|
378
456
|
);
|
|
379
457
|
|
|
@@ -389,6 +467,28 @@ export class PumpTrader {
|
|
|
389
467
|
return quoteInfo.value.uiAmount / baseInfo.value.uiAmount;
|
|
390
468
|
}
|
|
391
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
|
+
|
|
392
492
|
/* ---------- 余额查询 ---------- */
|
|
393
493
|
|
|
394
494
|
/**
|
|
@@ -667,17 +767,7 @@ export class PumpTrader {
|
|
|
667
767
|
[Buffer.from("fee_config"), SEEDS.FEE_CONFIG],
|
|
668
768
|
PROGRAM_IDS.FEE
|
|
669
769
|
);
|
|
670
|
-
|
|
671
|
-
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
|
|
672
|
-
[Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
|
|
673
|
-
PROGRAM_IDS.PUMP
|
|
674
|
-
);
|
|
675
|
-
|
|
676
|
-
const sellRemainingKeys = [];
|
|
677
|
-
if (state.isCashbackCoin) {
|
|
678
|
-
sellRemainingKeys.push({ pubkey: userVolumeAccumulator, isSigner: false, isWritable: true });
|
|
679
|
-
}
|
|
680
|
-
sellRemainingKeys.push({ pubkey: bondingCurveV2, isSigner: false, isWritable: false });
|
|
770
|
+
const feeRecipient = this.pickFeeRecipient();
|
|
681
771
|
|
|
682
772
|
for (let i = 0; i < solChunks.length; i++) {
|
|
683
773
|
try {
|
|
@@ -701,25 +791,25 @@ export class PumpTrader {
|
|
|
701
791
|
tx.add(
|
|
702
792
|
new TransactionInstruction({
|
|
703
793
|
programId: PROGRAM_IDS.PUMP,
|
|
704
|
-
keys:
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
794
|
+
keys: this.buildBondingBuyKeys({
|
|
795
|
+
global: this.global,
|
|
796
|
+
globalFeeRecipient: this.globalState.feeRecipient,
|
|
797
|
+
mint,
|
|
798
|
+
bonding,
|
|
799
|
+
associatedBondingCurve,
|
|
800
|
+
userAta,
|
|
801
|
+
wallet: this.wallet.publicKey,
|
|
802
|
+
creatorVault,
|
|
803
|
+
eventAuthority: PROGRAM_IDS.EVENT_AUTHORITY,
|
|
804
|
+
pumpProgram: PROGRAM_IDS.PUMP,
|
|
805
|
+
globalVolumeAccumulator,
|
|
806
|
+
userVolumeAccumulator,
|
|
807
|
+
feeConfig,
|
|
808
|
+
feeProgram: PROGRAM_IDS.FEE,
|
|
809
|
+
bondingCurveV2,
|
|
810
|
+
feeRecipient,
|
|
811
|
+
tokenProgramId: tokenProgram.programId
|
|
812
|
+
}),
|
|
723
813
|
data: Buffer.concat([DISCRIMINATORS.BUY, u64(tokenOut), u64(maxSol)])
|
|
724
814
|
})
|
|
725
815
|
);
|
|
@@ -797,6 +887,11 @@ export class PumpTrader {
|
|
|
797
887
|
[Buffer.from("fee_config"), SEEDS.FEE_CONFIG],
|
|
798
888
|
PROGRAM_IDS.FEE
|
|
799
889
|
);
|
|
890
|
+
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
|
|
891
|
+
[Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
|
|
892
|
+
PROGRAM_IDS.PUMP
|
|
893
|
+
);
|
|
894
|
+
const feeRecipient = this.pickFeeRecipient();
|
|
800
895
|
|
|
801
896
|
for (let i = 0; i < tokenChunks.length; i++) {
|
|
802
897
|
try {
|
|
@@ -818,23 +913,25 @@ export class PumpTrader {
|
|
|
818
913
|
tx.add(
|
|
819
914
|
new TransactionInstruction({
|
|
820
915
|
programId: PROGRAM_IDS.PUMP,
|
|
821
|
-
keys:
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
916
|
+
keys: this.buildBondingSellKeys({
|
|
917
|
+
global: this.global,
|
|
918
|
+
globalFeeRecipient: this.globalState.feeRecipient,
|
|
919
|
+
mint,
|
|
920
|
+
bonding,
|
|
921
|
+
associatedBondingCurve,
|
|
922
|
+
userAta,
|
|
923
|
+
wallet: this.wallet.publicKey,
|
|
924
|
+
creatorVault,
|
|
925
|
+
eventAuthority: PROGRAM_IDS.EVENT_AUTHORITY,
|
|
926
|
+
pumpProgram: PROGRAM_IDS.PUMP,
|
|
927
|
+
feeConfig,
|
|
928
|
+
feeProgram: PROGRAM_IDS.FEE,
|
|
929
|
+
bondingCurveV2,
|
|
930
|
+
feeRecipient,
|
|
931
|
+
isCashbackCoin: !!state.isCashbackCoin,
|
|
932
|
+
userVolumeAccumulator,
|
|
933
|
+
tokenProgramId: tokenProgram.programId
|
|
934
|
+
}),
|
|
838
935
|
data: Buffer.concat([
|
|
839
936
|
DISCRIMINATORS.SELL,
|
|
840
937
|
u64(tokenIn),
|
|
@@ -1153,6 +1250,14 @@ export class PumpTrader {
|
|
|
1153
1250
|
TOKEN_PROGRAM_ID,
|
|
1154
1251
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
1155
1252
|
);
|
|
1253
|
+
const newFeeRecipient = this.pickFeeRecipient();
|
|
1254
|
+
const newFeeRecipientTokenAccount = getAssociatedTokenAddressSync(
|
|
1255
|
+
poolKeys.quoteMint,
|
|
1256
|
+
newFeeRecipient,
|
|
1257
|
+
true,
|
|
1258
|
+
TOKEN_PROGRAM_ID,
|
|
1259
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
1260
|
+
);
|
|
1156
1261
|
|
|
1157
1262
|
const remainingKeys = [];
|
|
1158
1263
|
if (poolKeys.isCashbackCoin) {
|
|
@@ -1166,6 +1271,10 @@ export class PumpTrader {
|
|
|
1166
1271
|
remainingKeys.push({ pubkey: userVolumeAccumulatorWsolAta, isSigner: false, isWritable: true });
|
|
1167
1272
|
}
|
|
1168
1273
|
remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
|
|
1274
|
+
remainingKeys.push(
|
|
1275
|
+
{ pubkey: newFeeRecipient, isSigner: false, isWritable: false },
|
|
1276
|
+
{ pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true }
|
|
1277
|
+
);
|
|
1169
1278
|
|
|
1170
1279
|
return new TransactionInstruction({
|
|
1171
1280
|
programId: PROGRAM_IDS.PUMP_AMM,
|
|
@@ -1239,6 +1348,14 @@ export class PumpTrader {
|
|
|
1239
1348
|
TOKEN_PROGRAM_ID,
|
|
1240
1349
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
1241
1350
|
);
|
|
1351
|
+
const newFeeRecipient = this.pickFeeRecipient();
|
|
1352
|
+
const newFeeRecipientTokenAccount = getAssociatedTokenAddressSync(
|
|
1353
|
+
poolKeys.quoteMint,
|
|
1354
|
+
newFeeRecipient,
|
|
1355
|
+
true,
|
|
1356
|
+
TOKEN_PROGRAM_ID,
|
|
1357
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
1358
|
+
);
|
|
1242
1359
|
|
|
1243
1360
|
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
|
|
1244
1361
|
[Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()],
|
|
@@ -1261,6 +1378,10 @@ export class PumpTrader {
|
|
|
1261
1378
|
);
|
|
1262
1379
|
}
|
|
1263
1380
|
remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
|
|
1381
|
+
remainingKeys.push(
|
|
1382
|
+
{ pubkey: newFeeRecipient, isSigner: false, isWritable: false },
|
|
1383
|
+
{ pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true }
|
|
1384
|
+
);
|
|
1264
1385
|
|
|
1265
1386
|
return new TransactionInstruction({
|
|
1266
1387
|
programId: PROGRAM_IDS.PUMP_AMM,
|