four-flap-meme-sdk 1.1.94 → 1.1.95

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.
@@ -322,28 +322,73 @@ export async function batchSellWithBundleMerkle(params) {
322
322
  const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
323
323
  const sellers = privateKeys.map((k) => new Wallet(k, provider));
324
324
  const amountsWei = sellAmounts.map((a) => ethers.parseUnits(a, 18));
325
- // ✅ 解析 minOutputAmounts
325
+ // ✅ 自动获取报价以计算预期收益和利润(使用 PancakeSwap Router)
326
+ const PANCAKE_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
327
+ const ROUTER_ABI = [
328
+ 'function getAmountsOut(uint amountIn, address[] memory path) view returns (uint[] memory amounts)'
329
+ ];
330
+ const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
331
+ const router = new ethers.Contract(PANCAKE_ROUTER, ROUTER_ABI, provider);
332
+ // 并行获取所有报价
333
+ console.log(`📊 开始获取 ${amountsWei.length} 个卖单的报价...`);
334
+ const quotedOutputs = await Promise.all(amountsWei.map(async (amount, index) => {
335
+ try {
336
+ const path = [tokenAddress, WBNB];
337
+ const amounts = await router.getAmountsOut(amount, path);
338
+ const bnbAmount = amounts[1];
339
+ console.log(` ✅ 钱包 ${index}: 卖出 ${ethers.formatUnits(amount, 18)} 代币 → 预计获得 ${ethers.formatEther(bnbAmount)} BNB`);
340
+ return bnbAmount; // 返回 BNB 数量
341
+ }
342
+ catch (error) {
343
+ console.log(` ❌ 钱包 ${index}: 报价失败 - ${error}`);
344
+ return 0n;
345
+ }
346
+ }));
347
+ // ✅ 使用报价结果或用户提供的 minOutputAmounts
326
348
  let minOuts;
327
349
  if (minOutputAmounts && minOutputAmounts.length === sellers.length) {
350
+ // 用户提供了 minOutputAmounts,优先使用
328
351
  minOuts = minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
352
+ console.log(`📝 使用用户提供的 minOutputAmounts`);
329
353
  }
330
354
  else {
331
- minOuts = new Array(sellers.length).fill(0n);
355
+ // 使用报价结果作为 minOutputAmount(保守起见,使用 95% 的报价金额)
356
+ minOuts = quotedOutputs.map(quoted => quoted * 95n / 100n);
357
+ console.log(`📝 使用自动报价的 95% 作为 minOutputAmount(5%滑点保护)`);
332
358
  }
333
- // Step 1: 使用 Multicall3 批量检查授权状态
359
+ console.log(`💰 最终 minOutputAmounts:`);
360
+ minOuts.forEach((minOut, i) => {
361
+ console.log(` 钱包 ${i}: ${ethers.formatEther(minOut)} BNB`);
362
+ });
363
+ console.log('');
364
+ // ✅ Step 1: 检查代币余额和授权状态
334
365
  const ERC20_ABI = [
335
366
  'function approve(address spender, uint256 amount) returns (bool)',
336
- 'function allowance(address owner, address spender) view returns (uint256)'
367
+ 'function allowance(address owner, address spender) view returns (uint256)',
368
+ 'function balanceOf(address owner) view returns (uint256)'
337
369
  ];
338
- console.log('🔍 使用 Multicall3 批量检查授权状态...');
370
+ // 检查代币余额
371
+ console.log('🔍 检查代币余额...');
372
+ const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
373
+ const balances = await Promise.all(sellers.map(w => tokenContract.balanceOf(w.address)));
374
+ for (let i = 0; i < sellers.length; i++) {
375
+ const balance = balances[i];
376
+ const sellAmount = amountsWei[i];
377
+ console.log(` 钱包 ${i}: 余额 ${ethers.formatUnits(balance, 18)}, 卖出 ${ethers.formatUnits(sellAmount, 18)}`);
378
+ if (balance < sellAmount) {
379
+ throw new Error(`钱包 ${i} (${sellers[i].address.slice(0, 8)}...) 代币余额不足:需要 ${ethers.formatUnits(sellAmount, 18)},实际 ${ethers.formatUnits(balance, 18)}`);
380
+ }
381
+ }
382
+ console.log('\n🔍 使用 Multicall3 批量检查授权状态...');
339
383
  const allowances = await batchCheckAllowances(provider, tokenAddress, sellers.map(w => w.address), tmAddr);
340
384
  // 找出需要授权的钱包索引
341
- // 使用 MaxUint256 的一半作为阈值,确保能处理超大供应量代币
385
+ // 检查授权额度是否足够卖出
342
386
  const needApprovalIndexes = [];
343
- const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
344
387
  for (let i = 0; i < sellers.length; i++) {
345
- if (allowances[i] < APPROVAL_THRESHOLD) {
388
+ // 检查授权额度是否 >= 卖出数量
389
+ if (allowances[i] < amountsWei[i]) {
346
390
  needApprovalIndexes.push(i);
391
+ console.log(` ⚠️ 钱包 ${i}: 授权不足 (${ethers.formatUnits(allowances[i], 18)} < ${ethers.formatUnits(amountsWei[i], 18)})`);
347
392
  }
348
393
  }
349
394
  console.log(` - 总钱包数: ${sellers.length}`);
@@ -376,14 +421,17 @@ export async function batchSellWithBundleMerkle(params) {
376
421
  type: getTxType(config)
377
422
  })));
378
423
  signedTxs.push(...signedList);
379
- // ✅ 基于 minFunds 为每个钱包添加利润转账
424
+ // ✅ 基于报价金额为每个钱包添加利润转账
380
425
  const extractProfit = shouldExtractProfit(config);
381
- if (extractProfit && minOuts.length > 0) {
382
- // 为每个钱包添加利润转账(如果 minOut > 0)
426
+ if (extractProfit && quotedOutputs.length > 0) {
427
+ console.log(`💰 提取利润交易...`);
428
+ let totalProfitExtracted = 0n;
429
+ // 为每个钱包添加利润转账(基于完整报价金额,而非 minOut)
383
430
  for (let i = 0; i < sellers.length; i++) {
384
- if (minOuts[i] > 0n) { // ⚠️ 保留这个判断:只对设置了 minOut 的钱包提取利润
385
- const { profit } = calculateProfit(minOuts[i], config);
431
+ if (quotedOutputs[i] > 0n) { // 只对报价成功的交易提取利润
432
+ const { profit } = calculateProfit(quotedOutputs[i], config);
386
433
  if (profit > 0n) {
434
+ console.log(` ✅ 钱包 ${i}: 从 ${ethers.formatEther(quotedOutputs[i])} BNB 中提取 ${ethers.formatEther(profit)} BNB (${config.profitRateBps / 100}%)`);
387
435
  const profitNonce = await nonceManager.getNextNonce(sellers[i]);
388
436
  const profitTx = await sellers[i].signTransaction({
389
437
  to: config.profitRecipient,
@@ -395,9 +443,11 @@ export async function batchSellWithBundleMerkle(params) {
395
443
  type: getTxType(config)
396
444
  });
397
445
  signedTxs.push(profitTx);
446
+ totalProfitExtracted += profit;
398
447
  }
399
448
  }
400
449
  }
450
+ console.log(` 💵 总利润: ${ethers.formatEther(totalProfitExtracted)} BNB → ${config.profitRecipient}\n`);
401
451
  }
402
452
  // ✅ 清理临时 nonce 缓存
403
453
  nonceManager.clearTemp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.1.94",
3
+ "version": "1.1.95",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",