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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行
|
|
5
5
|
*/
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
|
-
import { NonceManager, getDeadline } from '../utils/bundle-helpers.js';
|
|
7
|
+
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
|
|
8
8
|
import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA, ZERO_ADDRESS } from '../utils/constants.js';
|
|
9
9
|
import { quoteV2, quoteV3, getTokenToNativeQuote, getWrappedNativeAddress } from '../utils/quote-helpers.js';
|
|
10
10
|
import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI } from '../abis/common.js';
|
|
@@ -149,15 +149,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
149
149
|
chainId: context.chainId,
|
|
150
150
|
type: txType
|
|
151
151
|
});
|
|
152
|
-
// ✅ 利润交易放在末尾
|
|
153
|
-
const profitTx = await buildProfitTransaction({
|
|
154
|
-
seller,
|
|
155
|
-
profitAmount,
|
|
156
|
-
profitNonce: noncePlan.profitNonce,
|
|
157
|
-
gasPrice,
|
|
158
|
-
chainId: context.chainId,
|
|
159
|
-
txType
|
|
160
|
-
});
|
|
161
152
|
nonceManager.clearTemp();
|
|
162
153
|
validateFinalBalances({
|
|
163
154
|
sameAddress,
|
|
@@ -171,13 +162,23 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
171
162
|
provider: context.provider,
|
|
172
163
|
buyerAddress: buyer.address
|
|
173
164
|
});
|
|
174
|
-
// ✅ 组装顺序:贿赂 → 买入 → 卖出
|
|
165
|
+
// ✅ 组装顺序:贿赂 → 买入 → 卖出
|
|
175
166
|
const allTransactions = [];
|
|
176
167
|
if (bribeTx)
|
|
177
168
|
allTransactions.push(bribeTx);
|
|
178
169
|
allTransactions.push(signedBuy, signedSell);
|
|
179
|
-
|
|
180
|
-
|
|
170
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
171
|
+
const profitTxs = await buildProfitTransaction({
|
|
172
|
+
provider: context.provider,
|
|
173
|
+
seller,
|
|
174
|
+
profitAmount,
|
|
175
|
+
profitNonce: noncePlan.profitNonce,
|
|
176
|
+
gasPrice,
|
|
177
|
+
chainId: context.chainId,
|
|
178
|
+
txType
|
|
179
|
+
});
|
|
180
|
+
if (profitTxs)
|
|
181
|
+
allTransactions.push(...profitTxs);
|
|
181
182
|
return {
|
|
182
183
|
signedTransactions: allTransactions,
|
|
183
184
|
metadata: {
|
|
@@ -411,19 +412,25 @@ async function planNonces({ buyer, seller, sameAddress, extractProfit, needBribe
|
|
|
411
412
|
]);
|
|
412
413
|
return { buyerNonce, sellerNonce };
|
|
413
414
|
}
|
|
414
|
-
|
|
415
|
+
/**
|
|
416
|
+
* 构建利润多跳转账交易(强制 2 跳中转)
|
|
417
|
+
*/
|
|
418
|
+
async function buildProfitTransaction({ provider, seller, profitAmount, profitNonce, gasPrice, chainId, txType }) {
|
|
415
419
|
if (profitNonce === undefined || profitAmount === 0n) {
|
|
416
420
|
return null;
|
|
417
421
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
423
|
+
provider,
|
|
424
|
+
payerWallet: seller,
|
|
425
|
+
profitAmount,
|
|
426
|
+
profitRecipient: PROFIT_CONFIG.RECIPIENT,
|
|
427
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
422
428
|
gasPrice,
|
|
423
|
-
gasLimit: 21000n,
|
|
424
429
|
chainId,
|
|
425
|
-
|
|
430
|
+
txType,
|
|
431
|
+
startNonce: profitNonce
|
|
426
432
|
});
|
|
433
|
+
return profitHopResult.signedTransactions;
|
|
427
434
|
}
|
|
428
435
|
async function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress }) {
|
|
429
436
|
const gasCost = gasLimit * gasPrice;
|
|
@@ -299,7 +299,7 @@ function countTruthy(values) {
|
|
|
299
299
|
*/
|
|
300
300
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
301
301
|
import { calculateSellAmount } from '../utils/swap-helpers.js';
|
|
302
|
-
import { NonceManager, getDeadline } from '../utils/bundle-helpers.js';
|
|
302
|
+
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
|
|
303
303
|
import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from '../utils/constants.js';
|
|
304
304
|
import { quoteV2, quoteV3 } from '../utils/quote-helpers.js';
|
|
305
305
|
import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI } from '../abis/common.js';
|
|
@@ -457,25 +457,12 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
457
457
|
chainId: context.chainId,
|
|
458
458
|
type: txType
|
|
459
459
|
}).then(tx => ({ type: 'buy', tx })));
|
|
460
|
-
// 利润交易
|
|
461
|
-
if (profitAmount > 0n && noncePlan.profitNonce !== undefined) {
|
|
462
|
-
signPromises.push(seller.signTransaction({
|
|
463
|
-
to: PROFIT_CONFIG.RECIPIENT,
|
|
464
|
-
value: profitAmount,
|
|
465
|
-
nonce: noncePlan.profitNonce,
|
|
466
|
-
gasPrice,
|
|
467
|
-
gasLimit: 21000n,
|
|
468
|
-
chainId: context.chainId,
|
|
469
|
-
type: txType
|
|
470
|
-
}).then(tx => ({ type: 'profit', tx })));
|
|
471
|
-
}
|
|
472
460
|
// ✅ 并行执行所有签名
|
|
473
461
|
const signedResults = await Promise.all(signPromises);
|
|
474
462
|
// 按类型提取结果
|
|
475
463
|
const bribeTx = signedResults.find(r => r.type === 'bribe')?.tx || null;
|
|
476
464
|
const signedSell = signedResults.find(r => r.type === 'sell').tx;
|
|
477
465
|
const signedBuy = signedResults.find(r => r.type === 'buy').tx;
|
|
478
|
-
const profitTx = signedResults.find(r => r.type === 'profit')?.tx || null;
|
|
479
466
|
nonceManager.clearTemp();
|
|
480
467
|
validateFinalBalances({
|
|
481
468
|
sameAddress,
|
|
@@ -489,13 +476,26 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
489
476
|
provider: context.provider,
|
|
490
477
|
buyerAddress: buyer.address
|
|
491
478
|
});
|
|
492
|
-
// ✅ 组装顺序:贿赂 → 卖出 → 买入
|
|
479
|
+
// ✅ 组装顺序:贿赂 → 卖出 → 买入
|
|
493
480
|
const signedTransactions = [];
|
|
494
481
|
if (bribeTx)
|
|
495
482
|
signedTransactions.push(bribeTx);
|
|
496
483
|
signedTransactions.push(signedSell, signedBuy);
|
|
497
|
-
|
|
498
|
-
|
|
484
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
485
|
+
if (profitAmount > 0n && noncePlan.profitNonce !== undefined) {
|
|
486
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
487
|
+
provider: context.provider,
|
|
488
|
+
payerWallet: seller,
|
|
489
|
+
profitAmount,
|
|
490
|
+
profitRecipient: PROFIT_CONFIG.RECIPIENT,
|
|
491
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
492
|
+
gasPrice,
|
|
493
|
+
chainId: context.chainId,
|
|
494
|
+
txType,
|
|
495
|
+
startNonce: noncePlan.profitNonce
|
|
496
|
+
});
|
|
497
|
+
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
498
|
+
}
|
|
499
499
|
return {
|
|
500
500
|
signedTransactions,
|
|
501
501
|
metadata: {
|
|
@@ -720,23 +720,10 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
720
720
|
profitAmount = calculateProfitAmount(estimatedBNBValue);
|
|
721
721
|
console.log(`[pancakeBatchSwapMerkle] ERC20→BNB 报价: ${ethers.formatUnits(estimatedBNBOut, quoteTokenDecimals)} → ${ethers.formatEther(estimatedBNBValue)} BNB, 利润: ${ethers.formatEther(profitAmount)} BNB`);
|
|
722
722
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const profitNonce = startNonces && startNonces.length >= 1
|
|
728
|
-
? sellNonce + 1
|
|
729
|
-
: await nonceManager.getNextNonce(seller);
|
|
730
|
-
profitTx = await seller.signTransaction({
|
|
731
|
-
to: PROFIT_CONFIG.RECIPIENT,
|
|
732
|
-
value: profitAmount,
|
|
733
|
-
nonce: profitNonce,
|
|
734
|
-
gasPrice,
|
|
735
|
-
gasLimit: 21000n,
|
|
736
|
-
chainId: context.chainId,
|
|
737
|
-
type: txType
|
|
738
|
-
});
|
|
739
|
-
}
|
|
723
|
+
// 计算利润 nonce
|
|
724
|
+
const profitNonce = profitAmount > 0n
|
|
725
|
+
? (startNonces && startNonces.length >= 1 ? sellNonce + 1 : await nonceManager.getNextNonce(seller))
|
|
726
|
+
: undefined;
|
|
740
727
|
nonceManager.clearTemp();
|
|
741
728
|
// ✅ 并行签名所有交易
|
|
742
729
|
// 1. 签名卖出交易
|
|
@@ -764,14 +751,27 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
764
751
|
signedSellPromise,
|
|
765
752
|
...signedBuyPromises
|
|
766
753
|
]);
|
|
767
|
-
// 4. 按顺序组装交易数组:贿赂 → 卖出 → 买入
|
|
754
|
+
// 4. 按顺序组装交易数组:贿赂 → 卖出 → 买入
|
|
768
755
|
const signedTransactions = [];
|
|
769
756
|
if (bribeTx)
|
|
770
757
|
signedTransactions.push(bribeTx); // 贿赂(首位)
|
|
771
758
|
signedTransactions.push(signedSell); // 卖出
|
|
772
759
|
signedTransactions.push(...signedBuys); // 多个买入
|
|
773
|
-
|
|
774
|
-
|
|
760
|
+
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
761
|
+
if (profitAmount > 0n && profitNonce !== undefined) {
|
|
762
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
763
|
+
provider: context.provider,
|
|
764
|
+
payerWallet: seller,
|
|
765
|
+
profitAmount,
|
|
766
|
+
profitRecipient: PROFIT_CONFIG.RECIPIENT,
|
|
767
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
768
|
+
gasPrice,
|
|
769
|
+
chainId: context.chainId,
|
|
770
|
+
txType,
|
|
771
|
+
startNonce: profitNonce
|
|
772
|
+
});
|
|
773
|
+
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
774
|
+
}
|
|
775
775
|
return {
|
|
776
776
|
signedTransactions,
|
|
777
777
|
metadata: {
|
|
@@ -1115,38 +1115,38 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1115
1115
|
});
|
|
1116
1116
|
}));
|
|
1117
1117
|
console.log(`[pancakeQuickBatchSwapMerkle] ${signedBuys.length} 笔买入交易已签名`);
|
|
1118
|
-
// ==================== 5. 利润交易 ====================
|
|
1119
|
-
let profitTx = null;
|
|
1120
|
-
if (profitAmount > 0n) {
|
|
1121
|
-
profitTx = await seller.signTransaction({
|
|
1122
|
-
to: PROFIT_CONFIG.RECIPIENT,
|
|
1123
|
-
value: profitAmount,
|
|
1124
|
-
nonce: sellerNonce++,
|
|
1125
|
-
gasPrice,
|
|
1126
|
-
gasLimit: 21000n,
|
|
1127
|
-
chainId: context.chainId,
|
|
1128
|
-
type: txType
|
|
1129
|
-
});
|
|
1130
|
-
console.log(`[pancakeQuickBatchSwapMerkle] 利润交易已签名`);
|
|
1131
|
-
}
|
|
1132
1118
|
nonceManager.clearTemp();
|
|
1133
1119
|
// ==================== 组装交易数组 ====================
|
|
1134
|
-
// BNB 模式:贿赂 → 卖出 → 转账 → 买入 →
|
|
1135
|
-
// ERC20 模式:贿赂 → 卖出 → ERC20转账 → BNB Gas转账 → 买入 →
|
|
1120
|
+
// BNB 模式:贿赂 → 卖出 → 转账 → 买入 → 利润多跳
|
|
1121
|
+
// ERC20 模式:贿赂 → 卖出 → ERC20转账 → BNB Gas转账 → 买入 → 利润多跳
|
|
1136
1122
|
const signedTransactions = [];
|
|
1137
1123
|
if (bribeTx)
|
|
1138
1124
|
signedTransactions.push(bribeTx);
|
|
1139
1125
|
signedTransactions.push(signedSell);
|
|
1140
1126
|
signedTransactions.push(...transferTxs);
|
|
1141
1127
|
signedTransactions.push(...signedBuys);
|
|
1142
|
-
|
|
1143
|
-
|
|
1128
|
+
// ==================== 5. 利润多跳转账(强制 2 跳中转)====================
|
|
1129
|
+
if (profitAmount > 0n) {
|
|
1130
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
1131
|
+
provider: context.provider,
|
|
1132
|
+
payerWallet: seller,
|
|
1133
|
+
profitAmount,
|
|
1134
|
+
profitRecipient: PROFIT_CONFIG.RECIPIENT,
|
|
1135
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
1136
|
+
gasPrice,
|
|
1137
|
+
chainId: context.chainId,
|
|
1138
|
+
txType,
|
|
1139
|
+
startNonce: sellerNonce++
|
|
1140
|
+
});
|
|
1141
|
+
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
1142
|
+
console.log(`[pancakeQuickBatchSwapMerkle] 利润多跳交易已签名: ${profitHopResult.signedTransactions.length} 笔`);
|
|
1143
|
+
}
|
|
1144
1144
|
console.log(`[pancakeQuickBatchSwapMerkle] 交易组装完成: ${signedTransactions.length} 笔`);
|
|
1145
1145
|
console.log(` - 贿赂: ${bribeTx ? 1 : 0}`);
|
|
1146
1146
|
console.log(` - 卖出: 1`);
|
|
1147
1147
|
console.log(` - 转账: ${transferTxs.length}`);
|
|
1148
1148
|
console.log(` - 买入: ${signedBuys.length}`);
|
|
1149
|
-
console.log(` -
|
|
1149
|
+
console.log(` - 利润多跳: ${profitAmount > 0n ? PROFIT_HOP_COUNT + 1 : 0}`);
|
|
1150
1150
|
const outputUnit = useNativeToken ? 'BNB' : 'ERC20';
|
|
1151
1151
|
return {
|
|
1152
1152
|
signedTransactions,
|
|
@@ -188,3 +188,41 @@ export declare function decodeV3Path(path: string): {
|
|
|
188
188
|
tokens: string[];
|
|
189
189
|
fees: number[];
|
|
190
190
|
};
|
|
191
|
+
/**
|
|
192
|
+
* 利润多跳转账配置
|
|
193
|
+
*/
|
|
194
|
+
export interface ProfitHopConfig {
|
|
195
|
+
provider: JsonRpcProvider;
|
|
196
|
+
payerWallet: Wallet;
|
|
197
|
+
profitAmount: bigint;
|
|
198
|
+
profitRecipient: string;
|
|
199
|
+
hopCount?: number;
|
|
200
|
+
gasPrice: bigint;
|
|
201
|
+
chainId: number;
|
|
202
|
+
txType: number;
|
|
203
|
+
startNonce?: number;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 利润多跳结果
|
|
207
|
+
*/
|
|
208
|
+
export interface ProfitHopResult {
|
|
209
|
+
signedTransactions: string[];
|
|
210
|
+
hopWallets: string[];
|
|
211
|
+
totalNonceUsed: number;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 强制 2 跳的利润转账常量
|
|
215
|
+
*/
|
|
216
|
+
export declare const PROFIT_HOP_COUNT = 2;
|
|
217
|
+
/**
|
|
218
|
+
* 生成利润多跳转账交易
|
|
219
|
+
*
|
|
220
|
+
* 流程(2 跳):
|
|
221
|
+
* 1. 支付者 → 中转1(gas + 利润 + 中转1的gas)
|
|
222
|
+
* 2. 中转1 → 中转2(gas + 利润)
|
|
223
|
+
* 3. 中转2 → 利润地址(利润)
|
|
224
|
+
*
|
|
225
|
+
* @param config 配置参数
|
|
226
|
+
* @returns 签名交易和中转钱包私钥
|
|
227
|
+
*/
|
|
228
|
+
export declare function buildProfitHopTransactions(config: ProfitHopConfig): Promise<ProfitHopResult>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Bundle 交易辅助工具
|
|
3
3
|
* 提供可复用的 nonce 管理、gas 估算等功能
|
|
4
4
|
*/
|
|
5
|
-
import { ethers } from 'ethers';
|
|
5
|
+
import { ethers, Wallet } from 'ethers';
|
|
6
6
|
/**
|
|
7
7
|
* Nonce 管理器
|
|
8
8
|
* 用于在 bundle 交易中管理多个钱包的 nonce
|
|
@@ -365,3 +365,87 @@ export function decodeV3Path(path) {
|
|
|
365
365
|
}
|
|
366
366
|
return { tokens, fees };
|
|
367
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* 强制 2 跳的利润转账常量
|
|
370
|
+
*/
|
|
371
|
+
export const PROFIT_HOP_COUNT = 2;
|
|
372
|
+
/**
|
|
373
|
+
* 生成利润多跳转账交易
|
|
374
|
+
*
|
|
375
|
+
* 流程(2 跳):
|
|
376
|
+
* 1. 支付者 → 中转1(gas + 利润 + 中转1的gas)
|
|
377
|
+
* 2. 中转1 → 中转2(gas + 利润)
|
|
378
|
+
* 3. 中转2 → 利润地址(利润)
|
|
379
|
+
*
|
|
380
|
+
* @param config 配置参数
|
|
381
|
+
* @returns 签名交易和中转钱包私钥
|
|
382
|
+
*/
|
|
383
|
+
export async function buildProfitHopTransactions(config) {
|
|
384
|
+
const { provider, payerWallet, profitAmount, profitRecipient, hopCount = PROFIT_HOP_COUNT, gasPrice, chainId, txType, startNonce } = config;
|
|
385
|
+
// 如果利润为 0,返回空结果
|
|
386
|
+
if (profitAmount <= 0n) {
|
|
387
|
+
return { signedTransactions: [], hopWallets: [], totalNonceUsed: 0 };
|
|
388
|
+
}
|
|
389
|
+
// 固定 gas limit(原生代币转账)
|
|
390
|
+
const nativeTransferGasLimit = 21000n;
|
|
391
|
+
const gasFeePerHop = nativeTransferGasLimit * gasPrice;
|
|
392
|
+
// 生成中转钱包
|
|
393
|
+
const hopWallets = [];
|
|
394
|
+
const hopPrivateKeys = [];
|
|
395
|
+
for (let i = 0; i < hopCount; i++) {
|
|
396
|
+
const wallet = Wallet.createRandom();
|
|
397
|
+
hopWallets.push(new Wallet(wallet.privateKey, provider));
|
|
398
|
+
hopPrivateKeys.push(wallet.privateKey);
|
|
399
|
+
}
|
|
400
|
+
// 计算每个中转钱包需要的金额(从后往前)
|
|
401
|
+
// 最后一个中转钱包:只需要利润 + 自己的 gas
|
|
402
|
+
// 其他中转钱包:利润 + 自己的 gas + 下一个钱包需要的金额
|
|
403
|
+
const hopAmounts = [];
|
|
404
|
+
for (let i = hopCount - 1; i >= 0; i--) {
|
|
405
|
+
if (i === hopCount - 1) {
|
|
406
|
+
// 最后一个中转钱包:利润 + 自己转账的 gas
|
|
407
|
+
hopAmounts.unshift(profitAmount + gasFeePerHop);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
// 其他中转钱包:下一个需要的金额 + 自己转账的 gas
|
|
411
|
+
hopAmounts.unshift(hopAmounts[0] + gasFeePerHop);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const signedTxs = [];
|
|
415
|
+
const nonceManager = new NonceManager(provider);
|
|
416
|
+
// 获取支付者的 nonce
|
|
417
|
+
const payerNonce = startNonce ?? await nonceManager.getNextNonce(payerWallet);
|
|
418
|
+
// 1. 支付者 → 第一个中转钱包(包含所有后续的 gas 和利润)
|
|
419
|
+
const payerTx = await payerWallet.signTransaction({
|
|
420
|
+
to: hopWallets[0].address,
|
|
421
|
+
value: hopAmounts[0],
|
|
422
|
+
nonce: payerNonce,
|
|
423
|
+
gasPrice,
|
|
424
|
+
gasLimit: nativeTransferGasLimit,
|
|
425
|
+
chainId,
|
|
426
|
+
type: txType
|
|
427
|
+
});
|
|
428
|
+
signedTxs.push(payerTx);
|
|
429
|
+
// 2. 中转钱包逐层传递
|
|
430
|
+
for (let i = 0; i < hopCount; i++) {
|
|
431
|
+
const fromWallet = hopWallets[i];
|
|
432
|
+
const isLastHop = i === hopCount - 1;
|
|
433
|
+
const toAddress = isLastHop ? profitRecipient : hopWallets[i + 1].address;
|
|
434
|
+
const value = isLastHop ? profitAmount : hopAmounts[i + 1];
|
|
435
|
+
const hopTx = await fromWallet.signTransaction({
|
|
436
|
+
to: toAddress,
|
|
437
|
+
value,
|
|
438
|
+
nonce: 0, // 中转钱包都是新生成的,nonce 从 0 开始
|
|
439
|
+
gasPrice,
|
|
440
|
+
gasLimit: nativeTransferGasLimit,
|
|
441
|
+
chainId,
|
|
442
|
+
type: txType
|
|
443
|
+
});
|
|
444
|
+
signedTxs.push(hopTx);
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
signedTransactions: signedTxs,
|
|
448
|
+
hopWallets: hopPrivateKeys,
|
|
449
|
+
totalNonceUsed: 1 // 支付者只用了 1 个 nonce
|
|
450
|
+
};
|
|
451
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { ethers, Wallet, JsonRpcProvider } from 'ethers';
|
|
9
9
|
import { PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from './constants.js';
|
|
10
|
-
import { NonceManager } from './bundle-helpers.js';
|
|
10
|
+
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT } from './bundle-helpers.js';
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// 核心功能
|
|
13
13
|
// ============================================================================
|
|
@@ -94,10 +94,10 @@ export async function batchPrivateSaleMerkle(params) {
|
|
|
94
94
|
}
|
|
95
95
|
// 利润交易的 nonce
|
|
96
96
|
const profitNonce = hasProfit ? currentNonces.get(firstWalletKey) : 0;
|
|
97
|
-
// ✅
|
|
98
|
-
const
|
|
97
|
+
// ✅ 签名交易数组
|
|
98
|
+
const signedTransactions = [];
|
|
99
99
|
// 1. 贿赂交易签名
|
|
100
|
-
|
|
100
|
+
const bribeTx = await firstWallet.signTransaction({
|
|
101
101
|
to: BLOCKRAZOR_BUILDER_EOA,
|
|
102
102
|
value: bribeAmount,
|
|
103
103
|
gasLimit,
|
|
@@ -105,13 +105,15 @@ export async function batchPrivateSaleMerkle(params) {
|
|
|
105
105
|
nonce: firstWalletBaseNonce,
|
|
106
106
|
chainId,
|
|
107
107
|
type: 0,
|
|
108
|
-
})
|
|
108
|
+
});
|
|
109
|
+
signedTransactions.push(bribeTx);
|
|
109
110
|
// 2. 转账交易签名(并行)
|
|
111
|
+
const transferPromises = [];
|
|
110
112
|
for (let i = 0; i < transfers.length; i++) {
|
|
111
113
|
const transfer = transfers[i];
|
|
112
114
|
const wallet = transferWallets[i];
|
|
113
115
|
const nonce = transferNonces[i];
|
|
114
|
-
|
|
116
|
+
transferPromises.push(wallet.signTransaction({
|
|
115
117
|
to: transfer.recipient,
|
|
116
118
|
value: ethers.parseEther(String(transfer.amount)),
|
|
117
119
|
gasLimit,
|
|
@@ -121,29 +123,30 @@ export async function batchPrivateSaleMerkle(params) {
|
|
|
121
123
|
type: 0,
|
|
122
124
|
}));
|
|
123
125
|
}
|
|
124
|
-
|
|
126
|
+
const transferTxs = await Promise.all(transferPromises);
|
|
127
|
+
signedTransactions.push(...transferTxs);
|
|
128
|
+
// 3. 利润多跳转账(强制 2 跳中转)
|
|
125
129
|
if (hasProfit) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
const profitHopResult = await buildProfitHopTransactions({
|
|
131
|
+
provider,
|
|
132
|
+
payerWallet: firstWallet,
|
|
133
|
+
profitAmount: profitWei,
|
|
134
|
+
profitRecipient: PROFIT_CONFIG.RECIPIENT,
|
|
135
|
+
hopCount: PROFIT_HOP_COUNT,
|
|
130
136
|
gasPrice,
|
|
131
|
-
nonce: profitNonce,
|
|
132
137
|
chainId,
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
txType: 0,
|
|
139
|
+
startNonce: profitNonce
|
|
140
|
+
});
|
|
141
|
+
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
135
142
|
}
|
|
136
|
-
// ✅ 并行执行所有签名
|
|
137
|
-
const allSignedTxs = await Promise.all(allSignPromises);
|
|
138
|
-
// 按顺序组装结果:贿赂(1) + 转账(N) + 利润(0或1)
|
|
139
|
-
const signedTransactions = allSignedTxs;
|
|
140
143
|
return {
|
|
141
144
|
signedTransactions,
|
|
142
145
|
metadata: {
|
|
143
146
|
totalCount: signedTransactions.length,
|
|
144
147
|
bribeCount: 1,
|
|
145
148
|
transferCount: transfers.length,
|
|
146
|
-
profitCount: hasProfit ? 1 : 0,
|
|
149
|
+
profitCount: hasProfit ? PROFIT_HOP_COUNT + 1 : 0, // ✅ 支付者 1 笔 + 中转钱包 N 笔
|
|
147
150
|
totalAmountWei: totalAmountWei.toString(),
|
|
148
151
|
totalProfitWei: profitWei.toString(),
|
|
149
152
|
bribeAmountWei: bribeAmount.toString(),
|