four-flap-meme-sdk 1.4.39 → 1.4.40
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.
- package/dist/contracts/tm-bundle-merkle/core.js +36 -28
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +25 -19
- package/dist/contracts/tm-bundle-merkle/private.js +47 -37
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +17 -19
- package/dist/contracts/tm-bundle-merkle/swap.js +51 -52
- package/dist/contracts/tm-bundle-merkle/utils.js +70 -58
- package/dist/contracts/tm-bundle.js +35 -25
- package/dist/dex/direct-router.js +37 -34
- package/dist/flap/portal-bundle-merkle/core.js +34 -28
- package/dist/flap/portal-bundle-merkle/pancake-proxy.js +25 -17
- package/dist/flap/portal-bundle-merkle/private.js +73 -53
- package/dist/flap/portal-bundle-merkle/swap-buy-first.js +26 -20
- package/dist/flap/portal-bundle-merkle/swap.js +60 -55
- package/dist/flap/portal-bundle-merkle/utils.js +69 -44
- package/dist/pancake/bundle-buy-first.js +27 -20
- package/dist/pancake/bundle-swap.js +56 -56
- package/dist/utils/bundle-helpers.d.ts +38 -0
- package/dist/utils/bundle-helpers.js +85 -1
- package/dist/utils/private-sale.js +22 -19
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ethers, Wallet } from 'ethers';
|
|
2
2
|
import { MerkleClient } from '../../clients/merkle.js';
|
|
3
|
-
import { getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
3
|
+
import { getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
|
|
4
4
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
5
5
|
import { ZERO_ADDRESS } from '../../utils/constants.js';
|
|
6
6
|
import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
|
|
@@ -67,20 +67,23 @@ export async function flapPrivateBuyMerkle(params) {
|
|
|
67
67
|
type: txType,
|
|
68
68
|
value: actualAmountWei
|
|
69
69
|
}));
|
|
70
|
-
//
|
|
70
|
+
// ✅ 并行签名完成后按顺序返回
|
|
71
|
+
const signedTxs = await Promise.all(signPromises);
|
|
72
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
71
73
|
if (needProfitTx && profitNonce !== undefined) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
75
|
+
provider,
|
|
76
|
+
payerWallet: wallet,
|
|
77
|
+
profitAmount: profitWei,
|
|
78
|
+
profitRecipient: getProfitRecipient(),
|
|
79
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
76
80
|
gasPrice,
|
|
77
|
-
gasLimit: 21000n,
|
|
78
81
|
chainId,
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
txType,
|
|
83
|
+
startNonce: profitNonce
|
|
84
|
+
});
|
|
85
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
81
86
|
}
|
|
82
|
-
// ✅ 并行签名完成后按顺序返回
|
|
83
|
-
const signedTxs = await Promise.all(signPromises);
|
|
84
87
|
return { signedTransactions: signedTxs };
|
|
85
88
|
}
|
|
86
89
|
/**
|
|
@@ -146,20 +149,23 @@ export async function flapPrivateSellMerkle(params) {
|
|
|
146
149
|
chainId,
|
|
147
150
|
type: txType
|
|
148
151
|
}));
|
|
149
|
-
//
|
|
152
|
+
// ✅ 并行签名完成后按顺序返回
|
|
153
|
+
const signedTxs = await Promise.all(signPromises);
|
|
154
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
150
155
|
if (needProfitTx && profitNonce !== undefined) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
157
|
+
provider,
|
|
158
|
+
payerWallet: wallet,
|
|
159
|
+
profitAmount: profitWei,
|
|
160
|
+
profitRecipient: getProfitRecipient(),
|
|
161
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
155
162
|
gasPrice,
|
|
156
|
-
gasLimit: 21000n,
|
|
157
163
|
chainId,
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
txType,
|
|
165
|
+
startNonce: profitNonce
|
|
166
|
+
});
|
|
167
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
160
168
|
}
|
|
161
|
-
// ✅ 并行签名完成后按顺序返回
|
|
162
|
-
const signedTxs = await Promise.all(signPromises);
|
|
163
169
|
return { signedTransactions: signedTxs };
|
|
164
170
|
}
|
|
165
171
|
/**
|
|
@@ -241,18 +247,20 @@ export async function flapBatchPrivateBuyMerkle(params) {
|
|
|
241
247
|
values: actualAmountsWei
|
|
242
248
|
});
|
|
243
249
|
signedTxs.push(...signedList);
|
|
244
|
-
// ✅
|
|
250
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
245
251
|
if (needProfitTx && profitNonce !== undefined && maxFundsIndex >= 0) {
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
253
|
+
provider,
|
|
254
|
+
payerWallet: wallets[maxFundsIndex],
|
|
255
|
+
profitAmount: totalProfit,
|
|
256
|
+
profitRecipient: getProfitRecipient(),
|
|
257
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
250
258
|
gasPrice,
|
|
251
|
-
gasLimit: 21000n,
|
|
252
259
|
chainId,
|
|
253
|
-
|
|
260
|
+
txType: getTxType(config),
|
|
261
|
+
startNonce: profitNonce
|
|
254
262
|
});
|
|
255
|
-
signedTxs.push(
|
|
263
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
256
264
|
}
|
|
257
265
|
return { signedTransactions: signedTxs };
|
|
258
266
|
}
|
|
@@ -337,18 +345,20 @@ export async function flapBatchPrivateSellMerkle(params) {
|
|
|
337
345
|
config
|
|
338
346
|
});
|
|
339
347
|
signedTxs.push(...signedList);
|
|
340
|
-
// ✅
|
|
348
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
341
349
|
if (needProfitTx && profitNonce !== undefined && maxRevenueIndex >= 0) {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
350
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
351
|
+
provider,
|
|
352
|
+
payerWallet: wallets[maxRevenueIndex],
|
|
353
|
+
profitAmount: totalProfit,
|
|
354
|
+
profitRecipient: getProfitRecipient(),
|
|
355
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
346
356
|
gasPrice,
|
|
347
|
-
gasLimit: 21000n,
|
|
348
357
|
chainId,
|
|
349
|
-
|
|
358
|
+
txType: getTxType(config),
|
|
359
|
+
startNonce: profitNonce
|
|
350
360
|
});
|
|
351
|
-
signedTxs.push(
|
|
361
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
352
362
|
}
|
|
353
363
|
return { signedTransactions: signedTxs };
|
|
354
364
|
}
|
|
@@ -395,20 +405,25 @@ function resolveGasLimit(multiplier, defaultGas = DEFAULT_GAS_LIMIT) {
|
|
|
395
405
|
const factor = multiplier ?? 1.0;
|
|
396
406
|
return BigInt(Math.ceil(defaultGas * factor));
|
|
397
407
|
}
|
|
398
|
-
|
|
408
|
+
/**
|
|
409
|
+
* 追加利润多跳转账交易(强制 2 跳中转)
|
|
410
|
+
*/
|
|
411
|
+
async function appendSingleProfitTransfer({ extractProfit, profitWei, wallet, baseNonce, provider, gasPrice, chainId, config, signedTxs }) {
|
|
399
412
|
if (!extractProfit || profitWei === 0n) {
|
|
400
413
|
return;
|
|
401
414
|
}
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
415
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
416
|
+
provider,
|
|
417
|
+
payerWallet: wallet,
|
|
418
|
+
profitAmount: profitWei,
|
|
419
|
+
profitRecipient: getProfitRecipient(),
|
|
420
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
406
421
|
gasPrice,
|
|
407
|
-
gasLimit: 21000n,
|
|
408
422
|
chainId,
|
|
409
|
-
|
|
423
|
+
txType: getTxType(config),
|
|
424
|
+
startNonce: baseNonce + 1
|
|
410
425
|
});
|
|
411
|
-
signedTxs.push(
|
|
426
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
412
427
|
}
|
|
413
428
|
async function resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutputAmount) {
|
|
414
429
|
if (minOutputAmount !== undefined) {
|
|
@@ -438,7 +453,10 @@ async function resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutp
|
|
|
438
453
|
};
|
|
439
454
|
}
|
|
440
455
|
}
|
|
441
|
-
|
|
456
|
+
/**
|
|
457
|
+
* 追加卖出利润多跳转账交易(强制 2 跳中转)
|
|
458
|
+
*/
|
|
459
|
+
async function appendSingleSellProfitTransfer({ extractProfit, quotedOutput, wallet, baseNonce, provider, gasPrice, chainId, config, signedTxs }) {
|
|
442
460
|
if (!extractProfit || quotedOutput <= 0n) {
|
|
443
461
|
return;
|
|
444
462
|
}
|
|
@@ -446,16 +464,18 @@ async function appendSingleSellProfitTransfer({ extractProfit, quotedOutput, wal
|
|
|
446
464
|
if (profit === 0n) {
|
|
447
465
|
return;
|
|
448
466
|
}
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
467
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
468
|
+
provider,
|
|
469
|
+
payerWallet: wallet,
|
|
470
|
+
profitAmount: profit,
|
|
471
|
+
profitRecipient: getProfitRecipient(),
|
|
472
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
453
473
|
gasPrice,
|
|
454
|
-
gasLimit: 21000n,
|
|
455
474
|
chainId,
|
|
456
|
-
|
|
475
|
+
txType: getTxType(config),
|
|
476
|
+
startNonce: baseNonce + 1
|
|
457
477
|
});
|
|
458
|
-
signedTxs.push(
|
|
478
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
459
479
|
}
|
|
460
480
|
function resolveBatchMinOutputs(minOutputAmounts, walletCount) {
|
|
461
481
|
if (minOutputAmounts && minOutputAmounts.length === walletCount) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行
|
|
5
5
|
*/
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
|
-
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
7
|
+
import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
|
|
8
8
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
9
9
|
import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
|
|
10
10
|
import { ERC20_BALANCE_ABI, V2_ROUTER_QUOTE_ABI } from '../../abis/common.js';
|
|
@@ -202,23 +202,24 @@ export async function flapBundleBuyFirstMerkle(params) {
|
|
|
202
202
|
buyer.signTransaction(buyTx),
|
|
203
203
|
seller.signTransaction(sellTx)
|
|
204
204
|
]);
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
nonceManager.clearTemp();
|
|
206
|
+
// ✅ 组装顺序:贿赂 → 买入 → 卖出
|
|
207
|
+
const allTransactions = [];
|
|
208
|
+
if (bribeTx)
|
|
209
|
+
allTransactions.push(bribeTx);
|
|
210
|
+
allTransactions.push(signedBuy, signedSell);
|
|
211
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
212
|
+
const profitTxs = await buildProfitTransaction({
|
|
213
|
+
provider: chainContext.provider,
|
|
207
214
|
seller,
|
|
208
|
-
profitAmount: nativeProfitAmount,
|
|
215
|
+
profitAmount: nativeProfitAmount,
|
|
209
216
|
profitNonce: noncePlan.profitNonce,
|
|
210
217
|
gasPrice,
|
|
211
218
|
chainId: chainContext.chainId,
|
|
212
219
|
txType
|
|
213
220
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const allTransactions = [];
|
|
217
|
-
if (bribeTx)
|
|
218
|
-
allTransactions.push(bribeTx);
|
|
219
|
-
allTransactions.push(signedBuy, signedSell);
|
|
220
|
-
if (profitTx)
|
|
221
|
-
allTransactions.push(profitTx);
|
|
221
|
+
if (profitTxs)
|
|
222
|
+
allTransactions.push(...profitTxs);
|
|
222
223
|
return {
|
|
223
224
|
signedTransactions: allTransactions,
|
|
224
225
|
metadata: {
|
|
@@ -396,20 +397,25 @@ function buildTransactionRequest(unsigned, { from, nonce, gasLimit, gasPrice, pr
|
|
|
396
397
|
}
|
|
397
398
|
return tx;
|
|
398
399
|
}
|
|
399
|
-
|
|
400
|
+
/**
|
|
401
|
+
* 构建利润多跳转账交易(强制 2 跳中转)
|
|
402
|
+
*/
|
|
403
|
+
async function buildProfitTransaction({ provider, seller, profitAmount, profitNonce, gasPrice, chainId, txType }) {
|
|
400
404
|
if (profitNonce === undefined || profitAmount === 0n) {
|
|
401
405
|
return null;
|
|
402
406
|
}
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
408
|
+
provider,
|
|
409
|
+
payerWallet: seller,
|
|
410
|
+
profitAmount,
|
|
411
|
+
profitRecipient: getProfitRecipient(),
|
|
412
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
407
413
|
gasPrice,
|
|
408
|
-
gasLimit: 21000n,
|
|
409
414
|
chainId,
|
|
410
|
-
|
|
415
|
+
txType,
|
|
416
|
+
startNonce: profitNonce
|
|
411
417
|
});
|
|
412
|
-
return
|
|
418
|
+
return profitHopResult.signedTransactions;
|
|
413
419
|
}
|
|
414
420
|
function countTruthy(values) {
|
|
415
421
|
return values.filter(Boolean).length;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
7
|
import { calculateSellAmount } from '../../utils/swap-helpers.js';
|
|
8
|
-
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
8
|
+
import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
|
|
9
9
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
10
10
|
import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
|
|
11
11
|
import { ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
|
|
@@ -229,25 +229,26 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
229
229
|
seller.signTransaction(sellTx),
|
|
230
230
|
buyer.signTransaction(buyTx)
|
|
231
231
|
]);
|
|
232
|
-
// ✅ 利润交易放在末尾
|
|
233
|
-
const profitTx = await buildProfitTransaction({
|
|
234
|
-
seller,
|
|
235
|
-
profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
|
|
236
|
-
profitNonce: noncePlan.profitNonce,
|
|
237
|
-
gasPrice,
|
|
238
|
-
chainId: chainContext.chainId,
|
|
239
|
-
txType
|
|
240
|
-
});
|
|
241
232
|
nonceManager.clearTemp();
|
|
242
|
-
// ✅ 组装顺序:贿赂 → 授权 → 卖出 → 买入
|
|
233
|
+
// ✅ 组装顺序:贿赂 → 授权 → 卖出 → 买入
|
|
243
234
|
const allTransactions = [];
|
|
244
235
|
if (bribeTx)
|
|
245
236
|
allTransactions.push(bribeTx);
|
|
246
237
|
if (approvalTx)
|
|
247
238
|
allTransactions.push(approvalTx);
|
|
248
239
|
allTransactions.push(signedSell, signedBuy);
|
|
249
|
-
|
|
250
|
-
|
|
240
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
241
|
+
const profitTxs = await buildProfitTransaction({
|
|
242
|
+
provider: chainContext.provider,
|
|
243
|
+
seller,
|
|
244
|
+
profitAmount: nativeProfitAmount,
|
|
245
|
+
profitNonce: noncePlan.profitNonce,
|
|
246
|
+
gasPrice,
|
|
247
|
+
chainId: chainContext.chainId,
|
|
248
|
+
txType
|
|
249
|
+
});
|
|
250
|
+
if (profitTxs)
|
|
251
|
+
allTransactions.push(...profitTxs);
|
|
251
252
|
return {
|
|
252
253
|
signedTransactions: allTransactions,
|
|
253
254
|
metadata: {
|
|
@@ -449,19 +450,25 @@ function buildTransactionRequest(unsigned, { from, nonce, gasLimit, gasPrice, pr
|
|
|
449
450
|
}
|
|
450
451
|
return tx;
|
|
451
452
|
}
|
|
452
|
-
|
|
453
|
+
/**
|
|
454
|
+
* 构建利润多跳转账交易(强制 2 跳中转)
|
|
455
|
+
*/
|
|
456
|
+
async function buildProfitTransaction({ provider, seller, profitAmount, profitNonce, gasPrice, chainId, txType }) {
|
|
453
457
|
if (!profitNonce || profitAmount === 0n) {
|
|
454
458
|
return null;
|
|
455
459
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
461
|
+
provider,
|
|
462
|
+
payerWallet: seller,
|
|
463
|
+
profitAmount,
|
|
464
|
+
profitRecipient: getProfitRecipient(),
|
|
465
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
460
466
|
gasPrice,
|
|
461
|
-
gasLimit: 21000n,
|
|
462
467
|
chainId,
|
|
463
|
-
|
|
468
|
+
txType,
|
|
469
|
+
startNonce: profitNonce
|
|
464
470
|
});
|
|
471
|
+
return profitHopResult.signedTransactions;
|
|
465
472
|
}
|
|
466
473
|
function calculateProfitAmount(quotedNative) {
|
|
467
474
|
if (quotedNative <= 0n) {
|
|
@@ -620,22 +627,9 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
620
627
|
});
|
|
621
628
|
bribeNonceOffset = 1; // 卖出交易的 nonce 需要 +1
|
|
622
629
|
}
|
|
623
|
-
// 利润交易放在末尾(由卖方发送,与贿赂交易同一钱包)
|
|
624
|
-
let profitTx = null;
|
|
625
|
-
if (nativeProfitAmount > 0n) {
|
|
626
|
-
// 利润交易 nonce = 卖出 nonce + 1
|
|
627
|
-
const profitNonce = sellNonce + bribeNonceOffset + 1;
|
|
628
|
-
profitTx = await seller.signTransaction({
|
|
629
|
-
to: getProfitRecipient(),
|
|
630
|
-
value: nativeProfitAmount,
|
|
631
|
-
nonce: profitNonce,
|
|
632
|
-
gasPrice,
|
|
633
|
-
gasLimit: 21000n,
|
|
634
|
-
chainId: chainContext.chainId,
|
|
635
|
-
type: txType
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
630
|
nonceManager.clearTemp();
|
|
631
|
+
// 利润多跳交易 nonce 计算
|
|
632
|
+
const profitNonce = nativeProfitAmount > 0n ? sellNonce + bribeNonceOffset + 1 : undefined;
|
|
639
633
|
// ✅ 并行签名所有交易
|
|
640
634
|
const sellTx = buildTransactionRequest(sellUnsigned, {
|
|
641
635
|
from: seller.address,
|
|
@@ -663,7 +657,7 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
663
657
|
return buyer.signTransaction(buyTx);
|
|
664
658
|
})
|
|
665
659
|
]);
|
|
666
|
-
// ✅ 按顺序组装交易数组:贿赂 → 授权 → 卖出 → 买入
|
|
660
|
+
// ✅ 按顺序组装交易数组:贿赂 → 授权 → 卖出 → 买入
|
|
667
661
|
const signedTransactions = [];
|
|
668
662
|
if (bribeTx)
|
|
669
663
|
signedTransactions.push(bribeTx);
|
|
@@ -671,8 +665,20 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
671
665
|
signedTransactions.push(approvalTx);
|
|
672
666
|
signedTransactions.push(signedSell);
|
|
673
667
|
signedTransactions.push(...signedBuys);
|
|
674
|
-
|
|
675
|
-
|
|
668
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
669
|
+
if (profitNonce !== undefined && nativeProfitAmount > 0n) {
|
|
670
|
+
const profitTxs = await buildProfitTransaction({
|
|
671
|
+
provider: chainContext.provider,
|
|
672
|
+
seller,
|
|
673
|
+
profitAmount: nativeProfitAmount,
|
|
674
|
+
profitNonce,
|
|
675
|
+
gasPrice,
|
|
676
|
+
chainId: chainContext.chainId,
|
|
677
|
+
txType
|
|
678
|
+
});
|
|
679
|
+
if (profitTxs)
|
|
680
|
+
signedTransactions.push(...profitTxs);
|
|
681
|
+
}
|
|
676
682
|
return {
|
|
677
683
|
signedTransactions,
|
|
678
684
|
metadata: {
|
|
@@ -923,20 +929,6 @@ export async function flapQuickBatchSwapMerkle(params) {
|
|
|
923
929
|
return buyer.signTransaction(buyTx);
|
|
924
930
|
}));
|
|
925
931
|
console.log(`[flapQuickBatchSwapMerkle] ${signedBuys.length} 笔买入交易已签名`);
|
|
926
|
-
// ==================== 5. 利润交易 ====================
|
|
927
|
-
let profitTx = null;
|
|
928
|
-
if (nativeProfitAmount > 0n) {
|
|
929
|
-
profitTx = await seller.signTransaction({
|
|
930
|
-
to: getProfitRecipient(),
|
|
931
|
-
value: nativeProfitAmount,
|
|
932
|
-
nonce: sellerNonce++,
|
|
933
|
-
gasPrice,
|
|
934
|
-
gasLimit: 21000n,
|
|
935
|
-
chainId: chainContext.chainId,
|
|
936
|
-
type: txType
|
|
937
|
-
});
|
|
938
|
-
console.log(`[flapQuickBatchSwapMerkle] 利润交易已签名`);
|
|
939
|
-
}
|
|
940
932
|
nonceManager.clearTemp();
|
|
941
933
|
// ==================== 组装交易数组 ====================
|
|
942
934
|
const signedTransactions = [];
|
|
@@ -945,14 +937,27 @@ export async function flapQuickBatchSwapMerkle(params) {
|
|
|
945
937
|
signedTransactions.push(signedSell);
|
|
946
938
|
signedTransactions.push(...transferTxs);
|
|
947
939
|
signedTransactions.push(...signedBuys);
|
|
948
|
-
|
|
949
|
-
|
|
940
|
+
// ==================== 5. 利润多跳转账(强制 2 跳中转)====================
|
|
941
|
+
if (nativeProfitAmount > 0n) {
|
|
942
|
+
const profitTxs = await buildProfitTransaction({
|
|
943
|
+
provider: chainContext.provider,
|
|
944
|
+
seller,
|
|
945
|
+
profitAmount: nativeProfitAmount,
|
|
946
|
+
profitNonce: sellerNonce++,
|
|
947
|
+
gasPrice,
|
|
948
|
+
chainId: chainContext.chainId,
|
|
949
|
+
txType
|
|
950
|
+
});
|
|
951
|
+
if (profitTxs)
|
|
952
|
+
signedTransactions.push(...profitTxs);
|
|
953
|
+
console.log(`[flapQuickBatchSwapMerkle] 利润多跳交易已签名: ${profitTxs?.length || 0} 笔`);
|
|
954
|
+
}
|
|
950
955
|
console.log(`[flapQuickBatchSwapMerkle] 交易组装完成: ${signedTransactions.length} 笔`);
|
|
951
956
|
console.log(` - 贿赂: ${bribeTx ? 1 : 0}`);
|
|
952
957
|
console.log(` - 卖出: 1`);
|
|
953
958
|
console.log(` - 转账: ${transferTxs.length}`);
|
|
954
959
|
console.log(` - 买入: ${signedBuys.length}`);
|
|
955
|
-
console.log(` -
|
|
960
|
+
console.log(` - 利润多跳: ${nativeProfitAmount > 0n ? PROFIT_HOP_COUNT + 1 : 0}`);
|
|
956
961
|
return {
|
|
957
962
|
signedTransactions,
|
|
958
963
|
metadata: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ethers, Wallet, Contract } from 'ethers';
|
|
2
|
-
import { getOptimizedGasPrice, NonceManager } from '../../utils/bundle-helpers.js';
|
|
2
|
+
import { getOptimizedGasPrice, NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
|
|
3
3
|
import { ADDRESSES } from '../../utils/constants.js';
|
|
4
4
|
import { V2_ROUTER_QUOTE_ABI, MULTICALL3_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
|
|
5
5
|
import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
|
|
@@ -238,18 +238,22 @@ export async function flapDisperseWithBundleMerkle(params) {
|
|
|
238
238
|
chainId: chainIdNum,
|
|
239
239
|
type: txType
|
|
240
240
|
}));
|
|
241
|
+
signedTxs.push(...(await Promise.all(txPromises)));
|
|
242
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
241
243
|
if (extractProfit && totalProfit > 0n) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
245
|
+
provider,
|
|
246
|
+
payerWallet: mainWallet,
|
|
247
|
+
profitAmount: totalProfit,
|
|
248
|
+
profitRecipient: getProfitRecipient(),
|
|
249
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
246
250
|
gasPrice,
|
|
247
|
-
gasLimit: 21000n,
|
|
248
251
|
chainId: chainIdNum,
|
|
249
|
-
|
|
250
|
-
|
|
252
|
+
txType,
|
|
253
|
+
startNonce: nonces[recipients.length]
|
|
254
|
+
});
|
|
255
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
251
256
|
}
|
|
252
|
-
signedTxs.push(...(await Promise.all(txPromises)));
|
|
253
257
|
}
|
|
254
258
|
else {
|
|
255
259
|
const decimals = tokenDecimals ?? (await getErc20Decimals(provider, tokenAddress));
|
|
@@ -282,18 +286,22 @@ export async function flapDisperseWithBundleMerkle(params) {
|
|
|
282
286
|
chainId: chainIdNum,
|
|
283
287
|
type: txType
|
|
284
288
|
}));
|
|
289
|
+
signedTxs.push(...(await Promise.all(txPromises)));
|
|
290
|
+
// ✅ 利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
|
|
285
291
|
if (extractProfit && nativeProfitAmount > 0n) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
292
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
293
|
+
provider,
|
|
294
|
+
payerWallet: mainWallet,
|
|
295
|
+
profitAmount: nativeProfitAmount,
|
|
296
|
+
profitRecipient: getProfitRecipient(),
|
|
297
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
290
298
|
gasPrice,
|
|
291
|
-
gasLimit: 21000n,
|
|
292
299
|
chainId: chainIdNum,
|
|
293
|
-
|
|
294
|
-
|
|
300
|
+
txType,
|
|
301
|
+
startNonce: nonces[recipients.length]
|
|
302
|
+
});
|
|
303
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
295
304
|
}
|
|
296
|
-
signedTxs.push(...(await Promise.all(txPromises)));
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
else {
|
|
@@ -395,15 +403,24 @@ export async function flapDisperseWithBundleMerkle(params) {
|
|
|
395
403
|
const nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum);
|
|
396
404
|
totalProfit = nativeProfitAmount;
|
|
397
405
|
}
|
|
406
|
+
const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
|
|
407
|
+
signedTxs.push(...signedTxsResult);
|
|
408
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
398
409
|
if (extractProfit && totalProfit > 0n) {
|
|
399
410
|
const profitNonce = allMainNonces[mainNonceIdx++];
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
411
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
412
|
+
provider,
|
|
413
|
+
payerWallet: mainWallet,
|
|
414
|
+
profitAmount: totalProfit,
|
|
415
|
+
profitRecipient: getProfitRecipient(),
|
|
416
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
417
|
+
gasPrice,
|
|
418
|
+
chainId: chainIdNum,
|
|
419
|
+
txType,
|
|
420
|
+
startNonce: profitNonce
|
|
403
421
|
});
|
|
422
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
404
423
|
}
|
|
405
|
-
const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
|
|
406
|
-
signedTxs.push(...signedTxsResult);
|
|
407
424
|
}
|
|
408
425
|
return {
|
|
409
426
|
signedTransactions: signedTxs,
|
|
@@ -590,19 +607,21 @@ export async function flapSweepWithBundleMerkle(params) {
|
|
|
590
607
|
});
|
|
591
608
|
const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
|
|
592
609
|
signedTxs.push(...allTxs);
|
|
593
|
-
//
|
|
610
|
+
// ✅ 第三步:利润多跳转账(强制 2 跳中转)
|
|
594
611
|
if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
|
|
595
612
|
const payerWallet = wallets[maxSweepIndex];
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
613
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
614
|
+
provider,
|
|
615
|
+
payerWallet,
|
|
616
|
+
profitAmount: totalProfit,
|
|
617
|
+
profitRecipient: getProfitRecipient(),
|
|
618
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
600
619
|
gasPrice,
|
|
601
|
-
gasLimit: nativeGasLimit,
|
|
602
620
|
chainId: chainIdNum,
|
|
603
|
-
|
|
621
|
+
txType,
|
|
622
|
+
startNonce: payerProfitNonce
|
|
604
623
|
});
|
|
605
|
-
signedTxs.push(
|
|
624
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
606
625
|
}
|
|
607
626
|
}
|
|
608
627
|
else {
|
|
@@ -713,19 +732,22 @@ export async function flapSweepWithBundleMerkle(params) {
|
|
|
713
732
|
});
|
|
714
733
|
const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
|
|
715
734
|
signedTxs.push(...allTxs);
|
|
735
|
+
// ✅ 利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
|
|
716
736
|
if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
|
|
717
737
|
const payerWallet = wallets[maxSweepIndex];
|
|
718
738
|
totalProfit = nativeProfitAmount;
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
739
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
740
|
+
provider,
|
|
741
|
+
payerWallet,
|
|
742
|
+
profitAmount: nativeProfitAmount,
|
|
743
|
+
profitRecipient: getProfitRecipient(),
|
|
744
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
723
745
|
gasPrice,
|
|
724
|
-
gasLimit: 21000n,
|
|
725
746
|
chainId: chainIdNum,
|
|
726
|
-
|
|
747
|
+
txType,
|
|
748
|
+
startNonce: payerProfitNonce
|
|
727
749
|
});
|
|
728
|
-
signedTxs.push(
|
|
750
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
729
751
|
}
|
|
730
752
|
}
|
|
731
753
|
}
|
|
@@ -989,19 +1011,22 @@ export async function flapSweepWithBundleMerkle(params) {
|
|
|
989
1011
|
nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum);
|
|
990
1012
|
totalProfit = nativeProfitAmount;
|
|
991
1013
|
}
|
|
1014
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
992
1015
|
if (nativeProfitAmount > 0n && maxSweepIndex >= 0) {
|
|
993
1016
|
const payerWallet = sourceWallets[maxSweepIndex];
|
|
994
1017
|
const profitNonce = await nonceManager.getNextNonce(payerWallet);
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1018
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
1019
|
+
provider,
|
|
1020
|
+
payerWallet,
|
|
1021
|
+
profitAmount: nativeProfitAmount,
|
|
1022
|
+
profitRecipient: getProfitRecipient(),
|
|
1023
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
999
1024
|
gasPrice,
|
|
1000
|
-
gasLimit: 21000n,
|
|
1001
1025
|
chainId: chainIdNum,
|
|
1002
|
-
|
|
1026
|
+
txType,
|
|
1027
|
+
startNonce: profitNonce
|
|
1003
1028
|
});
|
|
1004
|
-
signedTxs.push(
|
|
1029
|
+
signedTxs.push(...profitHopResult.signedTransactions);
|
|
1005
1030
|
}
|
|
1006
1031
|
}
|
|
1007
1032
|
}
|