four-flap-meme-sdk 1.4.25 → 1.4.26

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 (46) hide show
  1. package/dist/abis/common.d.ts +85 -0
  2. package/dist/abis/common.js +242 -0
  3. package/dist/abis/index.d.ts +1 -0
  4. package/dist/abis/index.js +2 -0
  5. package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.js +1 -6
  6. package/dist/contracts/tm-bundle-merkle/core.js +9 -16
  7. package/dist/contracts/tm-bundle-merkle/internal.js +6 -8
  8. package/dist/contracts/tm-bundle-merkle/pancake-proxy.d.ts +12 -6
  9. package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +224 -166
  10. package/dist/contracts/tm-bundle-merkle/private.js +6 -19
  11. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +2 -7
  12. package/dist/contracts/tm-bundle-merkle/swap-internal.d.ts +1 -1
  13. package/dist/contracts/tm-bundle-merkle/swap-internal.js +9 -2
  14. package/dist/contracts/tm-bundle-merkle/swap.js +1 -3
  15. package/dist/contracts/tm-bundle-merkle/types.d.ts +20 -0
  16. package/dist/contracts/tm-bundle-merkle/utils.js +2 -3
  17. package/dist/dex/direct-router.d.ts +2 -1
  18. package/dist/dex/direct-router.js +25 -140
  19. package/dist/flap/constants.d.ts +2 -1
  20. package/dist/flap/constants.js +2 -1
  21. package/dist/flap/meta.js +6 -4
  22. package/dist/flap/portal-bundle-merkle/config.js +6 -12
  23. package/dist/flap/portal-bundle-merkle/core.js +8 -11
  24. package/dist/flap/portal-bundle-merkle/pancake-proxy.d.ts +12 -10
  25. package/dist/flap/portal-bundle-merkle/pancake-proxy.js +307 -370
  26. package/dist/flap/portal-bundle-merkle/private.js +1 -1
  27. package/dist/flap/portal-bundle-merkle/swap-buy-first.js +12 -30
  28. package/dist/flap/portal-bundle-merkle/swap.js +13 -26
  29. package/dist/flap/portal-bundle-merkle/types.d.ts +22 -2
  30. package/dist/flap/portal-bundle-merkle/utils.js +11 -16
  31. package/dist/index.d.ts +3 -2
  32. package/dist/index.js +9 -2
  33. package/dist/pancake/bundle-buy-first.js +56 -38
  34. package/dist/pancake/bundle-swap.js +114 -61
  35. package/dist/utils/bundle-helpers.d.ts +28 -0
  36. package/dist/utils/bundle-helpers.js +64 -0
  37. package/dist/utils/constants.d.ts +23 -1
  38. package/dist/utils/constants.js +37 -7
  39. package/dist/utils/erc20.js +17 -25
  40. package/dist/utils/lp-inspect.js +9 -20
  41. package/dist/utils/private-sale.js +1 -2
  42. package/dist/utils/quote-helpers.js +3 -29
  43. package/dist/utils/swap-helpers.js +1 -6
  44. package/dist/utils/wallet.d.ts +8 -13
  45. package/dist/utils/wallet.js +154 -342
  46. package/package.json +1 -1
@@ -2,8 +2,8 @@ import { ethers, Wallet } from 'ethers';
2
2
  import { MerkleClient } from '../../clients/merkle.js';
