four-flap-meme-sdk 4.0.14 → 4.1.1

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.
Files changed (90) hide show
  1. package/dist/bundle/four-meme/core/sell-flow.js +6 -9
  2. package/dist/bundle/four-meme/pancake-proxy/helpers.d.ts +5 -38
  3. package/dist/bundle/four-meme/pancake-proxy/helpers.js +5 -228
  4. package/dist/bundle/four-meme/private/sell.js +5 -5
  5. package/dist/bundle/four-meme/swap-hop-helpers.d.ts +1 -5
  6. package/dist/bundle/four-meme/swap-hop-helpers.js +1 -63
  7. package/dist/bundle/four-meme/types/bundle-ops.d.ts +166 -0
  8. package/dist/bundle/four-meme/types/bundle-ops.js +4 -0
  9. package/dist/bundle/four-meme/types/buy-first.d.ts +1 -1
  10. package/dist/bundle/four-meme/types/config.d.ts +95 -0
  11. package/dist/bundle/four-meme/types/config.js +1 -0
  12. package/dist/bundle/four-meme/types/core-flow.d.ts +2 -1
  13. package/dist/bundle/four-meme/types/index.d.ts +5 -611
  14. package/dist/bundle/four-meme/types/pancake-proxy-types.d.ts +118 -0
  15. package/dist/bundle/four-meme/types/pancake-proxy-types.js +3 -0
  16. package/dist/bundle/four-meme/types/swap-types.d.ts +103 -0
  17. package/dist/bundle/four-meme/types/swap-types.js +1 -0
  18. package/dist/bundle/four-meme/types/transfer-ops.d.ts +134 -0
  19. package/dist/bundle/four-meme/types/transfer-ops.js +1 -0
  20. package/dist/chains/bsc/pancake/bundle-buy-first-build.d.ts +5 -3
  21. package/dist/chains/bsc/pancake/bundle-buy-first-build.js +25 -23
  22. package/dist/chains/bsc/pancake/bundle-buy-first-multi-wallet.js +6 -0
  23. package/dist/chains/bsc/pancake/bundle-buy-first-types.d.ts +4 -0
  24. package/dist/chains/bsc/pancake/bundle-buy-first.js +6 -0
  25. package/dist/chains/bsc/pancake/bundle-swap-types.d.ts +4 -0
  26. package/dist/chains/bsc/pancake/hop-chain.d.ts +1 -18
  27. package/dist/chains/bsc/pancake/hop-chain.js +1 -229
  28. package/dist/chains/bsc/pancake/quote.d.ts +18 -1
  29. package/dist/chains/bsc/pancake/quote.js +39 -1
  30. package/dist/chains/bsc/pancake/quote.test.d.ts +1 -0
  31. package/dist/chains/bsc/pancake/quote.test.js +28 -0
  32. package/dist/chains/bsc/pancake/swap-batch.js +16 -7
  33. package/dist/chains/bsc/pancake/swap-build.d.ts +1 -1
  34. package/dist/chains/bsc/pancake/swap-build.js +9 -18
  35. package/dist/chains/bsc/pancake/swap-quick.js +16 -7
  36. package/dist/chains/bsc/pancake/swap-single.js +10 -1
  37. package/dist/chains/eni/platforms/daoaas/portal-direct-submit.js +2 -6
  38. package/dist/chains/xlayer/eip7702/types-base.d.ts +44 -0
  39. package/dist/chains/xlayer/eip7702/types-base.js +4 -0
  40. package/dist/chains/xlayer/eip7702/types-bundle.d.ts +191 -0
  41. package/dist/chains/xlayer/eip7702/types-bundle.js +1 -0
  42. package/dist/chains/xlayer/eip7702/types-create.d.ts +222 -0
  43. package/dist/chains/xlayer/eip7702/types-create.js +1 -0
  44. package/dist/chains/xlayer/eip7702/types-transfer.d.ts +124 -0
  45. package/dist/chains/xlayer/eip7702/types-transfer.js +1 -0
  46. package/dist/chains/xlayer/eip7702/types.d.ts +4 -578
  47. package/dist/chains/xlayer/eip7702/types.js +0 -3
  48. package/dist/chains/xlayer/eoa/eoa-dex-types.d.ts +196 -0
  49. package/dist/chains/xlayer/eoa/eoa-dex-types.js +1 -0
  50. package/dist/chains/xlayer/eoa/eoa-swap-types.d.ts +283 -0
  51. package/dist/chains/xlayer/eoa/eoa-swap-types.js +1 -0
  52. package/dist/chains/xlayer/eoa/eoa-trade-types.d.ts +300 -0
  53. package/dist/chains/xlayer/eoa/eoa-trade-types.js +6 -0
  54. package/dist/chains/xlayer/eoa/eoa-types.d.ts +4 -774
  55. package/dist/chains/xlayer/eoa/eoa-types.js +0 -5
  56. package/dist/chains/xlayer/eoa/eoa-wash-volume.js +2 -13
  57. package/dist/chains/xlayer/eoa/hop-chain.d.ts +1 -1
  58. package/dist/chains/xlayer/eoa/hop-chain.js +4 -83
  59. package/dist/core/constants/index.d.ts +1 -0
  60. package/dist/core/constants/index.js +1 -0
  61. package/dist/core/constants/slippage.d.ts +6 -0
  62. package/dist/core/constants/slippage.js +15 -0
  63. package/dist/domains/flap/portal-bundle-merkle/core-helpers.d.ts +1 -1
  64. package/dist/domains/flap/portal-bundle-merkle/core-helpers.js +6 -4
  65. package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.d.ts +2 -43
  66. package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.js +8 -208
  67. package/dist/domains/flap/portal-bundle-merkle/private/helpers.js +2 -2
  68. package/dist/domains/flap/portal-bundle-merkle/private/sell.js +17 -20
  69. package/dist/domains/flap/portal-bundle-merkle/swap-helpers.d.ts +4 -24
  70. package/dist/domains/flap/portal-bundle-merkle/swap-helpers.js +12 -166
  71. package/dist/domains/flap/portal-bundle-merkle/types-bundle.d.ts +137 -0
  72. package/dist/domains/flap/portal-bundle-merkle/types-bundle.js +7 -0
  73. package/dist/domains/flap/portal-bundle-merkle/types-config.d.ts +118 -0
  74. package/dist/domains/flap/portal-bundle-merkle/types-config.js +4 -0
  75. package/dist/domains/flap/portal-bundle-merkle/types-pancake.d.ts +118 -0
  76. package/dist/domains/flap/portal-bundle-merkle/types-pancake.js +4 -0
  77. package/dist/domains/flap/portal-bundle-merkle/types-transfer.d.ts +70 -0
  78. package/dist/domains/flap/portal-bundle-merkle/types-transfer.js +1 -0
  79. package/dist/domains/flap/portal-bundle-merkle/types.d.ts +4 -441
  80. package/dist/domains/holders/internal/disperse.js +2 -18
  81. package/dist/domains/lp-inspect/inspect-helpers.d.ts +1 -0
  82. package/dist/domains/lp-inspect/inspect-helpers.js +3 -16
  83. package/dist/utils/hop-chains.d.ts +0 -3
  84. package/dist/utils/hop-chains.js +4 -5
  85. package/dist/utils/pancake-router-tx.d.ts +41 -0
  86. package/dist/utils/pancake-router-tx.js +174 -0
  87. package/dist/utils/swap-helpers.d.ts +6 -2
  88. package/dist/utils/swap-helpers.js +24 -4
  89. package/dist/utils/wallet.js +12 -12
  90. package/package.json +1 -1
