four-flap-meme-sdk 1.5.3 → 1.5.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.
@@ -25,6 +25,49 @@ const ERC20_ABI = [
25
25
  stateMutability: "nonpayable"
26
26
  }
27
27
  ];
28
+ // ==================== PancakeSwap Router ABI ====================
29
+ const PANCAKE_ROUTER_ABI = [
30
+ {
31
+ type: "function",
32
+ name: "exactInputSingle",
33
+ inputs: [
34
+ {
35
+ name: "params",
36
+ type: "tuple",
37
+ components: [
38
+ { name: "tokenIn", type: "address" },
39
+ { name: "tokenOut", type: "address" },
40
+ { name: "fee", type: "uint24" },
41
+ { name: "recipient", type: "address" },
42
+ { name: "amountIn", type: "uint256" },
43
+ { name: "amountOutMinimum", type: "uint256" },
44
+ { name: "sqrtPriceLimitX96", type: "uint160" }
45
+ ]
46
+ }
47
+ ],
48
+ outputs: [{ name: "amountOut", type: "uint256" }],
49
+ stateMutability: "payable"
50
+ },
51
+ {
52
+ type: "function",
53
+ name: "multicall",
54
+ inputs: [{ name: "data", type: "bytes[]" }],
55
+ outputs: [{ name: "results", type: "bytes[]" }],
56
+ stateMutability: "payable"
57
+ }
58
+ ];
59
+ // ==================== DEX 地址常量 ====================
60
+ const DEX_ADDRESSES = {
61
+ BSC: {
62
+ PANCAKE_SMART_ROUTER: '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4',
63
+ WBNB: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
64
+ },
65
+ XLAYER: {
66
+ // xLayer 使用 PotatoSwap
67
+ PANCAKE_SMART_ROUTER: '0x0000000000000000000000000000000000000000', // TODO: 添加 xLayer DEX 地址
68
+ WBNB: '0x0000000000000000000000000000000000000000',
69
+ }
70
+ };
28
71
  // ==================== 链常量 ====================
29
72
  // 获取链配置
