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 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
  }
@@ -104,6 +105,9 @@ export declare class PumpTrader {
104
105
  loadGlobal(): Promise<GlobalState>;
105
106
  getBondingPda(mint: PublicKey): PublicKey;
106
107
  deriveBondingCurveV2(mint: PublicKey): PublicKey;
108
+ private pickFeeRecipient;
109
+ private buildBondingBuyKeys;
110
+ private buildBondingSellKeys;
107
111
  loadBonding(mint: PublicKey): Promise<BondingInfo>;
108
112
  calcBuy(solIn: bigint, state: BondingCurveState): bigint;
109
113
  calcSell(tokenIn: bigint, state: BondingCurveState): bigint;
@@ -113,7 +117,9 @@ export declare class PumpTrader {
113
117
  price: number;
114
118
  completed: boolean;
115
119
  }>;
116
- getAmmPrice(mint: PublicKey): Promise<number>;
120
+ getAmmPrice(mint: PublicKey, quoteMint?: PublicKey): Promise<number>;
121
+ private getEffectiveQuoteMint;
122
+ private getMintDecimals;
117
123
  /**
118
124
  * 查询代币余额
119
125
  * @param tokenAddr - 代币地址(可选),如果不传则返回所有代币
package/dist/index.js CHANGED
@@ -36,6 +36,16 @@ const DISCRIMINATORS = {
36
36
  };
37
37
  const AMM_FEE_BPS = 100n;
38
38
  const BPS_DENOMINATOR = 10000n;
39
+ const PUMP_NEW_FEE_RECIPIENTS = [
40
+ "5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD",
41
+ "9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7",
42
+ "GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL",
43
+ "3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR",
44
+ "5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6",
45
+ "EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL",
46
+ "5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD",
47
+ "A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"
48
+ ].map((value) => new web3_js_1.PublicKey(value));
39
49
  /* ================= 工具函数 ================= */
40
50
  const u64 = (v) => {
41
51
  const bn = typeof v === 'bigint' ? new bn_js_1.default(v.toString()) : new bn_js_1.default(v.toString());
@@ -227,6 +237,56 @@ class PumpTrader {
227
237
  deriveBondingCurveV2(mint) {
228
238
  return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("bonding-curve-v2"), mint.toBuffer()], PROGRAM_IDS.PUMP)[0];
229
239
  }
240
+ pickFeeRecipient(index = 0) {
241
+ return PUMP_NEW_FEE_RECIPIENTS[index % PUMP_NEW_FEE_RECIPIENTS.length];
242
+ }
243
+ buildBondingBuyKeys(args) {
244
+ const tokenProgramId = args.tokenProgramId ?? spl_token_1.TOKEN_PROGRAM_ID;
245
+ return [
246
+ { pubkey: args.global, isSigner: false, isWritable: false },
247
+ { pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
248
+ { pubkey: args.mint, isSigner: false, isWritable: false },
249
+ { pubkey: args.bonding, isSigner: false, isWritable: true },
250
+ { pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
251
+ { pubkey: args.userAta, isSigner: false, isWritable: true },
252
+ { pubkey: args.wallet, isSigner: true, isWritable: true },
253
+ { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
254
+ { pubkey: tokenProgramId, isSigner: false, isWritable: false },
255
+ { pubkey: args.creatorVault, isSigner: false, isWritable: true },
256
+ { pubkey: args.eventAuthority, isSigner: false, isWritable: false },
257
+ { pubkey: args.pumpProgram, isSigner: false, isWritable: false },
258
+ { pubkey: args.globalVolumeAccumulator, isSigner: false, isWritable: false },
259
+ { pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true },
260
+ { pubkey: args.feeConfig, isSigner: false, isWritable: false },
261
+ { pubkey: args.feeProgram, isSigner: false, isWritable: false },
262
+ { pubkey: args.bondingCurveV2, isSigner: false, isWritable: false },
263
+ { pubkey: args.feeRecipient, isSigner: false, isWritable: true }
264
+ ];
265
+ }
266
+ buildBondingSellKeys(args) {
267
+ const tokenProgramId = args.tokenProgramId ?? spl_token_1.TOKEN_PROGRAM_ID;
268
+ const keys = [
269
+ { pubkey: args.global, isSigner: false, isWritable: false },
270
+ { pubkey: args.globalFeeRecipient, isSigner: false, isWritable: true },
271
+ { pubkey: args.mint, isSigner: false, isWritable: false },
272
+ { pubkey: args.bonding, isSigner: false, isWritable: true },
273
+ { pubkey: args.associatedBondingCurve, isSigner: false, isWritable: true },
274
+ { pubkey: args.userAta, isSigner: false, isWritable: true },
275
+ { pubkey: args.wallet, isSigner: true, isWritable: true },
276
+ { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
277
+ { pubkey: args.creatorVault, isSigner: false, isWritable: true },
278
+ { pubkey: tokenProgramId, isSigner: false, isWritable: false },
279
+ { pubkey: args.eventAuthority, isSigner: false, isWritable: false },
280
+ { pubkey: args.pumpProgram, isSigner: false, isWritable: false },
281
+ { pubkey: args.feeConfig, isSigner: false, isWritable: false },
282
+ { pubkey: args.feeProgram, isSigner: false, isWritable: false }
283
+ ];
284
+ if (args.isCashbackCoin) {
285
+ keys.push({ pubkey: args.userVolumeAccumulator, isSigner: false, isWritable: true });
286
+ }
287
+ keys.push({ pubkey: args.bondingCurveV2, isSigner: false, isWritable: false }, { pubkey: args.feeRecipient, isSigner: false, isWritable: true });
288
+ return keys;
289
+ }
230
290
  async loadBonding(mint) {
231
291
  const bonding = this.getBondingPda(mint);
232
292
  const acc = await this.connection.getAccountInfo(bonding);
@@ -244,6 +304,10 @@ class PumpTrader {
244
304
  offset += 1;
245
305
  const creator = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
246
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
+ }
247
311
  state.isMayhemMode = offset < data.length ? data[offset] === 1 : false;
248
312
  offset += 1;
249
313
  state.isCashbackCoin = offset < data.length ? data[offset] === 1 : false;
@@ -276,19 +340,21 @@ class PumpTrader {
276
340
  async getPriceAndStatus(tokenAddr) {
277
341
  const mint = new web3_js_1.PublicKey(tokenAddr);
278
342
  const { state } = await this.loadBonding(mint);
343
+ const quoteMint = this.getEffectiveQuoteMint(state.quoteMint);
279
344
  if (state.complete) {
280
- const price = await this.getAmmPrice(mint);
345
+ const price = await this.getAmmPrice(mint, quoteMint);
281
346
  return { price, completed: true };
282
347
  }
283
348
  const oneToken = BigInt(1_000_000);
284
- const solOut = this.calcSell(oneToken, state);
285
- 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;
286
352
  return { price, completed: false };
287
353
  }
288
- async getAmmPrice(mint) {
354
+ async getAmmPrice(mint, quoteMint = SOL_MINT) {
289
355
  const [poolCreator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool-authority"), mint.toBuffer()], PROGRAM_IDS.PUMP);
290
356
  const indexBuffer = new bn_js_1.default(0).toArrayLike(Buffer, "le", 2);
291
- 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);
292
358
  const acc = await this.connection.getAccountInfo(pool);
293
359
  if (!acc)
294
360
  throw new Error("Pool not found");
@@ -299,6 +365,23 @@ class PumpTrader {
299
365
  ]);
300
366
  return quoteInfo.value.uiAmount / baseInfo.value.uiAmount;
301
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
+ }
302
385
  /* ---------- 余额查询 ---------- */
303
386
  /**
304
387
  * 查询代币余额
@@ -488,6 +571,7 @@ class PumpTrader {
488
571
  const [globalVolumeAccumulator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("global_volume_accumulator")], PROGRAM_IDS.PUMP);
489
572
  const [userVolumeAccumulator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()], PROGRAM_IDS.PUMP);
490
573
  const [feeConfig] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), SEEDS.FEE_CONFIG], PROGRAM_IDS.FEE);
574
+ const feeRecipient = this.pickFeeRecipient();
491
575
  for (let i = 0; i < solChunks.length; i++) {
492
576
  try {
493
577
  const solIn = solChunks[i];
@@ -503,25 +587,25 @@ class PumpTrader {
503
587
  const userAta = await this.ensureAta(tx, mint, tokenProgram.programId);
504
588
  tx.add(new web3_js_1.TransactionInstruction({
505
589
  programId: PROGRAM_IDS.PUMP,
506
- keys: [
507
- { pubkey: this.global, isSigner: false, isWritable: false },
508
- { pubkey: this.globalState.feeRecipient, isSigner: false, isWritable: true },
509
- { pubkey: mint, isSigner: false, isWritable: false },
510
- { pubkey: bonding, isSigner: false, isWritable: true },
511
- { pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
512
- { pubkey: userAta, isSigner: false, isWritable: true },
513
- { pubkey: this.wallet.publicKey, isSigner: true, isWritable: true },
514
- { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
515
- { pubkey: tokenProgram.programId, isSigner: false, isWritable: false },
516
- { pubkey: creatorVault, isSigner: false, isWritable: true },
517
- { pubkey: PROGRAM_IDS.EVENT_AUTHORITY, isSigner: false, isWritable: false },
518
- { pubkey: PROGRAM_IDS.PUMP, isSigner: false, isWritable: false },
519
- { pubkey: globalVolumeAccumulator, isSigner: false, isWritable: false },
520
- { pubkey: userVolumeAccumulator, isSigner: false, isWritable: true },
521
- { pubkey: feeConfig, isSigner: false, isWritable: false },
522
- { pubkey: PROGRAM_IDS.FEE, isSigner: false, isWritable: false },
523
- { pubkey: bondingCurveV2, isSigner: false, isWritable: false }
524
- ],
590
+ keys: this.buildBondingBuyKeys({
591
+ global: this.global,
592
+ globalFeeRecipient: this.globalState.feeRecipient,
593
+ mint,
594
+ bonding,
595
+ associatedBondingCurve,
596
+ userAta,
597
+ wallet: this.wallet.publicKey,
598
+ creatorVault,
599
+ eventAuthority: PROGRAM_IDS.EVENT_AUTHORITY,
600
+ pumpProgram: PROGRAM_IDS.PUMP,
601
+ globalVolumeAccumulator,
602
+ userVolumeAccumulator,
603
+ feeConfig,
604
+ feeProgram: PROGRAM_IDS.FEE,
605
+ bondingCurveV2,
606
+ feeRecipient,
607
+ tokenProgramId: tokenProgram.programId
608
+ }),
525
609
  data: Buffer.concat([DISCRIMINATORS.BUY, u64(tokenOut), u64(maxSol)])
526
610
  }));
527
611
  const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash('finalized');
@@ -567,11 +651,7 @@ class PumpTrader {
567
651
  const [creatorVault] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("creator-vault"), creator.toBuffer()], PROGRAM_IDS.PUMP);
568
652
  const [feeConfig] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), SEEDS.FEE_CONFIG], PROGRAM_IDS.FEE);
569
653
  const [userVolumeAccumulator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()], PROGRAM_IDS.PUMP);
570
- const sellRemainingKeys = [];
571
- if (state.isCashbackCoin) {
572
- sellRemainingKeys.push({ pubkey: userVolumeAccumulator, isSigner: false, isWritable: true });
573
- }
574
- sellRemainingKeys.push({ pubkey: bondingCurveV2, isSigner: false, isWritable: false });
654
+ const feeRecipient = this.pickFeeRecipient();
575
655
  for (let i = 0; i < tokenChunks.length; i++) {
576
656
  try {
577
657
  const tokenIn = tokenChunks[i];
@@ -586,23 +666,25 @@ class PumpTrader {
586
666
  const tx = new web3_js_1.Transaction().add(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }), web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority }));
587
667
  tx.add(new web3_js_1.TransactionInstruction({
588
668
  programId: PROGRAM_IDS.PUMP,
589
- keys: [
590
- { pubkey: this.global, isSigner: false, isWritable: false },
591
- { pubkey: this.globalState.feeRecipient, isSigner: false, isWritable: true },
592
- { pubkey: mint, isSigner: false, isWritable: false },
593
- { pubkey: bonding, isSigner: false, isWritable: true },
594
- { pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
595
- { pubkey: userAta, isSigner: false, isWritable: true },
596
- { pubkey: this.wallet.publicKey, isSigner: true, isWritable: true },
597
- { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
598
- { pubkey: creatorVault, isSigner: false, isWritable: true },
599
- { pubkey: tokenProgram.programId, isSigner: false, isWritable: false },
600
- { pubkey: PROGRAM_IDS.EVENT_AUTHORITY, isSigner: false, isWritable: false },
601
- { pubkey: PROGRAM_IDS.PUMP, isSigner: false, isWritable: false },
602
- { pubkey: feeConfig, isSigner: false, isWritable: false },
603
- { pubkey: PROGRAM_IDS.FEE, isSigner: false, isWritable: false },
604
- ...sellRemainingKeys
605
- ],
669
+ keys: this.buildBondingSellKeys({
670
+ global: this.global,
671
+ globalFeeRecipient: this.globalState.feeRecipient,
672
+ mint,
673
+ bonding,
674
+ associatedBondingCurve,
675
+ userAta,
676
+ wallet: this.wallet.publicKey,
677
+ creatorVault,
678
+ eventAuthority: PROGRAM_IDS.EVENT_AUTHORITY,
679
+ pumpProgram: PROGRAM_IDS.PUMP,
680
+ feeConfig,
681
+ feeProgram: PROGRAM_IDS.FEE,
682
+ bondingCurveV2,
683
+ feeRecipient,
684
+ isCashbackCoin: !!state.isCashbackCoin,
685
+ userVolumeAccumulator,
686
+ tokenProgramId: tokenProgram.programId
687
+ }),
606
688
  data: Buffer.concat([
607
689
  DISCRIMINATORS.SELL,
608
690
  u64(tokenIn),
@@ -791,12 +873,15 @@ class PumpTrader {
791
873
  const [feeConfig] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), SEEDS.AMM_FEE_CONFIG], PROGRAM_IDS.FEE);
792
874
  const protocolFeeRecipient = globalConfig.protocolFeeRecipients[0];
793
875
  const protocolFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(SOL_MINT, protocolFeeRecipient, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
876
+ const newFeeRecipient = this.pickFeeRecipient();
877
+ const newFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolKeys.quoteMint, newFeeRecipient, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
794
878
  const remainingKeys = [];
795
879
  if (poolKeys.isCashbackCoin) {
796
880
  const userVolumeAccumulatorWsolAta = (0, spl_token_1.getAssociatedTokenAddressSync)(SOL_MINT, userVolumeAccumulator, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
797
881
  remainingKeys.push({ pubkey: userVolumeAccumulatorWsolAta, isSigner: false, isWritable: true });
798
882
  }
799
883
  remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
884
+ remainingKeys.push({ pubkey: newFeeRecipient, isSigner: false, isWritable: false }, { pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true });
800
885
  return new web3_js_1.TransactionInstruction({
801
886
  programId: PROGRAM_IDS.PUMP_AMM,
802
887
  keys: [
@@ -842,6 +927,8 @@ class PumpTrader {
842
927
  const [feeConfig] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), SEEDS.AMM_FEE_CONFIG], PROGRAM_IDS.FEE);
843
928
  const protocolFeeRecipient = globalConfig.protocolFeeRecipients[0];
844
929
  const protocolFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(SOL_MINT, protocolFeeRecipient, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
930
+ const newFeeRecipient = this.pickFeeRecipient();
931
+ const newFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolKeys.quoteMint, newFeeRecipient, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
845
932
  const [userVolumeAccumulator] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("user_volume_accumulator"), this.wallet.publicKey.toBuffer()], PROGRAM_IDS.PUMP_AMM);
846
933
  const userVolumeAccumulatorWsolAta = (0, spl_token_1.getAssociatedTokenAddressSync)(SOL_MINT, userVolumeAccumulator, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
847
934
  const remainingKeys = [];
@@ -849,6 +936,7 @@ class PumpTrader {
849
936
  remainingKeys.push({ pubkey: userVolumeAccumulatorWsolAta, isSigner: false, isWritable: true }, { pubkey: userVolumeAccumulator, isSigner: false, isWritable: true });
850
937
  }
851
938
  remainingKeys.push({ pubkey: poolV2, isSigner: false, isWritable: false });
939
+ remainingKeys.push({ pubkey: newFeeRecipient, isSigner: false, isWritable: false }, { pubkey: newFeeRecipientTokenAccount, isSigner: false, isWritable: true });
852
940
  return new web3_js_1.TransactionInstruction({
853
941
  programId: PROGRAM_IDS.PUMP_AMM,
854
942
  keys: [
@@ -0,0 +1,34 @@
1
+ # Pump Fee Recipient Upgrade Design
2
+
3
+ **Context**
4
+
5
+ `pump-trader@1.1.3` currently hardcodes Pump bonding and AMM instruction account layouts that matched the pre-upgrade programs. Pump announced a breaking account layout change effective on April 28, 2026 at 16:00 UTC. After that upgrade, the existing instruction builders send the wrong account count and wrong trailing account order.
6
+
7
+ **Design**
8
+
9
+ Use a compatibility patch inside the existing handwritten instruction builders instead of migrating the project to the official SDKs. The patch adds the 8 published fee recipient addresses as constants, centralizes fee recipient selection behind a small helper, and updates the trailing account order for both bonding and AMM flows.
10
+
11
+ For bonding:
12
+ - append one mutable fee recipient after `bonding-curve-v2`
13
+ - keep all existing accounts before `bonding-curve-v2` unchanged
14
+
15
+ For AMM:
16
+ - keep existing accounts through `pool-v2`
17
+ - move the fee recipient pair to the end
18
+ - pass fee recipient as readonly
19
+ - pass quote mint ATA for that recipient as mutable
20
+
21
+ **Why This Approach**
22
+
23
+ This is the smallest change that restores runtime compatibility while preserving the library's current API and handwritten transaction flow. It also gives one future extension point for recipient selection without forcing an SDK dependency or wider refactor.
24
+
25
+ **Validation**
26
+
27
+ Add regression tests that assert instruction key count and tail ordering for:
28
+ - bonding buy
29
+ - bonding sell without cashback
30
+ - bonding sell with cashback
31
+ - AMM buy without cashback
32
+ - AMM buy with cashback
33
+ - AMM sell without cashback
34
+ - AMM sell with cashback
@@ -0,0 +1,143 @@
1
+ # Pump Fee Recipient Upgrade Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Update `pump-trader@1.1.3` so Pump bonding and AMM instructions remain compatible with the April 28, 2026 fee recipient account layout upgrade.
6
+
7
+ **Architecture:** Keep the existing handwritten instruction builders, add a centralized fee recipient selector, and rebuild the bonding and AMM account arrays so their tail order matches the upgraded programs. Use narrow regression tests that assert exact key ordering and account counts rather than broad network integration tests.
8
+
9
+ **Tech Stack:** TypeScript, Node.js built-in test runner, `tsx`, `@solana/web3.js`, `@solana/spl-token`
10
+
11
+ ---
12
+
13
+ ### Task 1: Add regression tests for upgraded account layouts
14
+
15
+ **Files:**
16
+ - Modify: `package.json`
17
+ - Create: `tests/instruction-accounts.test.ts`
18
+
19
+ **Step 1: Write the failing test**
20
+
21
+ Create tests that expect:
22
+ - bonding buy has 18 keys and the final two are `bondingCurveV2`, fee recipient
23
+ - bonding sell has 16 keys without cashback and 17 with cashback, with fee recipient last
24
+ - AMM buy has 26 keys without cashback and 27 with cashback, with `poolV2`, fee recipient, fee recipient quote ATA at the tail
25
+ - AMM sell has 24 keys without cashback and 26 with cashback, with the same tail order
26
+
27
+ **Step 2: Run test to verify it fails**
28
+
29
+ Run: `npm test`
30
+ Expected: FAIL because the new helper methods or expected key layout do not yet exist.
31
+
32
+ **Step 3: Write minimal implementation**
33
+
34
+ Add helper methods in `index.ts` that build the account arrays and are reused by the existing transaction builders.
35
+
36
+ **Step 4: Run test to verify it passes**
37
+
38
+ Run: `npm test`
39
+ Expected: PASS
40
+
41
+ **Step 5: Commit**
42
+
43
+ ```bash
44
+ git add package.json tests/instruction-accounts.test.ts index.ts index.js dist docs/plans
45
+ git commit -m "fix: support upgraded pump fee recipient accounts"
46
+ ```
47
+
48
+ ### Task 2: Update bonding instruction account assembly
49
+
50
+ **Files:**
51
+ - Modify: `index.ts`
52
+ - Modify: `index.js`
53
+ - Modify: `dist/index.js`
54
+ - Modify: `dist/index.d.ts`
55
+
56
+ **Step 1: Write the failing test**
57
+
58
+ Use the bonding tests from Task 1 as the failing coverage.
59
+
60
+ **Step 2: Run test to verify it fails**
61
+
62
+ Run: `npm test -- --test-name-pattern bonding`
63
+ Expected: FAIL because bonding key count and fee recipient tail order are still old.
64
+
65
+ **Step 3: Write minimal implementation**
66
+
67
+ Add the 8 fee recipient constants, selector helper, bonding key builders, and switch `buy()` / `sell()` to use them.
68
+
69
+ **Step 4: Run test to verify it passes**
70
+
71
+ Run: `npm test -- --test-name-pattern bonding`
72
+ Expected: PASS
73
+
74
+ **Step 5: Commit**
75
+
76
+ ```bash
77
+ git add index.ts index.js dist
78
+ git commit -m "fix: update bonding fee recipient accounts"
79
+ ```
80
+
81
+ ### Task 3: Update AMM instruction account assembly
82
+
83
+ **Files:**
84
+ - Modify: `index.ts`
85
+ - Modify: `index.js`
86
+ - Modify: `dist/index.js`
87
+ - Modify: `dist/index.d.ts`
88
+
89
+ **Step 1: Write the failing test**
90
+
91
+ Use the AMM tests from Task 1 as the failing coverage.
92
+
93
+ **Step 2: Run test to verify it fails**
94
+
95
+ Run: `npm test -- --test-name-pattern amm`
96
+ Expected: FAIL because the fee recipient pair is still placed before `pool-v2`.
97
+
98
+ **Step 3: Write minimal implementation**
99
+
100
+ Make AMM key assembly place `pool-v2` before the new trailing fee recipient pair for both buy and sell, preserving cashback-only extras.
101
+
102
+ **Step 4: Run test to verify it passes**
103
+
104
+ Run: `npm test -- --test-name-pattern amm`
105
+ Expected: PASS
106
+
107
+ **Step 5: Commit**
108
+
109
+ ```bash
110
+ git add index.ts index.js dist
111
+ git commit -m "fix: update amm fee recipient accounts"
112
+ ```
113
+
114
+ ### Task 4: Build and verify distributable output
115
+
116
+ **Files:**
117
+ - Modify: `dist/index.js`
118
+ - Modify: `dist/index.d.ts`
119
+
120
+ **Step 1: Write the failing test**
121
+
122
+ Use the build command as the verification target for generated output drift.
123
+
124
+ **Step 2: Run test to verify it fails**
125
+
126
+ Run: `npm run build`
127
+ Expected: PASS after source changes, with generated `dist` updated.
128
+
129
+ **Step 3: Write minimal implementation**
130
+
131
+ No extra implementation beyond generating `dist`.
132
+
133
+ **Step 4: Run test to verify it passes**
134
+
135
+ Run: `npm test && npm run build`
136
+ Expected: PASS
137
+
138
+ **Step 5: Commit**
139
+
140
+ ```bash
141
+ git add dist
142
+ git commit -m "build: refresh distribution output"
143
+ ```