@@ -4,7 +4,7 @@
4
4
  import { ethers, Contract, Interface } from 'ethers';
5
5
  import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
6
  import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
7
- import { ADDRESSES } from '../../../core/constants/index.js';
7
+ import { ADDRESSES, CHAINS, applySlippageBps, reverseSlippageBps } from '../../../core/constants/index.js';
8
8
  import { MULTICALL3_ABI, ERC20_ABI } from '../../../abis/common.js';
9
9
  import { getBundleErrorMessage } from '../../errors.js';
10
10
  import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, } from '../../config-helpers.js';
@@ -123,7 +123,7 @@ async function resolveSellOutputs(params) {
123
123
  // 如果已提供 minOutputAmounts,直接使用,跳过报价查询
124
124
  if (minOutputAmounts && minOutputAmounts.length === sellers.length) {
125
125
  const minOuts = minOutputAmounts.map((m) => (typeof m === 'string' ? ethers.parseEther(m) : m));
126
- const quotedOutputs = minOuts.map((value) => (value * 100n) / 95n);
126
+ const quotedOutputs = minOuts.map((value) => reverseSlippageBps(value));
127
127
  return { minOuts, quotedOutputs };
128
128
  }
129
129
  // 如果只有 1 个,直接调用(避免 multicall 开销)
@@ -131,8 +131,7 @@ async function resolveSellOutputs(params) {
131
131
  try {
132
132
  const result = await trySell('BSC', rpcUrl, tokenAddress, amountsWei[0]);
133
133
  const quotedOutputs = [result.funds];
134
- // ✅ 已移除滑点保护:minOuts 固定为 0
135
- const minOuts = [0n];
134
+ const minOuts = [applySlippageBps(result.funds)];
136
135
  return { minOuts, quotedOutputs };
137
136
  }
138
137
  catch {
@@ -140,7 +139,7 @@ async function resolveSellOutputs(params) {
140
139
  }
141
140
  }
142
141
  // ✅ 使用 Multicall3 批量获取报价
143
- const provider = createSignProvider(rpcUrl, 56, 'BSC');
142
+ const provider = createSignProvider(rpcUrl, CHAINS.BSC.chainId, 'BSC');
144
143
  const helper3Address = ADDRESSES.BSC.TokenManagerHelper3;
145
144
  const helper3Iface = new Interface(Helper3Abi);
146
145
  const multicall = new Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
@@ -165,8 +164,7 @@ async function resolveSellOutputs(params) {
165
164
  }
166
165
  return 0n;
167
166
  });
