four-flap-meme-sdk 1.5.16 → 1.5.17

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.
@@ -333,6 +333,64 @@ async function getGasPrice(provider, config) {
333
333
  function isNativeToken(quoteToken) {
334
334
  return !quoteToken || quoteToken === ZERO_ADDRESS;
335
335
  }
336
+ // ============================================================================
337
+ // XLAYER V3 报价(slot0 现货价,纯 V3,不串 V2)
338
+ // - 只用于“利润换算”为原生币,避免 XLAYER 没有 v3Quoter 导致 profit=0
339
+ // - 不改 BSC 的任何配置/逻辑
340
+ // ============================================================================
341
+ const XLAYER_V3_FACTORY_ABI = [
342
+ 'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)',
343
+ ];
344
+ const XLAYER_V3_POOL_ABI = [
345
+ 'function slot0() view returns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked)',
346
+ 'function token0() view returns (address)',
347
+ 'function token1() view returns (address)',
348
+ ];
349
+ const V3_FEE_DENOMINATOR = 1000000n; // UniswapV3 fee: X / 1e6
350
+ async function quoteXLayerV3TokenToNativeBySlot0(params) {
351
+ try {
352
+ const { provider, tokenIn, amountIn, fee } = params;
353
+ if (!tokenIn || amountIn <= 0n)
354
+ return 0n;
355
+ const chainFactory = DIRECT_ROUTERS.XLAYER.V3_FACTORY;
356
+ const wrappedNative = DIRECT_ROUTERS.XLAYER.WOKB;
357
+ if (!chainFactory || !wrappedNative)
358
+ return 0n;
359
+ const tokenInLower = tokenIn.toLowerCase();
360
+ const wrappedLower = wrappedNative.toLowerCase();
361
+ if (tokenInLower === wrappedLower)
362
+ return amountIn;
363
+ const factory = new Contract(chainFactory, XLAYER_V3_FACTORY_ABI, provider);
364
+ const poolAddr = await factory.getPool?.(tokenIn, wrappedNative, fee);
365
+ if (!poolAddr || poolAddr.toLowerCase() === ZERO_ADDRESS.toLowerCase())
366
+ return 0n;
367
+ const pool = new Contract(poolAddr, XLAYER_V3_POOL_ABI, provider);
368
+ const [t0, t1, slot0] = await Promise.all([pool.token0?.(), pool.token1?.(), pool.slot0?.()]);
369
+ if (!t0 || !t1 || !slot0)
370
+ return 0n;
371
+ const sqrtPriceX96 = BigInt(slot0[0]);
372
+ if (sqrtPriceX96 <= 0n)
373
+ return 0n;
374
+ const amountInLessFee = (amountIn * (V3_FEE_DENOMINATOR - BigInt(fee))) / V3_FEE_DENOMINATOR;
375
+ if (amountInLessFee <= 0n)
376
+ return 0n;
377
+ const Q192 = 2n ** 192n;
378
+ const num = sqrtPriceX96 * sqrtPriceX96;
379
+ const t0Lower = String(t0).toLowerCase();
380
+ const t1Lower = String(t1).toLowerCase();
381
+ // sqrtPriceX96 表示 token1/token0 的现货价(raw)
382
+ if (tokenInLower === t0Lower && wrappedLower === t1Lower) {
383
+ return (amountInLessFee * num) / Q192;
384
+ }
385
+ if (tokenInLower === t1Lower && wrappedLower === t0Lower) {
386
+ return (amountInLessFee * Q192) / num;
387
+ }
388
+ return 0n;
389
+ }
390
+ catch {
391
+ return 0n;
392
+ }
393
+ }
336
394
  // ✅ getTokenToNativeQuote 函数已移至 ../utils/quote-helpers.ts
337
395
  /**
338
396
  * ✅ 找到金额最大的钱包索引(和 core.ts 逻辑一致)
@@ -766,7 +824,9 @@ export async function directV3BatchBuy(params) {
766
824
  getGasPrice(provider, config),
767
825
  // ERC20 报价(V3 买入用 V3 报价)
768
826
  (!useNative && baseProfitWei > 0n && quoteToken)
769
- ? getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee)
827
+ ? (chain.toUpperCase() === 'XLAYER'
828
+ ? quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: quoteToken, amountIn: baseProfitWei, fee })
829
+ : getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee))
770
830
  : Promise.resolve(baseProfitWei)
771
831
  ]);
772
832
  const profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
@@ -884,7 +944,9 @@ export async function directV3BatchSell(params) {
884
944
  try {
885
945
  if (useNativeOutput) {
886
946
  // 卖出代币 → 得到 BNB:先获取 V3 报价,再计算利润
887
- const estimatedBNBOut = await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
947
+ const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
948
+ ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
949
+ : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
888
950
  console.log(`[V3 Sell Profit] totalSellAmount: ${totalSellAmount}, estimatedBNBOut: ${estimatedBNBOut}, estimatedBNB: ${ethers.formatEther(estimatedBNBOut)}`);
889
951
  if (estimatedBNBOut <= 0n)
890
952
  return 0n;
@@ -894,7 +956,9 @@ export async function directV3BatchSell(params) {
894
956
  }
895
957
  else if (quoteToken) {
896
958
  // 卖出代币 → 得到 ERC20:先获取 V3 报价,再计算利润
897
- const estimatedBNBOut = await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
959
+ const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
960
+ ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
961
+ : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
898
962
  if (estimatedBNBOut <= 0n)
899
963
  return 0n;
900
964
  const profit = calculateProfitAmount(estimatedBNBOut);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.16",
3
+ "version": "1.5.17",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",