four-flap-meme-sdk 1.5.95 → 1.5.98
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/index.d.ts +2 -1
- package/dist/contracts/tm-bundle-merkle/index.js +2 -1
- package/dist/contracts/tm-bundle-merkle/submit.d.ts +11 -0
- package/dist/contracts/tm-bundle-merkle/submit.js +88 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/xlayer/bundle.js +98 -11
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ export { fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle,
|
|
|
9
9
|
export { disperseWithBundleMerkle, sweepWithBundleMerkle, pairwiseTransferWithBundleMerkle } from './utils.js';
|
|
10
10
|
export { fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch } from './pancake-proxy.js';
|
|
11
11
|
export { approveFourTokenManagerBatch, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './approve-tokenmanager.js';
|
|
12
|
-
export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type MerkleSubmitConfig, type SubmitBundleResult, submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel, type BlockRazorSubmitConfig, type BlockRazorSubmitResult, submitDirectToRpc, submitDirectToRpcSequential, // ✅
|
|
12
|
+
export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type MerkleSubmitConfig, type SubmitBundleResult, submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel, type BlockRazorSubmitConfig, type BlockRazorSubmitResult, submitDirectToRpc, submitDirectToRpcSequential, // ✅ 顺序广播并等待确认(用于多跳)
|
|
13
|
+
submitDirectToRpcSequentialNoWait, // ✅ 顺序广播但不等待确认(用于 AA handleOps + tail)
|
|
13
14
|
submitDirectToRpcParallel, type DirectSubmitConfig, type DirectSubmitResult, type DirectTxResult } from './submit.js';
|
|
14
15
|
export { fourBundleBuyFirstMerkle, type FourBundleBuyFirstSignParams, type FourBuyFirstSignConfig, type FourBuyFirstResult } from './swap-buy-first.js';
|
|
@@ -22,7 +22,8 @@ submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel,
|
|
|
22
22
|
// ✅ BlockRazor 提交方法
|
|
23
23
|
submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel,
|
|
24
24
|
// ✅ Monad 等链的逐笔广播方法
|
|
25
|
-
submitDirectToRpc, submitDirectToRpcSequential, // ✅
|
|
25
|
+
submitDirectToRpc, submitDirectToRpcSequential, // ✅ 顺序广播并等待确认(用于多跳)
|
|
26
|
+
submitDirectToRpcSequentialNoWait, // ✅ 顺序广播但不等待确认(用于 AA handleOps + tail)
|
|
26
27
|
submitDirectToRpcParallel } from './submit.js';
|
|
27
28
|
// 先买后卖换手方法
|
|
28
29
|
export { fourBundleBuyFirstMerkle } from './swap-buy-first.js';
|
|
@@ -260,6 +260,17 @@ export declare function submitDirectToRpc(signedTransactions: string[], config:
|
|
|
260
260
|
* @returns 广播结果
|
|
261
261
|
*/
|
|
262
262
|
export declare function submitDirectToRpcSequential(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
263
|
+
/**
|
|
264
|
+
* ✅ 顺序广播但不等待确认(用于 AA handleOps + tail 等 nonce 连续的场景)
|
|
265
|
+
*
|
|
266
|
+
* 按顺序逐笔发送交易,每笔只等待广播成功(RPC 返回 txHash),不等待链上确认。
|
|
267
|
+
* 这样可以保证交易按顺序进入 mempool,同时避免等待确认超时。
|
|
268
|
+
*
|
|
269
|
+
* @param signedTransactions 签名后的交易数组
|
|
270
|
+
* @param config 直接广播配置
|
|
271
|
+
* @returns 广播结果
|
|
272
|
+
*/
|
|
273
|
+
export declare function submitDirectToRpcSequentialNoWait(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
263
274
|
/**
|
|
264
275
|
* 并行逐笔广播到 RPC(速度更快,但可能有 nonce 冲突)
|
|
265
276
|
*
|
|
@@ -510,6 +510,94 @@ export async function submitDirectToRpcSequential(signedTransactions, config) {
|
|
|
510
510
|
errorSummary: errors.length > 0 ? errors.join('; ') : undefined
|
|
511
511
|
};
|
|
512
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* ✅ 顺序广播但不等待确认(用于 AA handleOps + tail 等 nonce 连续的场景)
|
|
515
|
+
*
|
|
516
|
+
* 按顺序逐笔发送交易,每笔只等待广播成功(RPC 返回 txHash),不等待链上确认。
|
|
517
|
+
* 这样可以保证交易按顺序进入 mempool,同时避免等待确认超时。
|
|
518
|
+
*
|
|
519
|
+
* @param signedTransactions 签名后的交易数组
|
|
520
|
+
* @param config 直接广播配置
|
|
521
|
+
* @returns 广播结果
|
|
522
|
+
*/
|
|
523
|
+
export async function submitDirectToRpcSequentialNoWait(signedTransactions, config) {
|
|
524
|
+
const totalTransactions = signedTransactions?.length ?? 0;
|
|
525
|
+
if (!signedTransactions || signedTransactions.length === 0) {
|
|
526
|
+
return {
|
|
527
|
+
code: false,
|
|
528
|
+
totalTransactions: 0,
|
|
529
|
+
successCount: 0,
|
|
530
|
+
failedCount: 0,
|
|
531
|
+
txHashes: [],
|
|
532
|
+
results: [],
|
|
533
|
+
errorSummary: 'signedTransactions cannot be empty'
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
if (!config.rpcUrl) {
|
|
537
|
+
return {
|
|
538
|
+
code: false,
|
|
539
|
+
totalTransactions,
|
|
540
|
+
successCount: 0,
|
|
541
|
+
failedCount: totalTransactions,
|
|
542
|
+
txHashes: [],
|
|
543
|
+
results: [],
|
|
544
|
+
errorSummary: 'rpcUrl is required in config'
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const chainId = config.chainId ?? 143;
|
|
548
|
+
const chainName = config.chainName ?? 'MONAD';
|
|
549
|
+
const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
|
|
550
|
+
chainId,
|
|
551
|
+
name: chainName
|
|
552
|
+
});
|
|
553
|
+
const results = [];
|
|
554
|
+
const txHashes = [];
|
|
555
|
+
const errors = [];
|
|
556
|
+
// ✅ 顺序广播,每笔只等待广播成功(不等待链上确认)
|
|
557
|
+
for (let i = 0; i < signedTransactions.length; i++) {
|
|
558
|
+
const signedTx = signedTransactions[i];
|
|
559
|
+
try {
|
|
560
|
+
// 广播交易,等待 RPC 返回 txHash
|
|
561
|
+
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
562
|
+
results.push({
|
|
563
|
+
index: i,
|
|
564
|
+
success: true,
|
|
565
|
+
txHash: txResponse.hash
|
|
566
|
+
});
|
|
567
|
+
txHashes.push(txResponse.hash);
|
|
568
|
+
console.log(`✅ [${chainName}] 交易 ${i + 1}/${totalTransactions} 广播成功: ${txResponse.hash}`);
|
|
569
|
+
}
|
|
570
|
+
catch (error) {
|
|
571
|
+
const errorMessage = error?.message || String(error);
|
|
572
|
+
console.error(`❌ [${chainName}] 交易 ${i + 1}/${totalTransactions} 广播失败:`, errorMessage);
|
|
573
|
+
// ✅ 兼容:nonce too low / already known 等情况下,交易可能已经被接收
|
|
574
|
+
const recovered = await recoverTxHashIfAlreadySeen(provider, signedTx, errorMessage);
|
|
575
|
+
if (recovered) {
|
|
576
|
+
results.push({ index: i, success: true, txHash: recovered, error: errorMessage });
|
|
577
|
+
txHashes.push(recovered);
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
results.push({
|
|
581
|
+
index: i,
|
|
582
|
+
success: false,
|
|
583
|
+
error: errorMessage
|
|
584
|
+
});
|
|
585
|
+
errors.push(`交易 ${i + 1}: ${errorMessage}`);
|
|
586
|
+
// ✅ 如果某笔失败,继续尝试后续交易(可能是 nonce 问题可以自动恢复)
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const successCount = txHashes.length;
|
|
590
|
+
const failedCount = totalTransactions - successCount;
|
|
591
|
+
return {
|
|
592
|
+
code: successCount > 0,
|
|
593
|
+
totalTransactions,
|
|
594
|
+
successCount,
|
|
595
|
+
failedCount,
|
|
596
|
+
txHashes,
|
|
597
|
+
results,
|
|
598
|
+
errorSummary: errors.length > 0 ? errors.join('; ') : undefined
|
|
599
|
+
};
|
|
600
|
+
}
|
|
513
601
|
/**
|
|
514
602
|
* 并行逐笔广播到 RPC(速度更快,但可能有 nonce 冲突)
|
|
515
603
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -49,7 +49,8 @@ export { flapBundleCurveToDex, type CurveToDexChain, type DexPoolType, type Curv
|
|
|
49
49
|
export { flapBundleCreateToDex, type CreateToDexChain, type CreateToDexSignConfig, type CreateTokenInfo, type FlapCreateToDexParams, type FlapCreateToDexResult } from './flap/portal-bundle-merkle/create-to-dex.js';
|
|
50
50
|
export { PROFIT_CONFIG } from './utils/constants.js';
|
|
51
51
|
export { quoteV2, quoteV3, quote, getTokenToNativeQuote, getNativeToTokenQuote, getWrappedNativeAddress, getStableCoins, V3_FEE_TIERS, QUOTE_CONFIG, type QuoteParams, type QuoteResult, type SupportedChain, } from './utils/quote-helpers.js';
|
|
52
|
-
export { submitDirectToRpc, submitDirectToRpcSequential, // ✅
|
|
52
|
+
export { submitDirectToRpc, submitDirectToRpcSequential, // ✅ 顺序广播并等待确认(用于多跳)
|
|
53
|
+
submitDirectToRpcSequentialNoWait, // ✅ 顺序广播但不等待确认(用于 AA handleOps + tail)
|
|
53
54
|
submitDirectToRpcParallel, type DirectSubmitConfig, type DirectSubmitResult, type DirectTxResult } from './contracts/tm-bundle-merkle/submit.js';
|
|
54
55
|
export { directV2BatchBuy, directV2BatchSell, directV3BatchBuy, directV3BatchSell, getRouterAddress, DIRECT_ROUTERS, type DirectV2BuyParams, type DirectV2SellParams, type DirectV3BuyParams, type DirectV3SellParams, type DirectRouterResult, type DirectRouterSignConfig, type DexKey, type RouterVersion, } from './dex/index.js';
|
|
55
56
|
export * as XLayer from './xlayer/index.js';
|
package/dist/index.js
CHANGED
|
@@ -82,7 +82,8 @@ export { PROFIT_CONFIG } from './utils/constants.js';
|
|
|
82
82
|
// ✅ V2/V3 报价工具(统一管理)
|
|
83
83
|
export { quoteV2, quoteV3, quote, getTokenToNativeQuote, getNativeToTokenQuote, getWrappedNativeAddress, getStableCoins, V3_FEE_TIERS, QUOTE_CONFIG, } from './utils/quote-helpers.js';
|
|
84
84
|
// ✅ Monad 等不支持 Bundle 的链:逐笔 RPC 广播方法(服务器端使用)
|
|
85
|
-
export { submitDirectToRpc, submitDirectToRpcSequential, // ✅
|
|
85
|
+
export { submitDirectToRpc, submitDirectToRpcSequential, // ✅ 顺序广播并等待确认(用于多跳)
|
|
86
|
+
submitDirectToRpcSequentialNoWait, // ✅ 顺序广播但不等待确认(用于 AA handleOps + tail)
|
|
86
87
|
submitDirectToRpcParallel } from './contracts/tm-bundle-merkle/submit.js';
|
|
87
88
|
// ============================================================
|
|
88
89
|
// ✅ DEX 直接交易(不走代理合约)
|
package/dist/xlayer/bundle.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { Wallet, Interface, Contract, ethers } from 'ethers';
|
|
11
11
|
import { FLAP_PORTAL, ENTRYPOINT_ABI, PORTAL_ABI, DEFAULT_CALL_GAS_LIMIT_SELL, DEFAULT_WITHDRAW_RESERVE, WOKB, POTATOSWAP_V2_ROUTER, POTATOSWAP_V3_ROUTER, } from './constants.js';
|
|
12
12
|
import { AAAccountManager, encodeExecute, encodeExecuteBatch, createWallet } from './aa-account.js';
|
|
13
|
-
import {
|
|
13
|
+
import { encodeBuyCallV3, encodeSellCall, encodeApproveCall, encodeTransferCall, encodeCreateCallV2, encodeCreateCallV3, encodeCreateCallV4, PortalQuery, parseOkb, formatOkb, lpFeeProfileToV3Fee, } from './portal-ops.js';
|
|
14
14
|
import { mapWithConcurrency } from '../utils/concurrency.js';
|
|
15
15
|
import { PROFIT_CONFIG, ZERO_ADDRESS } from '../utils/constants.js';
|
|
16
16
|
import { DexQuery } from './dex.js';
|
|
@@ -1418,28 +1418,58 @@ export class BundleExecutor {
|
|
|
1418
1418
|
}
|
|
1419
1419
|
}
|
|
1420
1420
|
const provider = this.aaManager.getProvider();
|
|
1421
|
-
|
|
1421
|
+
let currentNonce = params.payerStartNonce ?? await provider.getTransactionCount(payer.address, 'pending');
|
|
1422
1422
|
const signedTransactions = [];
|
|
1423
1423
|
const feeData = await provider.getFeeData();
|
|
1424
1424
|
const gasPrice = feeData.gasPrice ?? 100000000n;
|
|
1425
1425
|
const chainId = (await provider.getNetwork()).chainId;
|
|
1426
|
+
// === 0. 向买家 AA 账户转入 OKB(prefund + 买入金额)===
|
|
1427
|
+
// ✅ 修复 AA21 didn't pay prefund 错误:确保每个买家的 AA 账户有足够的 OKB
|
|
1428
|
+
const DEFAULT_PREFUND_ESTIMATE = parseOkb('0.002'); // 预估每个 UserOp 的 prefund (gas 费用)
|
|
1429
|
+
const BUFFER_WEI = parseOkb('0.0005'); // 缓冲金额
|
|
1430
|
+
for (let i = 0; i < buyerWallets.length; i++) {
|
|
1431
|
+
const buyerSender = buyerSenders[i];
|
|
1432
|
+
const buyWei = buyerData[i].buyWei;
|
|
1433
|
+
// 计算需要转入的金额:买入金额 + prefund + 缓冲
|
|
1434
|
+
const requiredAmount = useNativeToken
|
|
1435
|
+
? buyWei + DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI // 原生代币:需要买入金额 + gas
|
|
1436
|
+
: DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI; // ERC20 代币:只需要 gas
|
|
1437
|
+
// 检查买家 AA 账户当前余额
|
|
1438
|
+
const currentBalance = await provider.getBalance(buyerSender);
|
|
1439
|
+
if (currentBalance < requiredAmount) {
|
|
1440
|
+
const transferAmount = requiredAmount - currentBalance;
|
|
1441
|
+
console.log(`[买家${i + 1}] 向 AA 账户 ${buyerSender} 转入 ${formatOkb(transferAmount)} OKB`);
|
|
1442
|
+
const fundTxRequest = {
|
|
1443
|
+
to: buyerSender,
|
|
1444
|
+
value: transferAmount,
|
|
1445
|
+
nonce: currentNonce,
|
|
1446
|
+
gasLimit: 21000n,
|
|
1447
|
+
gasPrice,
|
|
1448
|
+
chainId
|
|
1449
|
+
};
|
|
1450
|
+
const signedFundTx = await payer.signTransaction(fundTxRequest);
|
|
1451
|
+
signedTransactions.push(signedFundTx);
|
|
1452
|
+
currentNonce++;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1426
1455
|
// === 1. AA handleOps 交易(包含所有 UserOps:创建 + 买入)===
|
|
1427
1456
|
const signedMainTx = await this.signHandleOpsTx({
|
|
1428
1457
|
ops,
|
|
1429
1458
|
payerWallet: payer,
|
|
1430
1459
|
beneficiary: useBeneficiary,
|
|
1431
|
-
nonce:
|
|
1460
|
+
nonce: currentNonce,
|
|
1432
1461
|
gasLimit: effConfig.gasLimit,
|
|
1433
1462
|
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1434
1463
|
});
|
|
1435
1464
|
signedTransactions.push(signedMainTx);
|
|
1465
|
+
currentNonce++;
|
|
1436
1466
|
// === 2. 利润提取交易(独立的 EOA 转账)===
|
|
1437
1467
|
if (nativeProfitAmount > 0n) {
|
|
1438
1468
|
console.log(`[利润提取-签名] 非 AA 转账: ${useNativeToken ? formatOkb(nativeProfitAmount) : `${formatOkb(totalBuyProfitWei)} (ERC20) -> ${formatOkb(nativeProfitAmount)} (OKB)`} -> ${profitSettings.profitRecipient}`);
|
|
1439
1469
|
const profitTxRequest = {
|
|
1440
1470
|
to: profitSettings.profitRecipient,
|
|
1441
1471
|
value: nativeProfitAmount,
|
|
1442
|
-
nonce:
|
|
1472
|
+
nonce: currentNonce,
|
|
1443
1473
|
gasLimit: 21000n,
|
|
1444
1474
|
gasPrice,
|
|
1445
1475
|
chainId
|
|
@@ -1539,9 +1569,11 @@ export class BundleExecutor {
|
|
|
1539
1569
|
});
|
|
1540
1570
|
totalCurveBuyWei = curveBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
|
|
1541
1571
|
// ✅ 并行构建和签名所有内盘买入 UserOps
|
|
1572
|
+
// ✅ 使用 encodeBuyCallV3(支持 extensionData),与 V4 代币创建保持一致
|
|
1573
|
+
const extensionData = params.extensionData ?? '0x';
|
|
1542
1574
|
const signedCurveBuyOps = await mapWithConcurrency(curveBuyData, 5, async (data) => {
|
|
1543
1575
|
const { wallet, info, buyWei, gasLimit } = data;
|
|
1544
|
-
const buyData =
|
|
1576
|
+
const buyData = encodeBuyCallV3(tokenAddress, buyWei, 0n, extensionData);
|
|
1545
1577
|
const buyCallData = encodeExecute(FLAP_PORTAL, buyWei, buyData);
|
|
1546
1578
|
const buyOpRes = await aaManager.buildUserOpWithFixedGas({
|
|
1547
1579
|
ownerWallet: wallet,
|
|
@@ -1556,17 +1588,48 @@ export class BundleExecutor {
|
|
|
1556
1588
|
return signedBuyOp.userOp;
|
|
1557
1589
|
});
|
|
1558
1590
|
ops1.push(...signedCurveBuyOps);
|
|
1591
|
+
// === 向内盘买家 AA 账户转入 OKB(prefund + 买入金额)===
|
|
1592
|
+
// ✅ 修复 AA21 didn't pay prefund 错误
|
|
1593
|
+
const feeData = await provider.getFeeData();
|
|
1594
|
+
const gasPrice = feeData.gasPrice ?? 100000000n;
|
|
1595
|
+
const chainId = (await provider.getNetwork()).chainId;
|
|
1596
|
+
let currentNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
|
|
1597
|
+
const DEFAULT_PREFUND_ESTIMATE = parseOkb('0.002'); // 预估每个 UserOp 的 prefund
|
|
1598
|
+
const BUFFER_WEI = parseOkb('0.0005'); // 缓冲金额
|
|
1599
|
+
for (let i = 0; i < curveBuyerWallets.length; i++) {
|
|
1600
|
+
const buyerSender = curveBuyerInfos[i].sender;
|
|
1601
|
+
const buyWei = curveBuyData[i].buyWei;
|
|
1602
|
+
// 计算需要转入的金额:买入金额 + prefund + 缓冲
|
|
1603
|
+
const requiredAmount = buyWei + DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI;
|
|
1604
|
+
// 检查买家 AA 账户当前余额
|
|
1605
|
+
const currentBalance = await provider.getBalance(buyerSender);
|
|
1606
|
+
if (currentBalance < requiredAmount) {
|
|
1607
|
+
const transferAmount = requiredAmount - currentBalance;
|
|
1608
|
+
console.log(`[内盘买家${i + 1}] 向 AA 账户 ${buyerSender} 转入 ${formatOkb(transferAmount)} OKB`);
|
|
1609
|
+
const fundTxRequest = {
|
|
1610
|
+
to: buyerSender,
|
|
1611
|
+
value: transferAmount,
|
|
1612
|
+
nonce: currentNonce,
|
|
1613
|
+
gasLimit: 21000n,
|
|
1614
|
+
gasPrice,
|
|
1615
|
+
chainId
|
|
1616
|
+
};
|
|
1617
|
+
const signedFundTx = await payerWallet.signTransaction(fundTxRequest);
|
|
1618
|
+
signedTransactions.push(signedFundTx);
|
|
1619
|
+
currentNonce++;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1559
1622
|
// 签名第一个 handleOps
|
|
1560
|
-
const startNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
|
|
1561
1623
|
const signedMainTx = await this.signHandleOpsTx({
|
|
1562
1624
|
ops: ops1,
|
|
1563
1625
|
payerWallet: payerWallet,
|
|
1564
1626
|
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1565
|
-
nonce:
|
|
1627
|
+
nonce: currentNonce,
|
|
1566
1628
|
gasLimit: effConfig.gasLimit,
|
|
1567
1629
|
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1568
1630
|
});
|
|
1569
1631
|
signedTransactions.push(signedMainTx);
|
|
1632
|
+
currentNonce++;
|
|
1570
1633
|
// --- 4. 构建外盘买入 handleOps (如果启用) ---
|
|
1571
1634
|
if (enableDexBuy && dexBuyerPrivateKeys.length > 0) {
|
|
1572
1635
|
const dexBuyerWallets = dexBuyerPrivateKeys.map(pk => createWallet(pk, config));
|
|
@@ -1584,10 +1647,34 @@ export class BundleExecutor {
|
|
|
1584
1647
|
return { wallet, info: dexBuyerInfos[i], buyWei };
|
|
1585
1648
|
});
|
|
1586
1649
|
totalDexBuyWei = dexBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
|
|
1650
|
+
// === 向外盘买家 AA 账户转入 OKB(prefund + 买入金额)===
|
|
1651
|
+
for (let i = 0; i < dexBuyerWallets.length; i++) {
|
|
1652
|
+
const buyerSender = dexBuyerInfos[i].sender;
|
|
1653
|
+
const buyWei = dexBuyData[i].buyWei;
|
|
1654
|
+
// 计算需要转入的金额:买入金额 + prefund + 缓冲
|
|
1655
|
+
const requiredAmount = buyWei + DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI;
|
|
1656
|
+
// 检查买家 AA 账户当前余额
|
|
1657
|
+
const dexBuyerBalance = await provider.getBalance(buyerSender);
|
|
1658
|
+
if (dexBuyerBalance < requiredAmount) {
|
|
1659
|
+
const transferAmount = requiredAmount - dexBuyerBalance;
|
|
1660
|
+
console.log(`[外盘买家${i + 1}] 向 AA 账户 ${buyerSender} 转入 ${formatOkb(transferAmount)} OKB`);
|
|
1661
|
+
const fundTxRequest = {
|
|
1662
|
+
to: buyerSender,
|
|
1663
|
+
value: transferAmount,
|
|
1664
|
+
nonce: currentNonce,
|
|
1665
|
+
gasLimit: 21000n,
|
|
1666
|
+
gasPrice,
|
|
1667
|
+
chainId
|
|
1668
|
+
};
|
|
1669
|
+
const signedFundTx = await payerWallet.signTransaction(fundTxRequest);
|
|
1670
|
+
signedTransactions.push(signedFundTx);
|
|
1671
|
+
currentNonce++;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1587
1674
|
// ✅ 并行构建和签名所有外盘买入 UserOps
|
|
1588
1675
|
const signedDexBuyOps = await mapWithConcurrency(dexBuyData, 5, async (data) => {
|
|
1589
1676
|
const { wallet, info, buyWei } = data;
|
|
1590
|
-
// ✅ 外盘买入:使用
|
|
1677
|
+
// ✅ 外盘买入:使用 DEX Router 进行交换
|
|
1591
1678
|
let swapData;
|
|
1592
1679
|
let routerAddress;
|
|
1593
1680
|
if (dexType === 'V3') {
|
|
@@ -1625,11 +1712,12 @@ export class BundleExecutor {
|
|
|
1625
1712
|
ops: ops2,
|
|
1626
1713
|
payerWallet: payerWallet,
|
|
1627
1714
|
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1628
|
-
nonce:
|
|
1715
|
+
nonce: currentNonce,
|
|
1629
1716
|
gasLimit: effConfig.gasLimit,
|
|
1630
1717
|
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1631
1718
|
});
|
|
1632
1719
|
signedTransactions.push(signedDexTx);
|
|
1720
|
+
currentNonce++;
|
|
1633
1721
|
}
|
|
1634
1722
|
// --- 5. 利润提取 (Direct EOA transfer) ---
|
|
1635
1723
|
let totalProfitWei = 0n;
|
|
@@ -1639,12 +1727,11 @@ export class BundleExecutor {
|
|
|
1639
1727
|
totalProfitWei += calculateProfitWei(totalDexBuyWei, profitSettings.profitBps);
|
|
1640
1728
|
}
|
|
1641
1729
|
if (totalProfitWei > 0n) {
|
|
1642
|
-
const profitTxNonce = startNonce + (enableDexBuy ? 2 : 1);
|
|
1643
1730
|
const signedProfitTx = await this.signProfitTransaction({
|
|
1644
1731
|
payerWallet,
|
|
1645
1732
|
profitWei: totalProfitWei,
|
|
1646
1733
|
recipient: profitSettings.profitRecipient,
|
|
1647
|
-
nonce:
|
|
1734
|
+
nonce: currentNonce
|
|
1648
1735
|
});
|
|
1649
1736
|
signedTransactions.push(signedProfitTx);
|
|
1650
1737
|
}
|