four-flap-meme-sdk 1.5.1 → 1.5.3

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.
@@ -228,6 +228,8 @@ export const FLAP_PORTAL_ABI = [
228
228
  'function newTokenV4((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile)) external payable returns (address)',
229
229
  // 交易
230
230
  'function swapExactInput((address inputToken,address outputToken,uint256 inputAmount,uint256 minOutputAmount,bytes permitData)) external payable returns (uint256)',
231
+ // ✅ V3:支持 extensionData(注意:这里的 V3 指“扩展交易接口版本”,不是“外盘 V3 池子”)
232
+ 'function swapExactInputV3((address inputToken,address outputToken,uint256 inputAmount,uint256 minOutputAmount,bytes permitData,bytes extensionData)) external payable returns (uint256)',
231
233
  'function quoteExactInput((address inputToken,address outputToken,uint256 inputAmount)) external view returns (uint256)',
232
234
  // 旧版兼容
233
235
  'function buy(address token, uint256 minReceived) external payable returns (uint256)',
@@ -57,9 +57,15 @@ export interface FlapCreateToDexParams {
57
57
  dexBuyers?: DexBuyerConfig[];
58
58
  /** 外盘总买入金额(用于自动分配) */
59
59
  dexTotalBuyAmount?: string;
60
- /** 外盘池类型(V2 或 V3),默认 V3 */
60
+ /**
61
+ * 外盘池类型(V2 或 V3),默认 V3
62
+ * @deprecated 现在外盘买入统一改为走 Portal 的 swapExactInput/swapExactInputV3 进行自动路由,
63
+ * 不再需要手动指定池类型/fee;保留字段仅为兼容老调用方。
64
+ */
61
65
  dexPoolType?: DexPoolType;
62
- /** V3 费率(100/500/2500/10000),默认 2500 */
66
+ /**
67
+ * @deprecated 同上:不再需要手动传 V3 fee;由合约记录的池子信息决定。
68
+ */
63
69
  v3Fee?: number;
64
70
  /** 发币扩展参数 */
65
71
  dexThresh?: number;
@@ -10,7 +10,7 @@
10
10
  import { ethers, Contract, Wallet } from 'ethers';
11
11
  import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
12
12
  import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
13
- import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
13
+ import { PROFIT_CONFIG, ZERO_ADDRESS } from '../../utils/constants.js';
14
14
  import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
15
15
  // ==================== ERC20 ABI ====================
16
16
  const ERC20_ABI = [
@@ -26,86 +26,20 @@ const ERC20_ABI = [
26
26
  }
27
27
  ];
28
28
  // ==================== 链常量 ====================
29
- // BSC
30
- const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
31
- const BSC_PANCAKE_V3_ROUTER = ADDRESSES.BSC.PancakeV3Router;
32
- const BSC_WBNB = ADDRESSES.BSC.WBNB;
33
- // XLAYER
34
- const XLAYER_POTATOSWAP_V2_ROUTER = '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e';
35
- const XLAYER_POTATOSWAP_V3_ROUTER = '0xB45D0149249488333E3F3f9F359807F4b810C1FC';
36
- const XLAYER_WOKB = '0xe538905cf8410324e03a5a23c1c177a474d59b2b';
37
- // 链 ID 映射
38
- const CHAIN_ID_MAP = {
39
- bsc: 56,
40
- xlayer: 196,
41
- };
42
29
  // 获取链配置
43
30
  function getChainConfig(chain) {
44
31
  if (chain === 'xlayer') {
45
32
  return {
46
33
  chainId: 196,
47
- v2Router: XLAYER_POTATOSWAP_V2_ROUTER,
48
- v3Router: XLAYER_POTATOSWAP_V3_ROUTER,
49
- wrappedNative: XLAYER_WOKB,
50
34
  nativeSymbol: 'OKB',
51
35
  };
52
36
  }
53
37
  // 默认 BSC
54
38
  return {
55
39
  chainId: 56,
56
- v2Router: BSC_PANCAKE_V2_ROUTER,
57
- v3Router: BSC_PANCAKE_V3_ROUTER,
58
- wrappedNative: BSC_WBNB,
59
40
  nativeSymbol: 'BNB',
60
41
  };
61
42
  }
62
- // PancakeSwap Router ABI
63
- const PANCAKE_V3_ROUTER_ABI = [
64
- {
65
- "type": "function",
66
- "name": "exactInputSingle",
67
- "inputs": [
68
- {
69
- "name": "params",
70
- "type": "tuple",
71
- "components": [
72
- { "name": "tokenIn", "type": "address" },
73
- { "name": "tokenOut", "type": "address" },
74
- { "name": "fee", "type": "uint24" },
75
- { "name": "recipient", "type": "address" },
76
- { "name": "amountIn", "type": "uint256" },
77
- { "name": "amountOutMinimum", "type": "uint256" },
78
- { "name": "sqrtPriceLimitX96", "type": "uint160" }
79
- ]
80
- }
81
- ],
82
- "outputs": [{ "name": "amountOut", "type": "uint256" }],
83
- "stateMutability": "payable"
84
- },
85
- {
86
- "type": "function",
87
- "name": "multicall",
88
- "inputs": [{ "name": "data", "type": "bytes[]" }],
89
- "outputs": [{ "name": "results", "type": "bytes[]" }],
90
- "stateMutability": "payable"
91
- },
92
- {
93
- "type": "function",
94
- "name": "swapExactTokensForTokens",
95
- "inputs": [
96
- { "name": "amountIn", "type": "uint256" },
97
- { "name": "amountOutMin", "type": "uint256" },
98
- { "name": "path", "type": "address[]" },
99
- { "name": "to", "type": "address" }
100
- ],
101
- "outputs": [{ "name": "amountOut", "type": "uint256" }],
102
- "stateMutability": "payable"
103
- },
104
- ];
105
- // ==================== V3 费率配置 ====================
106
- // USD1/USDT 使用 100 bps (0.01%),其他使用 2500 bps (0.25%)
107
- const USD1_V3_FEE = 100;
108
- const DEFAULT_V3_FEE = 2500;
109
43
  // ==================== 工具函数 ====================
110
44
  /** 构建 ERC20 approve 交易 */
111
45
  async function buildApproveTransaction(wallet, tokenAddress, spenderAddress, amount, nonce, gasPrice, txType, chainId = 56 // ✅ 添加 chainId 参数
@@ -394,12 +328,16 @@ export async function flapBundleCreateToDex(params) {
394
328
  const buyNonce = noncesMap.get(addr);
395
329
  noncesMap.set(addr, buyNonce + 1);
396
330
  const portal = new Contract(portalAddress, PORTAL_ABI, wallet);
397
- const unsigned = await portal.swapExactInput.populateTransaction({
331
+ // 交易阶段统一优先使用 swapExactInputV3(支持 extensionData;无扩展时传 0x 即可)
332
+ // 说明:这里的 V3 指“交易接口版本(扩展支持)”,不是“外盘 V3 池子”
333
+ const extensionData = params.extensionData ?? '0x';
334
+ const unsigned = await portal.swapExactInputV3.populateTransaction({
398
335
  inputToken,
399
336
  outputToken: tokenAddress,
400
337
  inputAmount: curveBuyAmounts[i],
401
338
  minOutputAmount: 0n,
402
- permitData: '0x' // 不使用 permit,使用链上 approve
339
+ permitData: '0x', // 不使用 permit,使用链上 approve
340
+ extensionData
403
341
  }, useNativeToken ? { value: curveBuyAmounts[i] } : {});
404
342
  // 最后一个买家触发毕业,需要更多 gas
405
343
  const isLastBuyer = i === curveWallets.length - 1;
@@ -428,66 +366,44 @@ export async function flapBundleCreateToDex(params) {
428
366
  // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
429
367
  curveBuyResults.forEach(txs => allTransactions.push(...txs));
430
368
  // 4. 外盘买入交易(PancakeSwap)
431
- // ✅ ERC20 需要先 approve,再 swap
369
+ // ✅ 改造:外盘买入不再直连 Router(避免 fee/池子不匹配),统一走 Portal 的 swapExactInputV3 自动路由:
370
+ // - 若 token 已毕业(DEX 状态)→ Portal 自动转发到 PortalDexRouter,按合约记录的 poolType/pool/fee 成交(V2/V3 自动)
371
+ // - 若尚未毕业(Tradable)→ 会回退走 bonding curve(这通常不是预期,所以仍依赖“最后一单触发毕业”的假设)
372
+ // ✅ ERC20 输入仍需先 approve 给 Portal
432
373
  if (enableDexBuy && dexWallets.length > 0) {
433
374
  const dexBuyTxPromises = dexWallets.map(async ({ wallet }, i) => {
434
375
  const addr = wallet.address.toLowerCase();
435
376
  const signedTxs = [];
436
377
  const buyAmount = dexBuyAmounts[i];
437
- // 使用动态 Router 地址
438
- const smartRouter = dexPoolType === 'v3' ? chainConfig.v3Router : chainConfig.v2Router;
439
- const wrappedNative = chainConfig.wrappedNative;
440
- // ✅ 根据 quoteToken 强制选择 V3 费率(参考 Flap 官方配置)
441
- // Flap 合约在毕业时创建的 V3 池子费率由 quoteToken 决定:
442
- // - BNB (原生代币) → 0.25% (2500)
443
- // - USD1 等稳定币 → 0.01% (100)
444
- // 即使传入了 lpFeeProfile,Flap 合约也可能忽略,所以这里强制匹配
445
- const actualV3Fee = useNativeToken ? DEFAULT_V3_FEE : USD1_V3_FEE;
378
+ const extensionData = params.extensionData ?? '0x';
446
379
  // ✅ ERC20: 先构建 approve 交易
447
380
  if (!useNativeToken) {
448
381
  const approveNonce = noncesMap.get(addr);
449
382
  noncesMap.set(addr, approveNonce + 1);
450
- const approveTx = await buildApproveTransaction(wallet, quoteToken, smartRouter, buyAmount, approveNonce, gasPrice, txType, chainId // ✅ 传递 chainId
383
+ const approveTx = await buildApproveTransaction(wallet, quoteToken, portalAddress, // approve Portal,而不是外部 Router
384
+ buyAmount, approveNonce, gasPrice, txType, chainId // ✅ 传递 chainId
451
385
  );
452
386
  signedTxs.push(approveTx);
453
387
  }
454
388
  // 构建买入交易
455
389
  const buyNonce = noncesMap.get(addr);
456
390
  noncesMap.set(addr, buyNonce + 1);
457
- let multicallData = [];
458
- let value;
459
- const routerInterface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
460
- if (dexPoolType === 'v3') {
461
- // V3: exactInputSingle
462
- const params = {
463
- tokenIn: useNativeToken ? wrappedNative : quoteToken,
464
- tokenOut: tokenAddress,
465
- fee: actualV3Fee,
466
- recipient: wallet.address,
467
- amountIn: buyAmount,
468
- amountOutMinimum: 0n,
469
- sqrtPriceLimitX96: 0n
470
- };
471
- multicallData = [routerInterface.encodeFunctionData('exactInputSingle', [params])];
472
- value = useNativeToken ? buyAmount : 0n;
473
- }
474
- else {
475
- // V2: swapExactTokensForTokens
476
- const path = useNativeToken ? [wrappedNative, tokenAddress] : [quoteToken, tokenAddress];
477
- const swapData = routerInterface.encodeFunctionData('swapExactTokensForTokens', [buyAmount, 0n, path, wallet.address]);
478
- multicallData = [swapData];
479
- value = useNativeToken ? buyAmount : 0n;
480
- }
481
- const calldata = routerInterface.encodeFunctionData('multicall', [multicallData]);
391
+ const portal = new Contract(portalAddress, PORTAL_ABI, wallet);
392
+ const unsigned = await portal.swapExactInputV3.populateTransaction({
393
+ inputToken,
394
+ outputToken: tokenAddress,
395
+ inputAmount: buyAmount,
396
+ minOutputAmount: 0n,
397
+ permitData: '0x',
398
+ extensionData
399
+ }, useNativeToken ? { value: buyAmount } : {});
482
400
  const tx = {
483
- to: smartRouter,
484
- data: calldata,
485
- from: wallet.address,
401
+ ...unsigned,
486
402
  nonce: buyNonce,
487
403
  gasLimit: BigInt(500000),
488
404
  chainId,
489
405
  type: txType,
490
- value
406
+ value: useNativeToken ? buyAmount : 0n
491
407
  };
492
408
  if (txType === 2) {
493
409
  tx.maxFeePerGas = gasPrice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.01",
3
+ "version": "1.5.3",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",