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