four-flap-meme-sdk 1.1.94 → 1.1.96

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,56 @@ 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
+ // ⚠️ Four.meme 内盘代币通过 TokenManager bonding curve 定价,不在 PancakeSwap 上
326
+ // ✅ 使用用户提供的 minOutputAmounts,或默认为 0(不限制最小输出)
326
327
  let minOuts;
328
+ let quotedOutputs = [];
327
329
  if (minOutputAmounts && minOutputAmounts.length === sellers.length) {
330
+ // 用户提供了 minOutputAmounts,优先使用
328
331
  minOuts = minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
332
+ quotedOutputs = minOuts.map(m => m * 100n / 95n); // 反推报价(用于利润计算)
333
+ console.log(`📝 使用用户提供的 minOutputAmounts`);
334
+ console.log(`💰 minOutputAmounts:`);
335
+ minOuts.forEach((minOut, i) => {
336
+ console.log(` 钱包 ${i}: ${ethers.formatEther(minOut)} BNB`);
337
+ });
329
338
  }
330
339
  else {
340
+ // Four.meme 内盘代币:默认 minOutputAmount = 0(不限制),不提取利润
331
341
  minOuts = new Array(sellers.length).fill(0n);
342
+ quotedOutputs = new Array(sellers.length).fill(0n);
343
+ console.log(`📝 Four.meme 内盘代币:minOutputAmount = 0(不限制最小输出)`);
344
+ console.log(`⚠️ 无法自动计算卖出收益,建议手动传入 minOutputAmounts 以提取利润`);
332
345
  }
333
- // ✅ Step 1: 使用 Multicall3 批量检查授权状态
346
+ console.log('');
347
+ // ✅ Step 1: 检查代币余额和授权状态
334
348
  const ERC20_ABI = [
335
349
  'function approve(address spender, uint256 amount) returns (bool)',
336
- 'function allowance(address owner, address spender) view returns (uint256)'
350
+ 'function allowance(address owner, address spender) view returns (uint256)',
351
+ 'function balanceOf(address owner) view returns (uint256)'
337
352
  ];
338
- console.log('🔍 使用 Multicall3 批量检查授权状态...');
353
+ // 检查代币余额
354
+ console.log('🔍 检查代币余额...');
355
+ const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
356
+ const balances = await Promise.all(sellers.map(w => tokenContract.balanceOf(w.address)));
357
+ for (let i = 0; i < sellers.length; i++) {
358
+ const balance = balances[i];
359
+ const sellAmount = amountsWei[i];
360
+ console.log(` 钱包 ${i}: 余额 ${ethers.formatUnits(balance, 18)}, 卖出 ${ethers.formatUnits(sellAmount, 18)}`);
361
+ if (balance < sellAmount) {
362
+ throw new Error(`钱包 ${i} (${sellers[i].address.slice(0, 8)}...) 代币余额不足:需要 ${ethers.formatUnits(sellAmount, 18)},实际 ${ethers.formatUnits(balance, 18)}`);
363
+ }
364
+ }
365
+ console.log('\n🔍 使用 Multicall3 批量检查授权状态...');
339
366
  const allowances = await batchCheckAllowances(provider, tokenAddress, sellers.map(w => w.address), tmAddr);
340
367
  // 找出需要授权的钱包索引
341
- // 使用 MaxUint256 的一半作为阈值,确保能处理超大供应量代币
368
+ // 检查授权额度是否足够卖出
342
369
  const needApprovalIndexes = [];
343
- const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
344
370
  for (let i = 0; i < sellers.length; i++) {
345
- if (allowances[i] < APPROVAL_THRESHOLD) {
371
+ // 检查授权额度是否 >= 卖出数量
372
+ if (allowances[i] < amountsWei[i]) {
346
373
  needApprovalIndexes.push(i);
374
+ console.log(` ⚠️ 钱包 ${i}: 授权不足 (${ethers.formatUnits(allowances[i], 18)} < ${ethers.formatUnits(amountsWei[i], 18)})`);
347
375
  }
348
376
  }
349
377
  console.log(` - 总钱包数: ${sellers.length}`);
@@ -376,14 +404,17 @@ export async function batchSellWithBundleMerkle(params) {
376
404
  type: getTxType(config)
377
405
  })));
378
406
  signedTxs.push(...signedList);
379
- // ✅ 基于 minFunds 为每个钱包添加利润转账
407
+ // ✅ 基于报价金额为每个钱包添加利润转账
380
408
  const extractProfit = shouldExtractProfit(config);
381
- if (extractProfit && minOuts.length > 0) {
382
- // 为每个钱包添加利润转账(如果 minOut > 0)
409
+ if (extractProfit && quotedOutputs.length > 0) {
410
+ console.log(`💰 提取利润交易...`);
411
+ let totalProfitExtracted = 0n;
412
+ // 为每个钱包添加利润转账(基于完整报价金额,而非 minOut)
383
413
  for (let i = 0; i < sellers.length; i++) {
384
- if (minOuts[i] > 0n) { // ⚠️ 保留这个判断:只对设置了 minOut 的钱包提取利润
385
- const { profit } = calculateProfit(minOuts[i], config);
414
+ if (quotedOutputs[i] > 0n) { // 只对报价成功的交易提取利润
415
+ const { profit } = calculateProfit(quotedOutputs[i], config);
386
416
  if (profit > 0n) {
417
+ console.log(` ✅ 钱包 ${i}: 从 ${ethers.formatEther(quotedOutputs[i])} BNB 中提取 ${ethers.formatEther(profit)} BNB (${config.profitRateBps / 100}%)`);
387
418
  const profitNonce = await nonceManager.getNextNonce(sellers[i]);
388
419
  const profitTx = await sellers[i].signTransaction({
389
420
  to: config.profitRecipient,
@@ -395,9 +426,11 @@ export async function batchSellWithBundleMerkle(params) {
395
426
  type: getTxType(config)
396
427
  });
397
428
  signedTxs.push(profitTx);
429
+ totalProfitExtracted += profit;
398
430
  }
399
431
  }
400
432
  }
433
+ console.log(` 💵 总利润: ${ethers.formatEther(totalProfitExtracted)} BNB → ${config.profitRecipient}\n`);
401
434
  }
402
435
  // ✅ 清理临时 nonce 缓存
403
436
  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.96",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",