30
73
  function getChainConfig(chain) {
@@ -149,6 +192,32 @@ export async function flapBundleCreateToDex(params) {
149
192
  // 判断是否使用原生代币
150
193
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
151
194
  const inputToken = useNativeToken ? ZERO_ADDRESS : quoteToken;
195
+ // ✅ 计算实际使用的 V3 费率
196
+ // 优先级:lpFeeProfile > v3Fee > 默认值(根据 quoteToken)
197
+ // lpFeeProfile: 0=STANDARD(0.25%), 1=LOW(0.01%), 2=HIGH(1%)
198
+ let actualV3Fee;
199
+ if (params.lpFeeProfile !== undefined) {
200
+ // 从 lpFeeProfile 转换为 V3 费率
201
+ switch (params.lpFeeProfile) {
202
+ case 1:
203
+ actualV3Fee = 100;
204
+ break; // LOW: 0.01%
205
+ case 2:
206
+ actualV3Fee = 10000;
207
+ break; // HIGH: 1%
208
+ default:
209
+ actualV3Fee = 2500;
210
+ break; // STANDARD: 0.25%
211
+ }
212
+ }
213
+ else if (v3Fee !== undefined && v3Fee !== 2500) {
214
+ actualV3Fee = v3Fee;
215
+ }
216
+ else {
217
+ // 根据 quoteToken 使用默认值(参考 Flap 官方配置)
218
+ // BNB → 0.25% (2500), USD1/稳定币 → 0.01% (100)
219
+ actualV3Fee = useNativeToken ? 2500 : 100;
220
+ }
152
221
  // ✅ 获取链配置
153
222
  const chainConfig = getChainConfig(chain);
154
223
  const chainId = chainConfig.chainId;
@@ -365,40 +434,58 @@ export async function flapBundleCreateToDex(params) {
365
434
  const curveBuyResults = await Promise.all(curveBuyTxPromises);
366
435
  // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
367
436
  curveBuyResults.forEach(txs => allTransactions.push(...txs));
368
- // 4. 外盘买入交易(PancakeSwap)
369
- // ✅ 改造:外盘买入不再直连 Router(避免 fee/池子不匹配),统一走 Portal swapExactInputV3 自动路由:
370
- // - 若 token 已毕业(DEX 状态)→ Portal 自动转发到 PortalDexRouter,按合约记录的 poolType/pool/fee 成交(V2/V3 自动)
371
- // - 若尚未毕业(Tradable)→ 会回退走 bonding curve(这通常不是预期,所以仍依赖“最后一单触发毕业”的假设)
372
- // ERC20 输入仍需先 approve 给 Portal
437
+ // 4. 外盘买入交易(直接调用 PancakeSwap Router
438
+ // ✅ 重要修改:直接调用 PancakeSwap SmartRouterexactInputSingle
439
+ // 参考官方代码: flap-bundle-release/app/v2/pvp/001_launch_buy.ts
440
+ //
441
+ // 原因:之前使用 Portal swapExactInputV3 进行"自动路由",但这有风险:
442
+ // - 如果代币刚毕业,Portal 可能还没有正确记录池子信息
443
+ // - 导致路由失败或回退到内盘
444
+ //
445
+ // 新方案:毕业后直接调用 PancakeSwap Router,确保外盘交易成功
373
446
  if (enableDexBuy && dexWallets.length > 0) {
447
+ // 获取 DEX 地址
448
+ const dexAddresses = chain === 'xlayer' ? DEX_ADDRESSES.XLAYER : DEX_ADDRESSES.BSC;
449
+ const smartRouterAddress = dexAddresses.PANCAKE_SMART_ROUTER;
450
+ const wbnbAddress = dexAddresses.WBNB;
451
+ // 获取 V3 费率
452
+ // 根据 lpFeeProfile 或 quoteToken 选择
453
+ const dexV3Fee = actualV3Fee;
374
454
  const dexBuyTxPromises = dexWallets.map(async ({ wallet }, i) => {
375
455
  const addr = wallet.address.toLowerCase();
376
456
  const signedTxs = [];
377
457
  const buyAmount = dexBuyAmounts[i];
378
- const extensionData = params.extensionData ?? '0x';
379
- // ✅ ERC20: 先构建 approve 交易
458
+ // ERC20: 先构建 approve 交易(approve 给 PancakeSwap Router)
380
459
  if (!useNativeToken) {
381
460
  const approveNonce = noncesMap.get(addr);
382
461
  noncesMap.set(addr, approveNonce + 1);
383
- const approveTx = await buildApproveTransaction(wallet, quoteToken, portalAddress, // ✅ approve 给 Portal,而不是外部 Router
384
- buyAmount, approveNonce, gasPrice, txType, chainId // ✅ 传递 chainId
385
- );
462
+ const approveTx = await buildApproveTransaction(wallet, quoteToken, smartRouterAddress, // ✅ approve 给 PancakeSwap Router
463
+ buyAmount, approveNonce, gasPrice, txType, chainId);
386
464
  signedTxs.push(approveTx);
387
465
  }
388
- // 构建买入交易
466
+ // 构建 PancakeSwap exactInputSingle 交易(使用 multicall 方式,与官方一致)
389
467
  const buyNonce = noncesMap.get(addr);
390
468
  noncesMap.set(addr, buyNonce + 1);
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 } : {});
469
+ // 对于 BNB,使用 WBNB 作为 tokenIn(Router 会自动 wrap)
470
+ const tokenIn = useNativeToken ? wbnbAddress : quoteToken;
471
+ // ✅ 使用官方方式:先编码 exactInputSingle,再用 multicall 包装
472
+ const routerInterface = new ethers.Interface(PANCAKE_ROUTER_ABI);
473
+ const exactInputSingleParams = {
474
+ tokenIn,
475
+ tokenOut: tokenAddress,
476
+ fee: dexV3Fee, // ✅ 使用与 newTokenV4 创建池子匹配的费率
477
+ recipient: wallet.address,
478
+ amountIn: buyAmount,
479
+ amountOutMinimum: 0n, // 不设置滑点保护(Bundle 中可以接受)
480
+ sqrtPriceLimitX96: 0n
481
+ };
482
+ // 编码 exactInputSingle 调用
483
+ const exactInputSingleData = routerInterface.encodeFunctionData('exactInputSingle', [exactInputSingleParams]);
484
+ // 用 multicall 包装(官方要求的调用方式)
485
+ const multicallData = routerInterface.encodeFunctionData('multicall', [[exactInputSingleData]]);
400
486
  const tx = {
401
- ...unsigned,
487
+ to: smartRouterAddress,
488
+ data: multicallData,
402
489
  nonce: buyNonce,
403
490
  gasLimit: BigInt(500000),
404
491
  chainId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.3",
3
+ "version": "1.5.5",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",