168
- // ✅ 已移除滑点保护:minOuts 固定为 0
169
- const minOuts = quotedOutputs.map(() => 0n);
167
+ const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
170
168
  return { minOuts, quotedOutputs };
171
169
  }
172
170
  catch {
@@ -180,8 +178,7 @@ async function resolveSellOutputs(params) {
180
178
  return 0n;
181
179
  }
182
180
  }));
183
- // ✅ 已移除滑点保护:minOuts 固定为 0
184
- const minOuts = quotedOutputs.map(() => 0n);
181
+ const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
185
182
  return { minOuts, quotedOutputs };
186
183
  }
187
184
  }
@@ -1,45 +1,12 @@
1
1
  /**
2
- * PancakeSwap 官方 Router 交易模块 — 共享辅助(报价 / 路由构建 / 授权目标)
2
+ * PancakeSwap 官方 Router 交易模块 — four-meme 辅助
3
+ *
4
+ * 交易构建 / 报价 / 授权目标与 flap 共用 utils/pancake-router-tx。
5
+ * decimals 不走缓存,与原先 four-meme 调用约定一致。
3
6
  */
4
- import { Wallet, Contract } from 'ethers';
5
7
  import type { JsonRpcProvider } from 'ethers';
6
- import type { ContractTransaction } from 'ethers/contract';
7
8
  import type { FourPancakeProxyBatchBuySignParams } from '../types/index.js';
8
- /**
9
- * 查询代币 decimals
10
- */
9
+ export { buildV2Transactions, buildV3SingleTransactions, buildV3MultiHopTransactions, batchGetV2Quotes, getApprovalTarget, } from '../../../utils/pancake-router-tx.js';
11
10
  export declare function getTokenDecimals(tokenAddress: string, provider: JsonRpcProvider): Promise<number>;
12
- /**
13
- * 判断是否需要发送 BNB
14
- */
15
11
  export type PancakeBuyRouteFields = Pick<FourPancakeProxyBatchBuySignParams, 'v2Path' | 'v3TokenIn' | 'v3ExactTokenIn'>;
16
12
  export declare function needSendBNB(routeType: FourPancakeProxyBatchBuySignParams['routeType'], params: PancakeBuyRouteFields): boolean;