3
3
  import { getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
4
4
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
5
+ import { ZERO_ADDRESS } from '../../utils/constants.js';
5
6
  import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
6
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
7
7
  const DEFAULT_GAS_LIMIT = 800000;
8
8
  /**
9
9
  * 私有购买(单笔)(Merkle 版本)
@@ -6,36 +6,17 @@
6
6
  import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
8
8
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
9
- import { PROFIT_CONFIG } from '../../utils/constants.js';
10
- import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
11
- // Portal ABI
12
- const PORTAL_ABI = [
13
- 'function swapExactInput((address inputToken, address outputToken, uint256 inputAmount, uint256 minOutputAmount, bytes permitData)) payable returns (uint256)',
14
- 'function quoteExactInput((address inputToken, address outputToken, uint256 inputAmount)) view returns (uint256)'
15
- ];
16
- const ERC20_BALANCE_ABI = [
17
- 'function balanceOf(address) view returns (uint256)',
18
- 'function decimals() view returns (uint8)'
19
- ];
20
- const ERC20_ALLOWANCE_ABI = [
21
- 'function allowance(address owner,address spender) view returns (uint256)',
22
- 'function approve(address spender,uint256 amount) returns (bool)',
23
- 'function decimals() view returns (uint8)'
24
- ];
25
- const APPROVE_INTERFACE = new ethers.Interface([
26
- 'function approve(address,uint256) returns (bool)'
27
- ]);
28
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
29
- // ==================== ERC20 → 原生代币报价 ====================
30
- // BSC 链常量
31
- const BSC_PANCAKE_V2_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
32
- const BSC_WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
33
- // ✅ Monad 链常量
9
+ import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
10
+ import { ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI } from '../../abis/common.js';
11
+ import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
12
+ // ABI 别名
13
+ const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
14
+ // ==================== 链常量 ====================
15
+ const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
16
+ const BSC_WBNB = ADDRESSES.BSC.WBNB;
34
17
  const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
35
- const MONAD_WMON = '0x3bd359c1119da7da1d913d1c4d2b7c461115433a';
36
- const ROUTER_ABI = [
37
- 'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)'
38
- ];
18
+ const MONAD_WMON = ADDRESSES.MONAD.WMON;
19
+ const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
39
20
  /**
40
21
  * 获取 ERC20 代币 → 原生代币的报价
41
22
  * @param provider - Provider 实例
@@ -267,7 +248,8 @@ export async function flapBundleBuyFirstMerkle(params) {
267
248
  }
268
249
  };
269
250
  }
270
- const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
251
+ // 使用公共模块中的 ERC20_BALANCE_ABI
252
+ const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
271
253
  async function calculateBuyerFunds({ buyer, buyerFunds, buyerFundsPercentage, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
272
254
  const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
273
255
  // ✅ 根据是否使用原生代币获取不同的余额
@@ -7,41 +7,28 @@ import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { calculateSellAmount } from '../../utils/swap-helpers.js';
8
8
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
9
9
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
10
- import { PROFIT_CONFIG } from '../../utils/constants.js';
11
- import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
10
+ import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
11
+ import { ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
12
+ import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
12
13
  /**
13
- * 获取 Gas Limit(支持 FlapAnyConfig)
14
+ * 获取 Gas Limit
14
15
  */
15
16
  function getGasLimit(config, defaultGas = 500000) {
16
17
  if (config.gasLimit !== undefined) {
17
18
  return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
18
19
  }
19
20
  const multiplier = config.gasLimitMultiplier ?? 1.0;
20
- const calculatedGas = Math.ceil(defaultGas * multiplier);
21
- return BigInt(calculatedGas);
21
+ return BigInt(Math.ceil(defaultGas * multiplier));
22
22
  }
23
- // Portal ABI(使用 swapExactInput 统一接口 + quoteExactInput 报价)
24
- const PORTAL_ABI = [
25
- 'function swapExactInput((address inputToken, address outputToken, uint256 inputAmount, uint256 minOutputAmount, bytes permitData)) payable returns (uint256)',
26
- 'function quoteExactInput((address inputToken, address outputToken, uint256 inputAmount)) view returns (uint256)'
27
- ];
28
- const ERC20_ALLOWANCE_ABI = [
29
- 'function allowance(address,address) view returns (uint256)',
30
- 'function approve(address,uint256) returns (bool)',
31
- 'function decimals() view returns (uint8)'
32
- ];
33
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
23
+ // ABI 别名
24
+ const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
25
+ const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
34
26
  const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
35
- // ==================== ERC20 → 原生代币报价 ====================
36
- // BSC 链常量
37
- const BSC_PANCAKE_V2_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
38
- const BSC_WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
39
- // ✅ Monad 链常量
27
+ // 链常量
28
+ const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
29
+ const BSC_WBNB = ADDRESSES.BSC.WBNB;
40
30
  const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
41
- const MONAD_WMON = '0x3bd359c1119da7da1d913d1c4d2b7c461115433a';
42
- const ROUTER_ABI = [
43
- 'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)'
44
- ];
31
+ const MONAD_WMON = ADDRESSES.MONAD.WMON;
45
32
  /**
46
33
  * 获取 ERC20 代币 → 原生代币的报价
47
34
  * @param provider - Provider 实例
@@ -341,7 +328,7 @@ async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, pro
341
328
  throw new Error(`卖出报价失败: ${err}`);
342
329
  }
343
330
  }
344
- const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
331
+ // ERC20_BALANCE_OF_ABI 已在文件开头定义
345
332
  async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
346
333
  const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
347
334
  // ✅ 根据是否使用原生代币获取不同的余额
@@ -203,6 +203,10 @@ export type PancakeProxyBatchBuyParams = {
203
203
  v3Fee?: number;
204
204
  v3LpAddresses?: string[];
205
205
  v3ExactTokenIn?: string;
206
+ /** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
207
+ v3Tokens?: string[];
208
+ /** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
209
+ v3Fees?: number[];
206
210
  minOutputAmounts?: (string | bigint)[];
207
211
  config: FlapBundleMerkleConfig;
208
212
  };
@@ -218,6 +222,10 @@ export type PancakeProxyBatchBuySignParams = {
218
222
  v3Fee?: number;
219
223
  v3LpAddresses?: string[];
220
224
  v3ExactTokenIn?: string;
225
+ /** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
226
+ v3Tokens?: string[];
227
+ /** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
228
+ v3Fees?: number[];
221
229
  minOutputAmounts?: (string | bigint)[];
222
230
  config: FlapSignConfig;
223
231
  quoteToken?: string;
@@ -240,6 +248,10 @@ export type PancakeProxyBatchSellParams = {
240
248
  v3Fee?: number;
241
249
  v3LpAddresses?: string[];
242
250
  v3ExactTokenIn?: string;
251
+ /** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
252
+ v3Tokens?: string[];
253
+ /** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
254
+ v3Fees?: number[];
243
255
  minOutputAmounts?: (string | bigint)[];
244
256
  config: FlapBundleMerkleConfig;
245
257
  };
@@ -255,13 +267,17 @@ export type PancakeProxyBatchSellSignParams = {
255
267
  v3Fee?: number;
256
268
  v3LpAddresses?: string[];
257
269
  v3ExactTokenIn?: string;
270
+ /** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
271
+ v3Tokens?: string[];
272
+ /** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
273
+ v3Fees?: number[];
258
274
  minOutputAmounts?: (string | bigint)[];
259
275
  config: FlapSignConfig;
260
276
  };
261
277
  /** ✅ PancakeProxy 批量卖出结果(简化版) */
262
278
  export type PancakeProxyBatchSellResult = MerkleSignedResult;
263
279
  /**
264
- * PancakeSwapProxy 单个授权参数
280
+ * PancakeSwap Router 单个授权参数(官方合约)
265
281
  */
266
282
  export type PancakeProxyApprovalParams = {
267
283
  chain: 'BSC';
@@ -269,9 +285,11 @@ export type PancakeProxyApprovalParams = {
269
285
  tokenAddress: string;
270
286
  amount: string | 'max';
271
287
  rpcUrl: string;
288
+ /** 路由类型,用于确定授权目标(V2 或 V3 Router) */
289
+ routeType?: 'v2' | 'v3-single' | 'v3-multi';
272
290
  };
273
291
  /**
274
- * PancakeSwapProxy 批量授权参数(Merkle Bundle 版本)
292
+ * PancakeSwap Router 批量授权参数(官方合约)
275
293
  */
276
294
  export type PancakeProxyApprovalBatchParams = {
277
295
  chain: FlapChainForMerkleBundle;
@@ -279,6 +297,8 @@ export type PancakeProxyApprovalBatchParams = {
279
297
  tokenAddress: string;
280
298
  amounts: (string | 'max')[];
281
299
  config: FlapSignConfig;
300
+ /** 路由类型,用于确定授权目标(V2 或 V3 Router) */
301
+ routeType?: 'v2' | 'v3-single' | 'v3-multi';
282
302
  };
283
303
  /** ✅ PancakeProxy 批量授权结果 */
284
304
  export type PancakeProxyApprovalBatchResult = {
@@ -1,5 +1,7 @@
1
1
  import { ethers, Wallet, Contract } from 'ethers';
2
2
  import { getOptimizedGasPrice, NonceManager } from '../../utils/bundle-helpers.js';
3
+ import { ADDRESSES } from '../../utils/constants.js';
4
+ import { V2_ROUTER_QUOTE_ABI, MULTICALL3_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
3
5
  import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
4
6
  // ==================== 链配置 ====================
5
7
  const CHAIN_ID_MAP = {
@@ -7,19 +9,16 @@ const CHAIN_ID_MAP = {
7
9
  'MONAD': 143,
8
10
  'XLAYER': 196
9
11
  };
10
- // ==================== ERC20 → 原生代币报价 ====================
11
- // BSC 链常量
12
- const BSC_PANCAKE_V2_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
13
- const BSC_WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
14
- // Monad 链常量
12
+ // ==================== 链常量 ====================
13
+ // 使用公共模块
14
+ const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
15
+ const BSC_WBNB = ADDRESSES.BSC.WBNB;
15
16
  const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
16
- const MONAD_WMON = '0x3bd359c1119da7da1d913d1c4d2b7c461115433a';
17
- // XLayer 链常量(PotatoSwap V2 Router)
17
+ const MONAD_WMON = ADDRESSES.MONAD.WMON;
18
18
  const XLAYER_POTATOSWAP_V2_ROUTER = '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e';
19
19
  const XLAYER_WOKB = '0xe538905cf8410324e03a5a23c1c177a474d59b2b';
20
- const ROUTER_ABI = [
21
- 'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)'
22
- ];
20
+ const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
21
+ const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
23
22
  /**
24
23
  * 获取 ERC20 代币 → 原生代币的报价
25
24
  */
@@ -101,13 +100,9 @@ async function batchGetBalances(provider, addresses, tokenAddress) {
101
100
  return Promise.all(addresses.map(addr => provider.getBalance(addr).catch(() => 0n)));
102
101
  }
103
102
  else {
104
- const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
105
- const MULTICALL3_ABI = [
106
- 'function aggregate3(tuple(address target, bool allowFailure, bytes callData)[] calls) view returns (tuple(bool success, bytes returnData)[] returnData)'
107
- ];
103
+ // 使用公共模块
108
104
  const multicall = new ethers.Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
109
- const ERC20_ABI = ['function balanceOf(address) view returns (uint256)'];
110
- const iface = new ethers.Interface(ERC20_ABI);
105
+ const iface = new ethers.Interface(ERC20_BALANCE_ABI);
111
106
  const calls = addresses.map(addr => ({
112
107
  target: tokenAddress,
113
108
  allowFailure: true,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * as Abis from './abis/index.js';
2
- export { ADDRESSES, CHAIN } from './utils/constants.js';
2
+ export { ERC20_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, MULTICALL3_ABI, V2_ROUTER_ABI, V2_ROUTER_QUOTE_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, V3_QUOTER_ABI, V2_FACTORY_ABI, V2_PAIR_ABI, V3_FACTORY_ABI, V3_POOL_ABI, FLAP_PORTAL_ABI, TM2_ABI, HELPER3_ABI, } from './abis/common.js';
3
+ export { ADDRESSES, CHAIN, BLOCKRAZOR_BUILDER_EOA as BUILDER_EOA, ZERO_ADDRESS as COMMON_ZERO_ADDRESS, DEFAULT_DEADLINE_MINUTES, V3_FEE_TIERS as COMMON_V3_FEE_TIERS, } from './utils/constants.js';
3
4
  export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
4
5
  export { ensureSellApprovalV1, checkSellApprovalV1, ensureSellApprovalV2, checkSellApprovalV2, ensureSellApproval, checkSellApproval, ensureFlapSellApproval, checkFlapSellApproval, ensureFlapSellApprovalBatch, checkFlapSellApprovalBatch, checkAllowance, approveToken, checkAllowanceBatch, approveTokenBatch, checkAllowanceRaw, approveTokenRaw, checkAllowanceBatchRaw, approveTokenBatchRaw, type EnsureAllowanceBatchItemResult, type ApproveTokenBatchParams, type ApproveTokenBatchRawParams, type ApproveTokenBatchResult, type ApproveTokenBatchSignResult } from './utils/erc20.js';
5
6
  export { parseFourError, type FourErrorCode } from './utils/errors.js';
@@ -21,7 +22,7 @@ export { createTokenFlow, type CreateTokenFlowInput, type CreateTokenFlowOutput
21
22
  export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle, type BundleParams, type BundleStatus, type Club48Config } from './clients/club48.js';
22
23
  export { MerkleClient, createMerkleClient, type MerkleConfig, type BundleParams as MerkleBundleParams, type SendBundleOptions, type BundleResult, type TransactionResult } from './clients/merkle.js';
23
24
  export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA, type BlockRazorConfig, type BlockRazorBundleParams, type SendBundleOptions as BlockRazorSendBundleOptions, type BundleResult as BlockRazorBundleResult, type TransactionResult as BlockRazorTransactionResult, type IncentiveTransactionParams } from './clients/blockrazor.js';
24
- export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, type GasPriceConfig, type GasEstimateConfig, type BuildTransactionOptions } from './utils/bundle-helpers.js';
25
+ export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, getDeadline, encodeV3Path, decodeV3Path, getGasLimit, getGasPriceConfig, getTxType, getChainId, type GasPriceConfig, type GasEstimateConfig, type BuildTransactionOptions, type CommonBundleConfig, } from './utils/bundle-helpers.js';
25
26
  export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle, type FourBundleConfig, type FourCreateWithBundleBuyParams, type FourCreateWithBundleBuyResult, type FourBatchBuyParams, type FourBatchBuyResult, type FourBatchSellParams, type FourBatchSellResult } from './contracts/tm-bundle.js';
26
27
  export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle, type FlapBundleConfig, type FlapChainForBundle, type FlapCreateWithBundleBuyParams, type FlapCreateWithBundleBuyResult, type FlapBatchBuyParams, type FlapBatchBuyResult, type FlapBatchSellParams, type FlapBatchSellResult } from './flap/portal-bundle.js';
27
28
  export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell, type FourPrivateBuyParams, type FourPrivateSellParams, type FourBatchPrivateBuyParams, type FourBatchPrivateSellParams } from './contracts/tm-bundle.js';
package/dist/index.js CHANGED
@@ -1,5 +1,12 @@
1
+ // ============================================================================
2
+ // 公共 ABI(统一管理)
3
+ // ============================================================================
1
4
  export * as Abis from './abis/index.js';
2
- export { ADDRESSES, CHAIN } from './utils/constants.js';
5
+ export { ERC20_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, MULTICALL3_ABI, V2_ROUTER_ABI, V2_ROUTER_QUOTE_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, V3_QUOTER_ABI, V2_FACTORY_ABI, V2_PAIR_ABI, V3_FACTORY_ABI, V3_POOL_ABI, FLAP_PORTAL_ABI, TM2_ABI, HELPER3_ABI, } from './abis/common.js';
6
+ // ============================================================================
7
+ // 公共常量(统一管理)
8
+ // ============================================================================
9
+ export { ADDRESSES, CHAIN, BLOCKRAZOR_BUILDER_EOA as BUILDER_EOA, ZERO_ADDRESS as COMMON_ZERO_ADDRESS, DEFAULT_DEADLINE_MINUTES, V3_FEE_TIERS as COMMON_V3_FEE_TIERS, } from './utils/constants.js';
3
10
  export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
4
11
  export {
5
12
  // Four.meme V1 授权
@@ -33,7 +40,7 @@ export { createTokenFlow } from './flows/create.js';
33
40
  export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle } from './clients/club48.js';
34
41
  export { MerkleClient, createMerkleClient } from './clients/merkle.js';
35
42
  export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA } from './clients/blockrazor.js';
36
- export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions } from './utils/bundle-helpers.js';
43
+ export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, getDeadline, encodeV3Path, decodeV3Path, getGasLimit, getGasPriceConfig, getTxType, getChainId, } from './utils/bundle-helpers.js';
37
44
  export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle } from './contracts/tm-bundle.js';
