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
|
|
353
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
410
|
+
value: actualToSend,
|
|
411
|
+
nonce,
|
|
401
412
|
gasPrice,
|
|
402
413
|
gasLimit: nativeGasLimit,
|
|
403
414
|
chainId: chainIdNum,
|
|
404
415
|
type: txType
|
|
405
416
|
});
|
|
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;
|
|
417
|
+
return mainTx;
|
|
421
418
|
});
|
|
422
|
-
const allTxs = (await Promise.all(txPromises)).
|
|
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
|
-
|
|
434
|
-
const
|
|
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
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
|
514
|
+
nonce,
|
|
487
515
|
gasPrice,
|
|
488
516
|
gasLimit: finalGasLimit,
|
|
489
517
|
chainId: chainIdNum,
|
|
490
518
|
type: txType
|
|
491
519
|
});
|
|
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;
|
|
520
|
+
return mainTx;
|
|
509
521
|
});
|
|
510
|
-
const allTxs = (await Promise.all(txPromises)).
|
|
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 {
|