17
- /**
18
- * ✅ 构建 V2 交易(使用官方 Router)
19
- */
20
- export declare function buildV2Transactions(routers: Contract[], wallets: Wallet[], amountsWei: bigint[], minOuts: bigint[], path: string[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
21
- /**
22
- * ✅ 构建 V3 单跳交易(使用官方 SwapRouter02 + multicall)
23
- */
24
- export declare function buildV3SingleTransactions(routers: Contract[], wallets: Wallet[], tokenIn: string, tokenOut: string, fee: number, amountsWei: bigint[], minOuts: bigint[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
25
- /**
26
- * ✅ 构建 V3 多跳交易(使用官方 SwapRouter02 的 exactInput)
27
- *
28
- * @param routers - V3 Router 合约数组
29
- * @param wallets - 钱包数组
30
- * @param tokens - 代币路径 [tokenIn, tokenMid1, ..., tokenOut]
31
- * @param fees - 费率路径 [fee0, fee1, ...]
32
- * @param amountsWei - 每个钱包的输入金额
33
- * @param minOuts - 最小输出金额
34
- * @param isBuy - 是否为买入操作
35
- * @param needBNB - 是否需要发送 BNB
36
- */
37
- export declare function buildV3MultiHopTransactions(routers: Contract[], wallets: Wallet[], tokens: string[], fees: number[], amountsWei: bigint[], minOuts: bigint[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
38
- /**
39
- * ✅ 使用 Multicall3 批量获取 V2 报价
40
- */
41
- export declare function batchGetV2Quotes(provider: JsonRpcProvider, amountsWei: bigint[], v2Path: string[]): Promise<bigint[]>;
42
- /**
43
- * 根据 routeType 获取授权目标地址
44
- */
45
- export declare function getApprovalTarget(routeType: string): string;
@@ -1,232 +1,9 @@
1
- /**
2
- * PancakeSwap 官方 Router 交易模块 — 共享辅助(报价 / 路由构建 / 授权目标)
3
- */
4
- import { Contract, Interface } from 'ethers';
5
- import { getDeadline, encodeV3Path } from '../../../utils/bundle-helpers.js';
6
- import { V2_ROUTER_ABI, ERC20_ABI, MULTICALL3_ABI } from '../../../abis/common.js';
7
- import { MULTICALL3_ADDRESS, WBNB_ADDRESS, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ADDRESS, V3_ROUTER_ABI, } from './constants.js';
8
- /**
9
- * 查询代币 decimals
10
- */
1
+ import { getTokenDecimals as fetchTokenDecimals } from '../../../utils/swap-helpers.js';
2
+ import { needSendBNBFromRoute } from '../../../utils/pancake-router-tx.js';
3
+ export { buildV2Transactions, buildV3SingleTransactions, buildV3MultiHopTransactions, batchGetV2Quotes, getApprovalTarget, } from '../../../utils/pancake-router-tx.js';
11
4
  export async function getTokenDecimals(tokenAddress, provider) {
12
- try {
13
- const token = new Contract(tokenAddress, ERC20_ABI, provider);
14
- const decimals = await token.decimals();
15
- return Number(decimals);
16
- }
17
- catch {
18
- return 18;
19
- }
5
+ return fetchTokenDecimals(provider, tokenAddress, { fallback: 18 });
20
6
  }
21
7
  export function needSendBNB(routeType, params) {
22
- if (routeType === 'v2' && params.v2Path && params.v2Path[0].toLowerCase() === WBNB_ADDRESS.toLowerCase()) {
23
- return true;
24
- }
25
- if (routeType === 'v3-single' && params.v3TokenIn && params.v3TokenIn.toLowerCase() === WBNB_ADDRESS.toLowerCase()) {
26
- return true;
27
- }
28
- if (routeType === 'v3-multi' &&
29
- params.v3ExactTokenIn &&
30
- params.v3ExactTokenIn.toLowerCase() === WBNB_ADDRESS.toLowerCase()) {
31
- return true;
32
- }
33
- return false;
34
- }
35
- /**
36
- * ✅ 构建 V2 交易(使用官方 Router)
37
- */
38
- export async function buildV2Transactions(routers, wallets, amountsWei, minOuts, path, isBuy, needBNB) {
39
- const deadline = getDeadline();
40
- return Promise.all(routers.map(async (router, i) => {
41
- if (isBuy && needBNB) {
42
- // ✅ 买入:BNB → Token,使用 swapExactETHForTokensSupportingFeeOnTransferTokens
43
- return router.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(minOuts[i], // amountOutMin
44
- path, // path
45
- wallets[i].address, // to
46
- deadline, // deadline
47
- { value: amountsWei[i] });
48
- }
49
- else {
50
- // ✅ 卖出:Token → BNB,使用 swapExactTokensForETHSupportingFeeOnTransferTokens
51
- return router.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(amountsWei[i], // amountIn
52
- minOuts[i], // amountOutMin
53
- path, // path
54
- wallets[i].address, // to
55
- deadline);
56
- }
57
- }));
58
- }
59
- /**
60
- * ✅ 构建 V3 单跳交易(使用官方 SwapRouter02 + multicall)
61
- */
62
- export async function buildV3SingleTransactions(routers, wallets, tokenIn, tokenOut, fee, amountsWei, minOuts, isBuy, needBNB) {
63
- const deadline = getDeadline();
64
- const v3RouterIface = new Interface(V3_ROUTER_ABI);
65
- return Promise.all(routers.map(async (router, i) => {
66
- const isTokenOutWBNB = tokenOut.toLowerCase() === WBNB_ADDRESS.toLowerCase();
67
- // ✅ 构建 exactInputSingle calldata
68
- const exactInputSingleData = v3RouterIface.encodeFunctionData('exactInputSingle', [
69
- {
70
- tokenIn: tokenIn,
71
- tokenOut: tokenOut,
72
- fee: fee,
73
- recipient: isTokenOutWBNB ? PANCAKE_V3_ROUTER_ADDRESS : wallets[i].address, // 如果输出是 WBNB,先发给 Router
74
- amountIn: amountsWei[i],
75
- amountOutMinimum: minOuts[i],
76
- sqrtPriceLimitX96: 0n,
77
- },
78
- ]);
79
- if (isBuy && needBNB) {
80
- // ✅ 买入:BNB → Token,只需要 exactInputSingle
81
- // 通过 multicall 包装,传入 deadline 和 ETH value
82
- return router.multicall.populateTransaction(deadline, [exactInputSingleData], { value: amountsWei[i] });
83
- }
84
- else if (!isBuy && isTokenOutWBNB) {
85
- // ✅ 卖出:Token → WBNB → BNB,需要 exactInputSingle + unwrapWETH9
86
- const unwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [
87
- minOuts[i], // amountMinimum
88
- wallets[i].address, // recipient
89
- ]);
90
- return router.multicall.populateTransaction(deadline, [exactInputSingleData, unwrapData]);
91
- }
92
- else {
93
- // ✅ Token → Token,只需要 exactInputSingle
94
- return router.multicall.populateTransaction(deadline, [exactInputSingleData]);
95
- }
96
- }));
97
- }
98
- /**
99
- * ✅ 构建 V3 多跳交易(使用官方 SwapRouter02 的 exactInput)
100
- *
101
- * @param routers - V3 Router 合约数组
102
- * @param wallets - 钱包数组
103
- * @param tokens - 代币路径 [tokenIn, tokenMid1, ..., tokenOut]
104
- * @param fees - 费率路径 [fee0, fee1, ...]
105
- * @param amountsWei - 每个钱包的输入金额
106
- * @param minOuts - 最小输出金额
107
- * @param isBuy - 是否为买入操作
108
- * @param needBNB - 是否需要发送 BNB
109
- */
110
- export async function buildV3MultiHopTransactions(routers, wallets, tokens, fees, amountsWei, minOuts, isBuy, needBNB) {
111
- if (!tokens || tokens.length < 2) {
112
- throw new Error('V3 多跳需要至少 2 个代币(v3Tokens)');
113
- }
114
- if (!fees || fees.length !== tokens.length - 1) {
115
- throw new Error(`V3 多跳费率数量 (${fees?.length || 0}) 必须等于代币数量 - 1 (${tokens.length - 1})(v3Fees)`);
116
- }
117
- const deadline = getDeadline();
118
- const v3RouterIface = new Interface(V3_ROUTER_ABI);
119
- // 编码正向 path(用于买入:BNB → Token)
120
- const forwardPath = encodeV3Path(tokens, fees);
121
- // 编码反向 path(用于卖出:Token → BNB)
122
- const reversedTokens = [...tokens].reverse();
123
- const reversedFees = [...fees].reverse();
124
- const reversePath = encodeV3Path(reversedTokens, reversedFees);
125
- const tokenOut = tokens[tokens.length - 1];
126
- const isTokenOutWBNB = tokenOut.toLowerCase() === WBNB_ADDRESS.toLowerCase();
127
- return Promise.all(routers.map(async (router, i) => {
128
- if (isBuy && needBNB) {
129
- // ✅ 买入:BNB → ... → Token
130
- const swapData = v3RouterIface.encodeFunctionData('exactInput', [
131
- {
132
- path: forwardPath,
133
- recipient: wallets[i].address,
134
- amountIn: amountsWei[i],
135
- amountOutMinimum: minOuts[i],
136
- },
137
- ]);
138
- return router.multicall.populateTransaction(deadline, [swapData], { value: amountsWei[i] });
139
- }
140
- else if (!isBuy) {
141
- // ✅ 卖出:Token → ... → BNB
142
- const swapData = v3RouterIface.encodeFunctionData('exactInput', [
143
- {
144
- path: reversePath,
145
- recipient: isTokenOutWBNB ? PANCAKE_V3_ROUTER_ADDRESS : wallets[i].address,
146
- amountIn: amountsWei[i],
147
- amountOutMinimum: minOuts[i],
148
- },
149
- ]);
150
- if (isTokenOutWBNB) {
151
- // 需要 unwrapWETH9
152
- const unwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [minOuts[i], wallets[i].address]);
153
- return router.multicall.populateTransaction(deadline, [swapData, unwrapData]);
154
- }
155
- return router.multicall.populateTransaction(deadline, [swapData]);
156
- }
157
- else {
158
- // Token → Token(不需要 BNB)
159
- const swapData = v3RouterIface.encodeFunctionData('exactInput', [
160
- {
161
- path: forwardPath,
162
- recipient: wallets[i].address,
163
- amountIn: amountsWei[i],
164
- amountOutMinimum: minOuts[i],
165
- },
166
- ]);
167
- return router.multicall.populateTransaction(deadline, [swapData]);
168
- }
169
- }));
170
- }
171
- /**
172
- * ✅ 使用 Multicall3 批量获取 V2 报价
173
- */
174
- export async function batchGetV2Quotes(provider, amountsWei, v2Path) {
175
- if (amountsWei.length === 0)
176
- return [];
177
- if (amountsWei.length === 1) {
178
- try {
179
- const v2Router = new Contract(PANCAKE_V2_ROUTER_ADDRESS, V2_ROUTER_ABI, provider);
180
- const amounts = await v2Router.getAmountsOut(amountsWei[0], v2Path);
181
- return [amounts[amounts.length - 1]];
182
- }
183
- catch {
184
- return [0n];
185
- }
186
- }
187
- try {
188
- const v2RouterIface = new Interface(V2_ROUTER_ABI);
189
- const multicall = new Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
190
- const calls = amountsWei.map((amount) => ({
191
- target: PANCAKE_V2_ROUTER_ADDRESS,
192
- allowFailure: true,
193
- callData: v2RouterIface.encodeFunctionData('getAmountsOut', [amount, v2Path]),
194
- }));
195
- const results = await multicall.aggregate3.staticCall(calls);
196
- return results.map((r) => {
197
- if (r.success && r.returnData && r.returnData !== '0x') {
198
- try {
199
- const decoded = v2RouterIface.decodeFunctionResult('getAmountsOut', r.returnData);
200
- const amounts = decoded[0];
201
- return amounts[amounts.length - 1];
202
- }
203
- catch {
204
- return 0n;
205
- }
206
- }
207
- return 0n;
208
- });
209
- }
210
- catch {
211
- return await Promise.all(amountsWei.map(async (amount) => {
212
- try {
213
- const v2Router = new Contract(PANCAKE_V2_ROUTER_ADDRESS, V2_ROUTER_ABI, provider);
214
- const amounts = await v2Router.getAmountsOut(amount, v2Path);
215
- return amounts[amounts.length - 1];
216
- }
217
- catch {
218
- return 0n;
219
- }
220
- }));
221
- }
222
- }
223
- /**
224
- * 根据 routeType 获取授权目标地址
225
- */
226
- export function getApprovalTarget(routeType) {
227
- if (routeType === 'v2') {
228
- return PANCAKE_V2_ROUTER_ADDRESS;
229
- }
230
- // V3 路由授权给 V3 Router
231
- return PANCAKE_V3_ROUTER_ADDRESS;
8
+ return needSendBNBFromRoute(routeType, params);
232
9
  }
@@ -4,7 +4,7 @@
4
4
  import { ethers, Wallet } from 'ethers';
5
5
  import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
6
  import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
7
- import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA, CHAINS } from '../../../core/constants/index.js';
7
+ import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA, CHAINS, applySlippageBps, reverseSlippageBps } from '../../../core/constants/index.js';
8
8
  import { TM2_ABI } from '../../../abis/common.js';
9
9
  import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, } from '../../config-helpers.js';
10
10
  import { trySell } from '../../../domains/four/contracts/tm.js';
@@ -31,7 +31,7 @@ export async function fourPrivateSellMerkle(params) {
31
31
  const [gasPrice, sellNonce, sellUnsigned] = await Promise.all([
32
32
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
33
33
  wallet.getNonce(),
34
- tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, 0n), // ✅ 已移除滑点保护:minOut 固定为 0
34
+ tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, minOut),
35
35
  ]);
