four-flap-meme-sdk 1.6.99 → 1.7.2

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.
@@ -79,6 +79,8 @@ export interface XLayerCrossSwapParams {
79
79
  quoteTokenDecimals?: number;
80
80
  buyersPerSell?: number;
81
81
  disperseHopCount?: number;
82
+ /** ✅ 预获取的 nonce(地址 -> nonce),避免 nonce 不同步 */
83
+ startNonces?: Map<string, number>;
82
84
  }
83
85
  export interface XLayerCrossSwapResult {
84
86
  signedTransactions: string[];
@@ -9,16 +9,19 @@
9
9
  import { ethers, Contract, Wallet } from 'ethers';
10
10
  import { calculateSellAmount } from '../utils/swap-helpers.js';
11
11
  import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
12
- import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from '../utils/constants.js';
12
+ import { PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from '../utils/constants.js';
13
13
  import { quoteV2, quoteV3 } from '../utils/quote-helpers.js';
14
14
  import { V2_ROUTER_ABI, V3_ROUTER02_ABI } from '../abis/common.js';
15
15
  import { generateWallets } from '../utils/wallet.js';
16
+ // ✅ 从 XLayer 常量导入正确的路由地址
17
+ import { POTATOSWAP_V2_ROUTER, POTATOSWAP_SWAP_ROUTER02, WOKB as WOKB_CONST } from './constants.js';
16
18
  // ==================== XLayer 专用常量 ====================
17
19
  const XLAYER_CHAIN_ID = 196;
18
20
  const XLAYER_CHAIN_NAME = 'XLAYER';
19
- const WOKB_ADDRESS = ADDRESSES.XLAYER.WOKB;
20
- const POTATO_V2_ROUTER = '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e';
21
- const POTATO_V3_ROUTER = '0x4e57fe71624fBCD5F1175C6B1a1e5d5fE2e4Da45';
21
+ const WOKB_ADDRESS = ethers.getAddress(WOKB_CONST);
22
+ // 强制校验和,避免大小写错误导致的 bad address checksum
23
+ const POTATO_V2_ROUTER = ethers.getAddress(POTATOSWAP_V2_ROUTER);
24
+ const POTATO_V3_ROUTER = ethers.getAddress(POTATOSWAP_SWAP_ROUTER02); // ✅ SwapRouter02 用于 V3 交易
22
25
  const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
23
26
  const ERC20_TRANSFER_GAS_LIMIT = 65000n;
24
27
  const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
@@ -87,6 +90,17 @@ async function quoteSellOutput(provider, routeParams, sellAmountWei) {
87
90
  console.log(`[XLayer quoteSellOutput] V3 报价成功: ${ethers.formatEther(result.amountOut)} OKB`);
88
91
  return result.amountOut;
89
92
  }
93
+ // ❗️兜底:如果 V3 报价失败且提供了 v2Path,则尝试 V2 报价(避免因为无对应费率池导致失败)
94
+ if (params.v2Path && params.v2Path.length >= 2) {
95
+ console.warn('[XLayer quoteSellOutput] V3 报价失败,尝试 V2 兜底');
96
+ const tokenIn = params.v2Path[0];
97
+ const tokenOut = params.v2Path[params.v2Path.length - 1];
98
+ const v2Result = await quoteV2(provider, tokenIn, tokenOut, sellAmountWei, XLAYER_CHAIN_NAME);
99
+ if (v2Result.amountOut > 0n) {
100
+ console.log(`[XLayer quoteSellOutput] V2 兜底报价成功: ${ethers.formatEther(v2Result.amountOut)} OKB`);
101
+ return v2Result.amountOut;
102
+ }
103
+ }
90
104
  throw new Error(`V3 单跳报价失败: tokenIn=${params.v3TokenIn}, tokenOut=${params.v3TokenOut}, fee=${params.v3Fee}`);
91
105
  }
92
106
  if (routeParams.routeType === 'v3-multi') {
@@ -97,6 +111,17 @@ async function quoteSellOutput(provider, routeParams, sellAmountWei) {
97
111
  console.log(`[XLayer quoteSellOutput] V3 多跳报价成功: ${ethers.formatEther(result.amountOut)} OKB`);
98
112
  return result.amountOut;
99
113
  }
114
+ // ❗️兜底:如果 V3 多跳失败且提供 v2Path,则尝试 V2 报价
115
+ if (params.v2Path && params.v2Path.length >= 2) {
116
+ console.warn('[XLayer quoteSellOutput] V3 多跳报价失败,尝试 V2 兜底');
117
+ const tokenInV2 = params.v2Path[0];
118
+ const tokenOutV2 = params.v2Path[params.v2Path.length - 1];
119
+ const v2Result = await quoteV2(provider, tokenInV2, tokenOutV2, sellAmountWei, XLAYER_CHAIN_NAME);
120
+ if (v2Result.amountOut > 0n) {
121
+ console.log(`[XLayer quoteSellOutput] V2 多跳兜底成功: ${ethers.formatEther(v2Result.amountOut)} OKB`);
122
+ return v2Result.amountOut;
123
+ }
124
+ }
100
125
  throw new Error(`V3 多跳报价失败`);
101
126
  }
102
127
  throw new Error(`不支持的路由类型: ${routeParams.routeType}`);
@@ -458,7 +483,7 @@ export async function xlayerQuickBatchSwapMerkle(params) {
458
483
  }
459
484
  // ==================== XLayer 交叉换手 ====================
460
485
  export async function xlayerCrossSwapMerkle(params) {
461
- const { sellerPrivateKeys, sellAmounts, buyerPrivateKeys, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, buyersPerSell, disperseHopCount = 0 } = params;
486
+ const { sellerPrivateKeys, sellAmounts, buyerPrivateKeys, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, buyersPerSell, disperseHopCount = 0, startNonces: inputNonces } = params;
462
487
  if (sellerPrivateKeys.length === 0)
463
488
  throw new Error('至少需要一个卖方');
464
489
  if (sellerPrivateKeys.length !== sellAmounts.length)
@@ -469,16 +494,28 @@ export async function xlayerCrossSwapMerkle(params) {
469
494
  const nonceManager = new NonceManager(context.provider);
470
495
  const allSellerWallets = sellerPrivateKeys.map(pk => new Wallet(pk, context.provider));
471
496
  const allBuyerWallets = buyerPrivateKeys.map(pk => new Wallet(pk, context.provider));
472
- // 预先获取所有钱包的初始 nonce
497
+ // 优先使用前端传入的 nonce,避免 nonce 不同步
473
498
  const addressToNonce = new Map();
474
499
  for (const wallet of allSellerWallets) {
475
500
  if (!addressToNonce.has(wallet.address)) {
476
- addressToNonce.set(wallet.address, await nonceManager.getNextNonce(wallet));
501
+ const inputNonce = inputNonces?.get(wallet.address.toLowerCase()) ?? inputNonces?.get(wallet.address);
502
+ if (inputNonce !== undefined) {
503
+ addressToNonce.set(wallet.address, inputNonce);
504
+ }
505
+ else {
506
+ addressToNonce.set(wallet.address, await nonceManager.getNextNonce(wallet));
507
+ }
477
508
  }
478
509
  }
479
510
  for (const wallet of allBuyerWallets) {
480
511
  if (!addressToNonce.has(wallet.address)) {
481
- addressToNonce.set(wallet.address, await nonceManager.getNextNonce(wallet));
512
+ const inputNonce = inputNonces?.get(wallet.address.toLowerCase()) ?? inputNonces?.get(wallet.address);
513
+ if (inputNonce !== undefined) {
514
+ addressToNonce.set(wallet.address, inputNonce);
515
+ }
516
+ else {
517
+ addressToNonce.set(wallet.address, await nonceManager.getNextNonce(wallet));
518
+ }
482
519
  }
483
520
  }
484
521
  console.log(`[xlayerCrossSwapMerkle] 初始化: ${sellerPrivateKeys.length} 卖方, ${buyerPrivateKeys.length} 买方`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.6.99",
3
+ "version": "1.7.2",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",