38
45
  export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle } from './flap/portal-bundle.js';
39
46
  export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell } from './contracts/tm-bundle.js';
@@ -4,12 +4,13 @@
4
4
  * 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行
5
5
  */
6
6
  import { ethers, Contract, Wallet } from 'ethers';
7
- import { NonceManager } from '../utils/bundle-helpers.js';
8
- import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
7
+ import { NonceManager, getDeadline } from '../utils/bundle-helpers.js';
8
+ import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA, ZERO_ADDRESS } from '../utils/constants.js';
9
9
  import { quoteV2, quoteV3, getTokenToNativeQuote, getWrappedNativeAddress } from '../utils/quote-helpers.js';
10
- // BlockRazor Builder EOA 地址(用于贿赂)
11
- // 参考文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
12
- const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
10
+ import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI } from '../abis/common.js';
11
+ /**
12
+ * 获取 Gas Limit
13
+ */
13
14
  function getGasLimit(config, defaultGas = 800000) {
14
15
  if (config.gasLimit !== undefined) {
15
16
  return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
@@ -33,22 +34,17 @@ async function getGasPrice(provider, config) {
33
34
  }
34
35
  return gasPrice;
35
36
  }
36
- // PancakeSwapProxy ABI
37
- const PANCAKE_PROXY_ABI = [
38
- 'function swapV2(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) payable returns (uint256)',
39
- 'function swapV3Single(address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint256 amountOutMin, address to) payable returns (uint256)',
40
- 'function swapV3MultiHop(address[] calldata lpAddresses, address exactTokenIn, uint256 amountIn, uint256 amountOutMin, address to) payable returns (uint256)'
41
- ];
42
- const PANCAKE_PROXY_ADDRESS = ADDRESSES.BSC.PancakeProxy;
43
- const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
44
- const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
45
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
46
- const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
47
- const ERC20_ALLOWANCE_ABI = [
48
- 'function allowance(address,address) view returns (uint256)',
49
- 'function approve(address,uint256) returns (bool)',
50
- 'function decimals() view returns (uint8)'
51
- ];
37
+ // ABI 别名(从公共模块导入)
38
+ const PANCAKE_V2_ROUTER_ABI = V2_ROUTER_ABI;
39
+ const PANCAKE_V3_ROUTER_ABI = V3_ROUTER02_ABI;
40
+ const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
41
+ // 使用官方 PancakeSwap Router 地址
42
+ const PANCAKE_V2_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV2Router;
43
+ const PANCAKE_V3_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV3Router;
44
+ // 常量
45
+ const FLAT_FEE = 0n;
46
+ const WBNB_ADDRESS = ADDRESSES.BSC.WBNB;
47
+ // getDeadline bundle-helpers.js 导入
52
48
  const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
53
49
  export async function pancakeBundleBuyFirstMerkle(params) {
54
50
  const { buyerPrivateKey, sellerPrivateKey, tokenAddress, routeParams, buyerFunds, buyerFundsPercentage, config, quoteToken, quoteTokenDecimals = 18 } = params;
@@ -337,7 +333,8 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
337
333
  return null;
338
334
  }
339
335
  const erc20Contract = new Contract(tokenAddress, ERC20_ALLOWANCE_ABI, provider);
340
- const currentAllowance = await erc20Contract.allowance(seller.address, PANCAKE_PROXY_ADDRESS);
336
+ // 使用官方 V2 Router 作为授权目标
337
+ const currentAllowance = await erc20Contract.allowance(seller.address, PANCAKE_V2_ROUTER_ADDRESS);
341
338
  // ✅ 阈值:MaxUint256 / 2,如果授权额度超过这个值,认为是"无限授权"
342
339
  const halfMaxUint = ethers.MaxUint256 / 2n;
343
340
  if (currentAllowance >= halfMaxUint) {
@@ -346,7 +343,7 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
346
343
  const approvalNonce = await nonceManager.getNextNonce(seller);
347
344
  return await seller.signTransaction({
348
345
  to: tokenAddress,
349
- data: APPROVE_INTERFACE.encodeFunctionData('approve', [PANCAKE_PROXY_ADDRESS, ethers.MaxUint256]),
346
+ data: APPROVE_INTERFACE.encodeFunctionData('approve', [PANCAKE_V2_ROUTER_ADDRESS, ethers.MaxUint256]),
350
347
  value: 0n,
351
348
  nonce: approvalNonce,
352
349
  gasLimit: 80000n,
@@ -356,32 +353,53 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
356
353
  });
357
354
  }
358
355
  async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountToken, buyer, seller, tokenAddress, useNativeToken = true }) {
359
- const proxyBuyer = new Contract(PANCAKE_PROXY_ADDRESS, PANCAKE_PROXY_ABI, buyer);
360
- const proxySeller = new Contract(PANCAKE_PROXY_ADDRESS, PANCAKE_PROXY_ABI, seller);
361
- const deadline = Math.floor(Date.now() / 1000) + 600;
356
+ const deadline = getDeadline();
362
357
  // ✅ ERC20 购买时,value 只需要 FLAT_FEE
363
358
  const buyValue = useNativeToken ? buyerFundsWei + FLAT_FEE : FLAT_FEE;
364
359
  if (routeParams.routeType === 'v2') {
365
360
  const { v2Path } = routeParams;
366
361
  const reversePath = [...v2Path].reverse();
367
- const buyUnsigned = await proxyBuyer.swapV2.populateTransaction(buyerFundsWei, 0n, v2Path, buyer.address, deadline, { value: buyValue } // ✅ 使用动态 value
368
- );
369
- const sellUnsigned = await proxySeller.swapV2.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline, { value: FLAT_FEE });
362
+ // ✅ 使用官方 V2 Router
363
+ const v2RouterBuyer = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, buyer);
364
+ const v2RouterSeller = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, seller);
365
+ // 买入:BNB → Token
366
+ const buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
367
+ // 卖出:Token → BNB
368
+ const sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
370
369
  return { buyUnsigned, sellUnsigned };