36
36
  // ✅ 已移除授权检查(前端负责确保授权)
37
37
  // ✅ 利润计算(同步)
@@ -121,7 +121,7 @@ export async function fourBatchPrivateSellMerkle(params) {
121
121
  minFundsEach !== undefined
122
122
  ? Promise.resolve((() => {
123
123
  const minOutWei = typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach;
124
- return new Array(wallets.length).fill((minOutWei * 100n) / 95n);
124
+ return new Array(wallets.length).fill(reverseSlippageBps(minOutWei));
125
125
  })())
126
126
  : Promise.all(amountsWei.map(async (amount) => {
127
127
  try {
@@ -133,8 +133,8 @@ export async function fourBatchPrivateSellMerkle(params) {
133
133
  }
134
134
  })),
135
135
  ]);
136
- // ✅ 已移除滑点保护:minOuts 固定为 0
137
- const minOuts = new Array(wallets.length).fill(0n);
136
+ // 报价 × (1 - 100bps)
137
+ const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
138
138
  // ✅ 计算总利润和找出收益最高的钱包(同步计算)
139
139
  const extractProfit = shouldExtractProfit();
140
140
  let totalProfit = 0n;
@@ -1,6 +1,2 @@
1
- import { Wallet, type JsonRpcProvider } from 'ethers';
2
- import type { DisperseHopPath } from './types/index.js';
3
- export declare const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
1
+ export { generateDisperseHopPaths, buildNativeHopChain, NATIVE_TRANSFER_GAS_LIMIT, } from '../../utils/hop-chains.js';
4
2
  export type { DisperseHopPath } from './types/index.js';
