four-flap-meme-sdk 1.2.21 → 1.2.22

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.
@@ -345,12 +345,15 @@ export async function sweepWithBundleMerkle(params) {
345
345
  const txType = getTxType(config);
346
346
  const nonceManager = new NonceManager(provider);
347
347
  if (isNative) {
348
- // ✅ 原生币:批量查询余额,扣除利润
348
+ // ✅ 原生币:批量查询余额,统一扣除利润
349
349
  const balances = await _batchGetBalances(provider, addresses);
350
- const extraTxPerWallet = extractProfit ? 1 : 0; // 每个钱包需要额外1笔利润转账
351
350
  const gasCostBase = nativeGasLimit * gasPrice; // 基础 gas 费
352
- const gasCost = gasCostBase * BigInt(1 + extraTxPerWallet); // gas 费(含利润转账)
353
- const txPromises = wallets.map(async (w, i) => {
351
+ const gasCost = gasCostBase; // 每个钱包只需要主转账的 gas
352
+ // 第一步:计算所有钱包的归集金额和利润,找出归集金额最大的钱包
353
+ const sweepAmounts = [];
354
+ let maxSweepIndex = -1;
355
+ let maxSweepAmount = 0n;
356
+ for (let i = 0; i < wallets.length; i++) {
354
357
  const bal = balances[i];
355
358
  let toSend = 0n;
356
359
  const ratioForI = (() => {
@@ -378,63 +381,74 @@ export async function sweepWithBundleMerkle(params) {
378
381
  if (!skipIfInsufficient || bal >= need)
379
382
  toSend = amt;
380
383
  }
381
- if (toSend <= 0n)
382
- return [];
384
+ sweepAmounts.push(toSend);
383
385
  totalAmountBeforeProfit += toSend;
384
- // ✅ 计算利润并扣除
386
+ // 找出归集金额最大的钱包
387
+ if (toSend > maxSweepAmount) {
388
+ maxSweepAmount = toSend;
389
+ maxSweepIndex = i;
390
+ }
391
+ // 累计总利润
392
+ if (extractProfit && toSend > 0n) {
393
+ const { profit } = calculateProfit(toSend, config);
394
+ totalProfit += profit;
395
+ }
396
+ }
397
+ // ✅ 第二步:生成归集交易(扣除利润后的金额)
398
+ const txPromises = wallets.map(async (w, i) => {
399
+ const toSend = sweepAmounts[i];
400
+ if (toSend <= 0n)
401
+ return null;
385
402
  let actualToSend = toSend;
386
- let profitAmount = 0n;
387
403
  if (extractProfit) {
388
- const { profit, remaining } = calculateProfit(toSend, config);
404
+ const { remaining } = calculateProfit(toSend, config);
389
405
  actualToSend = remaining;
390
- profitAmount = profit;
391
- totalProfit += profit;
392
406
  }
393
407
  const nonce = await nonceManager.getNextNonce(w);
394
- const nonces = [nonce, nonce + 1];
395
- const txs = [];
396
- // 归集到target
397
408
  const mainTx = await w.signTransaction({
398
409
  to: target,
399
- value: actualToSend, // ✅ 扣除利润后的金额
400
- nonce: nonces[0],
410
+ value: actualToSend,
411
+ nonce,
401
412
  gasPrice,
402
413
  gasLimit: nativeGasLimit,
403
414
  chainId: chainIdNum,
404
415
  type: txType
405
416
  });
406
- txs.push(mainTx);
407
- // ✅ 利润转账
408
- if (extractProfit && profitAmount > 0n) {
409
- const profitTx = await w.signTransaction({
410
- to: config.profitRecipient,
411
- value: profitAmount,
412
- nonce: nonces[1],
413
- gasPrice,
414
- gasLimit: 21000n,
415
- chainId: chainIdNum,
416
- type: txType
417
- });
418
- txs.push(profitTx);
419
- }
420
- return txs;
417
+ return mainTx;
421
418
  });
422
- const allTxs = (await Promise.all(txPromises)).flat().filter(tx => tx !== null);
419
+ const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
423
420
  signedTxs.push(...allTxs);
421
+ // ✅ 第三步:由归集金额最大的钱包统一支付所有利润
422
+ if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0) {
423
+ const payerWallet = wallets[maxSweepIndex];
424
+ const profitNonce = await nonceManager.getNextNonce(payerWallet);
425
+ const profitTx = await payerWallet.signTransaction({
426
+ to: config.profitRecipient,
427
+ value: totalProfit,
428
+ nonce: profitNonce,
429
+ gasPrice,
430
+ gasLimit: 21000n,
431
+ chainId: chainIdNum,
432
+ type: txType
433
+ });
434
+ signedTxs.push(profitTx);
435
+ }
424
436
  }
425
437
  else {
426
- // ✅ ERC20:批量查询余额,扣除利润
438
+ // ✅ ERC20:批量查询余额,统一扣除利润
427
439
  const [decimals, balances, bnbBalances] = await Promise.all([
428
440
  Promise.resolve(tokenDecimals ?? (await _getErc20DecimalsMerkle(provider, tokenAddress))),
429
441
  _batchGetBalances(provider, addresses, tokenAddress),
430
442
  config.checkBnbForErc20NoHop ? _batchGetBalances(provider, addresses) : Promise.resolve([])
431
443
  ]);
432
444
  const iface = new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
433
- const extraTxPerWallet = extractProfit ? 1 : 0; // 每个钱包需要额外1笔利润转账
434
- const txPromises = wallets.map(async (w, i) => {
445
+ // 第一步:计算所有钱包的归集金额和利润,找出归集金额最大的钱包
446
+ const sweepAmounts = [];
447
+ let maxSweepIndex = -1;
448
+ let maxSweepAmount = 0n;
449
+ for (let i = 0; i < wallets.length; i++) {
435
450
  const bal = balances[i];
436
451
  let toSend = 0n;
437
- // 逐地址优先级:sources[i] > ratios[i]/amounts[i] > 全局 ratio/amount
438
452
  const ratioForI = (() => {
439
453
  if (sources && sources[i] && sources[i].ratioPct !== undefined)
440
454
  return clamp(sources[i].ratioPct);
@@ -455,60 +469,75 @@ export async function sweepWithBundleMerkle(params) {
455
469
  else if (amountStrForI && amountStrForI.trim().length > 0) {
456
470
  toSend = ethers.parseUnits(amountStrForI, decimals);
457
471
  }
458
- if (toSend <= 0n || (skipIfInsufficient && bal < toSend))
459
- return [];
460
- // ✅ 检查 BNB 余额(含利润转账的 gas)
461
- const totalGasNeeded = finalGasLimit * gasPrice * BigInt(1 + extraTxPerWallet);
472
+ if (toSend <= 0n || (skipIfInsufficient && bal < toSend)) {
473
+ sweepAmounts.push(0n);
474
+ continue;
475
+ }
476
+ // ✅ 检查 BNB 余额(只需主转账的 gas)
477
+ const totalGasNeeded = finalGasLimit * gasPrice;
462
478
  if (config.checkBnbForErc20NoHop) {
463
479
  const bnb = bnbBalances[i] ?? 0n;
464
- if (skipIfInsufficient && bnb < totalGasNeeded)
465
- return [];
480
+ if (skipIfInsufficient && bnb < totalGasNeeded) {
481
+ sweepAmounts.push(0n);
482
+ continue;
483
+ }
466
484
  }
485
+ sweepAmounts.push(toSend);
467
486
  totalAmountBeforeProfit += toSend;
468
- // ✅ 计算利润并扣除
487
+ // 找出归集金额最大的钱包
488
+ if (toSend > maxSweepAmount) {
489
+ maxSweepAmount = toSend;
490
+ maxSweepIndex = i;
491
+ }
492
+ // 累计总利润
493
+ if (extractProfit && toSend > 0n) {
494
+ const { profit } = calculateProfit(toSend, config);
495
+ totalProfit += profit;
496
+ }
497
+ }
498
+ // ✅ 第二步:生成归集交易(扣除利润后的金额)
499
+ const txPromises = wallets.map(async (w, i) => {
500
+ const toSend = sweepAmounts[i];
501
+ if (toSend <= 0n)
502
+ return null;
469
503
  let actualToSend = toSend;
470
- let profitAmount = 0n;
471
504
  if (extractProfit) {
472
- const { profit, remaining } = calculateProfit(toSend, config);
505
+ const { remaining } = calculateProfit(toSend, config);
473
506
  actualToSend = remaining;
474
- profitAmount = profit;
475
- totalProfit += profit;
476
507
  }
477
508
  const nonce = await nonceManager.getNextNonce(w);
478
- const nonces = [nonce, nonce + 1];
479
- const txs = [];
480
- // 归集到target
481
- const data = iface.encodeFunctionData('transfer', [target, actualToSend]); // ✅ 扣除利润后的金额
509
+ const data = iface.encodeFunctionData('transfer', [target, actualToSend]);
482
510
  const mainTx = await w.signTransaction({
483
511
  to: tokenAddress,
484
512
  data,
485
513
  value: 0n,
486
- nonce: nonces[0],
514
+ nonce,
487
515
  gasPrice,
488
516
  gasLimit: finalGasLimit,
489
517
  chainId: chainIdNum,
490
518
  type: txType
491
519
  });
492
- txs.push(mainTx);
493
- // ✅ 利润转账
494
- if (extractProfit && profitAmount > 0n) {
495
- const profitData = iface.encodeFunctionData('transfer', [config.profitRecipient, profitAmount]);
496
- const profitTx = await w.signTransaction({
497
- to: tokenAddress,
498
- data: profitData,
499
- value: 0n,
500
- nonce: nonces[1],
501
- gasPrice,
502
- gasLimit: 60000n,
503
- chainId: chainIdNum,
504
- type: txType
505
- });
506
- txs.push(profitTx);
507
- }
508
- return txs;
520
+ return mainTx;
509
521
  });
510
- const allTxs = (await Promise.all(txPromises)).flat().filter(tx => tx !== null);
522
+ const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
511
523
  signedTxs.push(...allTxs);
524
+ // ✅ 第三步:由归集金额最大的钱包统一支付所有利润
525
+ if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0) {
526
+ const payerWallet = wallets[maxSweepIndex];
527
+ const profitNonce = await nonceManager.getNextNonce(payerWallet);
528
+ const profitData = iface.encodeFunctionData('transfer', [config.profitRecipient, totalProfit]);
529
+ const profitTx = await payerWallet.signTransaction({
530
+ to: tokenAddress,
531
+ data: profitData,
532
+ value: 0n,
533
+ nonce: profitNonce,
534
+ gasPrice,
535
+ gasLimit: 60000n,
536
+ chainId: chainIdNum,
537
+ type: txType
538
+ });
539
+ signedTxs.push(profitTx);
540
+ }
512
541
  }
513
542
  }
514
543
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.2.21",
3
+ "version": "1.2.22",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",