371
370
  }
372
371
  if (routeParams.routeType === 'v3-single') {
373
372
  const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
374
- const buyUnsigned = await proxyBuyer.swapV3Single.populateTransaction(v3TokenIn, v3TokenOut, v3Fee, buyerFundsWei, 0n, buyer.address, { value: buyValue } // ✅ 使用动态 value
375
- );
376
- const sellUnsigned = await proxySeller.swapV3Single.populateTransaction(v3TokenOut, v3TokenIn, v3Fee, sellAmountToken, 0n, seller.address, { value: FLAT_FEE });
373
+ const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
374
+ const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
375
+ const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
376
+ // 买入:WBNB → Token
377
+ const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
378
+ tokenIn: v3TokenIn,
379
+ tokenOut: v3TokenOut,
380
+ fee: v3Fee,
381
+ recipient: buyer.address,
382
+ amountIn: buyerFundsWei,
383
+ amountOutMinimum: 0n,
384
+ sqrtPriceLimitX96: 0n
385
+ }]);
386
+ const buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
387
+ // 卖出:Token → WBNB → BNB
388
+ const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
389
+ tokenIn: v3TokenOut,
390
+ tokenOut: v3TokenIn,
391
+ fee: v3Fee,
392
+ recipient: PANCAKE_V3_ROUTER_ADDRESS,
393
+ amountIn: sellAmountToken,
394
+ amountOutMinimum: 0n,
395
+ sqrtPriceLimitX96: 0n
396
+ }]);
397
+ const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
398
+ const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
377
399
  return { buyUnsigned, sellUnsigned };
378
400
  }
379
- const { v3LpAddresses, v3ExactTokenIn } = routeParams;
380
- const exactTokenOut = v3ExactTokenIn.toLowerCase() === WBNB_ADDRESS.toLowerCase() ? tokenAddress : WBNB_ADDRESS;
381
- const buyUnsigned = await proxyBuyer.swapV3MultiHop.populateTransaction(v3LpAddresses, v3ExactTokenIn, buyerFundsWei, 0n, buyer.address, { value: buyValue } // ✅ 使用动态 value
382
- );
383
- const sellUnsigned = await proxySeller.swapV3MultiHop.populateTransaction(v3LpAddresses, exactTokenOut, sellAmountToken, 0n, seller.address, { value: FLAT_FEE });
384
- return { buyUnsigned, sellUnsigned };
401
+ // V3 多跳暂不支持官方合约
402
+ throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
385
403
  }
386
404
  /**
387
405
  * ✅ 使用 quote-helpers 统一报价(估算利润)