5
- export declare function generateDisperseHopPaths(targetAddresses: string[], hopCount: number, provider: JsonRpcProvider): DisperseHopPath[];
6
- export declare function buildNativeHopChain(payer: Wallet, path: DisperseHopPath, finalAmount: bigint, gasPrice: bigint, chainId: number, txType: 0 | 2, payerNonce: number): Promise<string[]>;
@@ -1,63 +1 @@
1
- import { Wallet } from 'ethers';
2
- import { generateWallets } from '../../utils/wallet.js';
3
- export const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
4
- export function generateDisperseHopPaths(targetAddresses, hopCount, provider) {
5
- if (hopCount <= 0) {
6
- return targetAddresses.map((addr) => ({
7
- targetAddress: addr,
8
- hopWallets: [],
9
- hopWalletsInfo: [],
10
- }));
11
- }
12
- return targetAddresses.map((targetAddress) => {
13
- const hopWalletsInfo = generateWallets(hopCount);
14
- const hopWallets = hopWalletsInfo.map((w) => new Wallet(w.privateKey, provider));
15
- return { targetAddress, hopWallets, hopWalletsInfo };
16
- });
17
- }
18
- export async function buildNativeHopChain(payer, path, finalAmount, gasPrice, chainId, txType, payerNonce) {
19
- const signedTxs = [];
20
- const hopCount = path.hopWallets.length;
21
- if (hopCount === 0) {
22
- signedTxs.push(await payer.signTransaction({
23
- to: path.targetAddress,
24
- value: finalAmount,
25
- nonce: payerNonce,
26
- gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
27
- gasPrice,
28
- chainId,
29
- type: txType,
30
- }));
31
- return signedTxs;
32
- }
33
- const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
34
- const amountsPerHop = [];
35
- for (let i = 0; i < hopCount; i++) {
36
- const remainingHops = hopCount - i;
37
- amountsPerHop.push(finalAmount + hopGasCost * BigInt(remainingHops));
38
- }
39
- signedTxs.push(await payer.signTransaction({
40
- to: path.hopWallets[0].address,
41
- value: amountsPerHop[0],
42
- nonce: payerNonce,
43
- gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
44
- gasPrice,
45
- chainId,
46
- type: txType,
47
- }));
48
- for (let i = 0; i < hopCount; i++) {
49
- const fromWallet = path.hopWallets[i];
50
- const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
51
- const amount = i === hopCount - 1 ? finalAmount : amountsPerHop[i + 1];
52
- signedTxs.push(await fromWallet.signTransaction({
53
- to: toAddress,
54
- value: amount,
55
- nonce: 0,
56
- gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
57
- gasPrice,
58
- chainId,
59
- type: txType,
60
- }));
61
- }
62
- return signedTxs;
63
- }
1
+ export { generateDisperseHopPaths, buildNativeHopChain, NATIVE_TRANSFER_GAS_LIMIT, } from '../../utils/hop-chains.js';
@@ -0,0 +1,166 @@
1
+ import type { FourTokenTaxInfo } from '../../../core/clients/four.js';
2
+ import type { FourRaisedToken } from '../../../domains/four/raised-token.js';
3
+ import type { FourBundleMerkleConfig, FourSignConfig, MerkleSignedResult } from './config.js';
4
+ /** ✅ 创建代币 + 购买参数(Merkle 版本 - 完整) */
5
+ export type FourCreateWithBundleBuyMerkleParams = {
6
+ privateKeys: string[];
7
+ buyAmounts: string[];
8
+ b0Amount?: string;
9
+ tokenInfo: {
10
+ name: string;
11
+ symbol: string;
12
+ description: string;
13
+ imageUrl?: string;
14
+ imageFile?: Blob;
15
+ label?: 'Meme' | 'AI' | 'Defi' | 'Games' | 'Infra' | 'De-Sci' | 'Social' | 'Depin' | 'Charity' | 'Others';
16
+ preSale?: string;
17
+ webUrl?: string;
18
+ twitterUrl?: string;
19
+ telegramUrl?: string;
20
+ /** ✅ AntiSniperFeeMode(开盘高税模式) */
21
+ feePlan?: boolean;
22
+ /** ✅ 税币配置(Tax Token, creatorType=5) */
23
+ tokenTaxInfo?: FourTokenTaxInfo;
24
+ /** 官网计价币 symbol,如 BNB / USDT / USD1 */
25
+ quoteSymbol?: string;
26
+ raisedToken?: FourRaisedToken;
27
+ };
28
+ config: FourBundleMerkleConfig;
29
+ };
30
+ /** ✅ 创建代币 + 购买参数(仅签名版本 - 精简) */
31
+ export type FourCreateWithBundleBuySignParams = {
32
+ privateKeys: string[];
33
+ buyAmounts: string[];
34
+ b0Amount?: string;
35
+ tokenInfo: {
36
+ name: string;
37
+ symbol: string;
38
+ description: string;
39
+ imageUrl?: string;
40
+ imageFile?: Blob;
41
+ label?: 'Meme' | 'AI' | 'Defi' | 'Games' | 'Infra' | 'De-Sci' | 'Social' | 'Depin' | 'Charity' | 'Others';
42
+ preSale?: string;
43
+ webUrl?: string;
44
+ twitterUrl?: string;
45
+ telegramUrl?: string;
46
+ /** ✅ AntiSniperFeeMode(开盘高税模式) */
47
+ feePlan?: boolean;
48
+ /** ✅ 税币配置(Tax Token, creatorType=5) */
49
+ tokenTaxInfo?: FourTokenTaxInfo;
50
+ quoteSymbol?: string;
51
+ raisedToken?: FourRaisedToken;
52
+ };
53
+ config: FourSignConfig;
54
+ };
55
+ /**
56
+ * ✅ 创建代币 + 购买结果(简化版)
57
+ * 包含 tokenAddress 用于返回创建的代币地址
58
+ */
59
+ export type FourCreateWithBundleBuyMerkleResult = MerkleSignedResult;
60
+ /** ✅ 批量购买参数(Merkle 版本 - 完整) */
61
+ export type FourBatchBuyMerkleParams = {
62
+ privateKeys: string[];
63
+ buyAmounts: string[];
64
+ tokenAddress: string;
65
+ config: FourBundleMerkleConfig;
66
+ };
67
+ /** ✅ 批量购买参数(仅签名版本 - 精简) */
68
+ export type FourBatchBuySignParams = {
69
+ privateKeys: string[];
70
+ buyAmounts: string[];
71
+ tokenAddress: string;
72
+ config: FourSignConfig;
73
+ };
74
+ /** ✅ 批量购买结果(简化版) */
75
+ export type FourBatchBuyMerkleResult = MerkleSignedResult;
76
+ /** ✅ 批量卖出参数(Merkle 版本 - 完整) */
77
+ export type FourBatchSellMerkleParams = {
78
+ privateKeys: string[];
79
+ sellAmounts: string[];
80
+ tokenAddress: string;
81
+ minOutputAmounts?: (string | bigint)[];
82
+ config: FourBundleMerkleConfig;
83
+ };
84
+ /** ✅ 批量卖出参数(仅签名版本 - 精简) */
85
+ export type FourBatchSellSignParams = {
86
+ privateKeys: string[];
87
+ sellAmounts: string[];
88
+ tokenAddress: string;
89
+ minOutputAmounts?: (string | bigint)[];
90
+ config: FourSignConfig;
91
+ };
92
+ /** ✅ 批量卖出结果(简化版) */
93
+ export type FourBatchSellMerkleResult = MerkleSignedResult;
94
+ /** ✅ 私有交易基础配置(Merkle 版本 - 完整) */
95
+ export type FourPrivateMerkleBase = {
96
+ config: FourBundleMerkleConfig;
97
+ };
98
+ /** ✅ 私有交易基础配置(仅签名版本 - 精简) */
99
+ export type FourPrivateSignBase = {
100
+ config: FourSignConfig;
101
+ };
102
+ /** ✅ 私有购买参数(Merkle 版本 - 完整) */
103
+ export type FourPrivateBuyMerkleParams = FourPrivateMerkleBase & {
104
+ privateKey: string;
105
+ tokenAddress: string;
106
+ funds: string;
107
+ to?: string;
108
+ };
109
+ /** ✅ 私有购买参数(仅签名版本 - 精简) */
110
+ export type FourPrivateBuySignParams = FourPrivateSignBase & {
111
+ privateKey: string;
112
+ tokenAddress: string;
113
+ funds: string;
114
+ to?: string;
115
+ /** ERC20 计价跟买;不传则按 BNB `msg.value` */
116
+ quoteTokenAddress?: string;
117
+ quoteDecimals?: number;
118
+ };
119
+ /** ✅ 私有卖出参数(Merkle 版本 - 完整) */
120
+ export type FourPrivateSellMerkleParams = FourPrivateMerkleBase & {
121
+ privateKey: string;
122
+ tokenAddress: string;
123
+ amount: string;
124
+ minFunds?: bigint;
125
+ };
126
+ /** ✅ 私有卖出参数(仅签名版本 - 精简) */
127
+ export type FourPrivateSellSignParams = FourPrivateSignBase & {
128
+ privateKey: string;
129
+ tokenAddress: string;
130
+ amount: string;
131
+ minFunds?: bigint;
132
+ };
133
+ /** ✅ 私有交易结果(简化版) */
134
+ export type FourPrivateTransactionResult = MerkleSignedResult;
135
+ /** ✅ 批量私有购买参数(Merkle 版本 - 完整) */
136
+ export type FourBatchPrivateBuyMerkleParams = FourPrivateMerkleBase & {
137
+ privateKeys: string[];
138
+ fundsList: string[];
139
+ tokenAddress: string;
140
+ quoteTokenAddress?: string;
141
+ quoteDecimals?: number;
142
+ };
143
+ /** ✅ 批量私有购买参数(仅签名版本 - 精简) */
144
+ export type FourBatchPrivateBuySignParams = FourPrivateSignBase & {
145
+ privateKeys: string[];
146
+ fundsList: string[];
147
+ tokenAddress: string;
148
+ quoteTokenAddress?: string;
149
+ quoteDecimals?: number;
150
+ };
151
+ /** ✅ 批量私有卖出参数(Merkle 版本 - 完整) */
152
+ export type FourBatchPrivateSellMerkleParams = FourPrivateMerkleBase & {
153
+ privateKeys: string[];
154
+ amounts: string[];
155
+ tokenAddress: string;
156
+ minFundsEach?: bigint;
157
+ };
158
+ /** ✅ 批量私有卖出参数(仅签名版本 - 精简) */
159
+ export type FourBatchPrivateSellSignParams = FourPrivateSignBase & {
160
+ privateKeys: string[];
161
+ amounts: string[];
162
+ tokenAddress: string;
163
+ minFundsEach?: bigint;
164
+ };
165
+ /** ✅ 批量私有交易结果(简化版) */
166
+ export type FourBatchPrivateMerkleResult = MerkleSignedResult;
@@ -0,0 +1,4 @@
1
+ export {};
2
+ // ========================================
3
+ // 工具方法参数
4
+ // ========================================
@@ -1,6 +1,6 @@
1
1
  import type { CommonBundleConfig } from '../../../utils/bundle-helpers.js';
2
2
  import type { GeneratedWallet } from '../../../utils/wallet.js';
3
- import type { FourSignConfig, UserType } from './index.js';
3
+ import type { FourSignConfig, UserType } from './config.js';
4
4
  export type FourBuyFirstSignConfig = FourSignConfig & {
5
5
  reserveGasBNB?: number;
6
6
  userType?: UserType;