four-flap-meme-sdk 1.6.16 → 1.6.18
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/xlayer/aa-transfer-profit.d.ts +4 -0
- package/dist/xlayer/aa-transfer-profit.js +48 -27
- package/dist/xlayer/bundle.d.ts +11 -11
- package/dist/xlayer/bundle.js +38 -113
- package/package.json +1 -1
|
@@ -19,6 +19,8 @@ export declare function buildDisperseFromSingleOwnerOpsWithProfit(params: {
|
|
|
19
19
|
startNonce?: bigint;
|
|
20
20
|
assumeDeployed?: boolean;
|
|
21
21
|
maxTransfersPerUserOp?: number;
|
|
22
|
+
/** ✅ 多跳中间层:跳过利润扣除(只在最后一跳扣利润) */
|
|
23
|
+
skipProfit?: boolean;
|
|
22
24
|
}): Promise<{
|
|
23
25
|
ops: UserOperation[];
|
|
24
26
|
sender: string;
|
|
@@ -41,6 +43,8 @@ export declare function buildTransfersWithProfit(params: {
|
|
|
41
43
|
toAddresses: string[];
|
|
42
44
|
amounts: string[];
|
|
43
45
|
config?: Partial<XLayerConfig>;
|
|
46
|
+
/** ✅ 多跳中间层:跳过利润扣除(只在最后一跳扣利润) */
|
|
47
|
+
skipProfit?: boolean;
|
|
44
48
|
}): Promise<{
|
|
45
49
|
ops: UserOperation[];
|
|
46
50
|
senders: string[];
|
|
@@ -78,9 +78,11 @@ export async function buildDisperseFromSingleOwnerOpsWithProfit(params) {
|
|
|
78
78
|
});
|
|
79
79
|
totalWei = values.reduce((a, b) => a + b, 0n);
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
// ✅ 多跳中间层:skipProfit=true 时不扣利润,全额转给目标
|
|
82
|
+
const skipProfit = params.skipProfit === true;
|
|
83
|
+
const profitWei = skipProfit ? 0n : calcProfitWei(totalWei, PROFIT_CONFIG.RATE_BPS);
|
|
82
84
|
const distributableWei = totalWei > profitWei ? (totalWei - profitWei) : 0n;
|
|
83
|
-
//
|
|
85
|
+
// 按比例缩放每个收款金额,使"总分发=总额-利润";利润单独转给 recipient
|
|
84
86
|
const scaled = [];
|
|
85
87
|
if (totalWei > 0n && distributableWei > 0n) {
|
|
86
88
|
if (params.kind === 'native') {
|
|
@@ -268,11 +270,10 @@ export async function buildTransfersWithProfit(params) {
|
|
|
268
270
|
initCodeUsed.add(k);
|
|
269
271
|
return aaManager.generateInitCode(ownerAddress);
|
|
270
272
|
};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
+
// ✅ 第一步:计算每个钱包的归集金额和总利润
|
|
274
|
+
// 利润从每个钱包的归集金额中扣除,但只由第一个有效钱包统一转账给利润地址
|
|
275
|
+
const transferInfos = [];
|
|
273
276
|
for (let i = 0; i < ownerWallets.length; i++) {
|
|
274
|
-
const w = ownerWallets[i];
|
|
275
|
-
const ai = infos[i];
|
|
276
277
|
const sender = senders[i];
|
|
277
278
|
const to = String(params.toAddresses[i] || '').trim();
|
|
278
279
|
if (!/^0x[a-fA-F0-9]{40}$/.test(to))
|
|
@@ -292,36 +293,56 @@ export async function buildTransfersWithProfit(params) {
|
|
|
292
293
|
}
|
|
293
294
|
if (amountWei <= 0n)
|
|
294
295
|
continue;
|
|
295
|
-
|
|
296
|
+
// ✅ 多跳中间层:skipProfit=true 时不扣利润,全额转给目标
|
|
297
|
+
const skipProfit = params.skipProfit === true;
|
|
298
|
+
const profitWei = skipProfit ? 0n : calcProfitWei(amountWei, PROFIT_CONFIG.RATE_BPS);
|
|
296
299
|
const toWei = amountWei - profitWei;
|
|
297
300
|
totalProfitWei += profitWei;
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
301
|
+
transferInfos.push({ walletIndex: i, sender, to, amountWei, profitWei, toWei });
|
|
302
|
+
}
|
|
303
|
+
const unsigned = [];
|
|
304
|
+
const opOwnerIndex = [];
|
|
305
|
+
// ✅ 第二步:构建 UserOps
|
|
306
|
+
// - Native (OKB):只转 toWei,利润保留在 AA 钱包(可能需要用于后续 gas)
|
|
307
|
+
// - ERC20:全部转出,profitWei 给利润地址 + toWei 给目标地址
|
|
308
|
+
for (let idx = 0; idx < transferInfos.length; idx++) {
|
|
309
|
+
const info = transferInfos[idx];
|
|
310
|
+
const i = info.walletIndex;
|
|
311
|
+
const w = ownerWallets[i];
|
|
312
|
+
const ai = infos[i];
|
|
313
|
+
const initCode = getInitCode(info.sender, ai?.deployed ?? false, w.address);
|
|
314
|
+
const nonce = getNextNonce(info.sender, BigInt(ai?.nonce ?? 0n));
|
|
315
|
+
let callData;
|
|
316
|
+
let callGasLimit;
|
|
317
|
+
if (params.kind === 'native') {
|
|
318
|
+
// ✅ Native (OKB):只转 toWei,利润保留在 AA 钱包
|
|
319
|
+
callData = encodeExecute(info.to, info.toWei, '0x');
|
|
320
|
+
callGasLimit = 120000n;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// ✅ ERC20:全部转出,不需要留余额
|
|
324
|
+
// executeBatch: 利润转给利润地址 + 归集金额转给目标地址
|
|
325
|
+
const token = String(params.tokenAddress || '').trim();
|
|
326
|
+
if (info.profitWei > 0n) {
|
|
327
|
+
const t1 = erc20Iface.encodeFunctionData('transfer', [PROFIT_CONFIG.RECIPIENT, info.profitWei]);
|
|
328
|
+
const t2 = erc20Iface.encodeFunctionData('transfer', [info.to, info.toWei]);
|
|
329
|
+
callData = encodeExecuteBatch([token, token], [0n, 0n], [t1, t2]);
|
|
330
|
+
callGasLimit = 260000n;
|
|
308
331
|
}
|
|
309
|
-
|
|
310
|
-
|
|
332
|
+
else {
|
|
333
|
+
const transfer = erc20Iface.encodeFunctionData('transfer', [info.to, info.amountWei]);
|
|
334
|
+
callData = encodeExecute(token, 0n, transfer);
|
|
335
|
+
callGasLimit = 200000n;
|
|
311
336
|
}
|
|
312
|
-
|
|
313
|
-
const t1 = erc20Iface.encodeFunctionData('transfer', [PROFIT_CONFIG.RECIPIENT, profitWei]);
|
|
314
|
-
const t2 = erc20Iface.encodeFunctionData('transfer', [to, toWei]);
|
|
315
|
-
return encodeExecuteBatch([token, token], [0n, 0n], [t1, t2]);
|
|
316
|
-
})();
|
|
337
|
+
}
|
|
317
338
|
const built = await aaManager.buildUserOpWithFixedGas({
|
|
318
339
|
ownerWallet: w,
|
|
319
|
-
sender,
|
|
340
|
+
sender: info.sender,
|
|
320
341
|
callData,
|
|
321
342
|
nonce,
|
|
322
343
|
initCode,
|
|
323
|
-
deployed: initCode === '0x',
|
|
324
|
-
fixedGas: { callGasLimit
|
|
344
|
+
deployed: initCode === '0x',
|
|
345
|
+
fixedGas: { callGasLimit },
|
|
325
346
|
});
|
|
326
347
|
unsigned.push(built.userOp);
|
|
327
348
|
opOwnerIndex.push(i);
|
package/dist/xlayer/bundle.d.ts
CHANGED
|
@@ -92,19 +92,19 @@ export declare class BundleExecutor {
|
|
|
92
92
|
*
|
|
93
93
|
* 目标:对齐 BSC `flapBundleCreateToDex` 的逻辑,但适配 XLayer AA (EIP-4337)
|
|
94
94
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
95
|
+
* ✅ 所有操作合并到一个 handleOps 中原子执行:
|
|
96
|
+
*
|
|
97
|
+
* handleOps([
|
|
98
|
+
* Op 1: `newTokenV4` (发币) - Payer 发起
|
|
99
|
+
* Ops 2..N: `swapExactInput` (内盘买入) - 多个 Curve Buyer 发起
|
|
100
|
+
* Ops N+1..M: `swapExactETHForTokens` (外盘买入,可选) - 多个 DEX Buyer 发起
|
|
101
|
+
* Op M+1: 利润转账 (可选) - Payer 发起
|
|
102
|
+
* ])
|
|
103
|
+
*
|
|
104
|
+
* 注意:最后一笔内盘买入通常触发毕业,GasLimit 设为 8,000,000
|
|
105
105
|
*
|
|
106
106
|
* @param params - 签名参数
|
|
107
|
-
* @returns
|
|
107
|
+
* @returns 签名后的交易列表及元数据(只有一个 handleOps 交易)
|
|
108
108
|
*/
|
|
109
109
|
bundleCreateToDexSign(params: BundleCreateToDexSignParams): Promise<BundleCreateToDexSignResult>;
|
|
110
110
|
/**
|
package/dist/xlayer/bundle.js
CHANGED
|
@@ -1492,19 +1492,19 @@ export class BundleExecutor {
|
|
|
1492
1492
|
*
|
|
1493
1493
|
* 目标:对齐 BSC `flapBundleCreateToDex` 的逻辑,但适配 XLayer AA (EIP-4337)
|
|
1494
1494
|
*
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1495
|
+
* ✅ 所有操作合并到一个 handleOps 中原子执行:
|
|
1496
|
+
*
|
|
1497
|
+
* handleOps([
|
|
1498
|
+
* Op 1: `newTokenV4` (发币) - Payer 发起
|
|
1499
|
+
* Ops 2..N: `swapExactInput` (内盘买入) - 多个 Curve Buyer 发起
|
|
1500
|
+
* Ops N+1..M: `swapExactETHForTokens` (外盘买入,可选) - 多个 DEX Buyer 发起
|
|
1501
|
+
* Op M+1: 利润转账 (可选) - Payer 发起
|
|
1502
|
+
* ])
|
|
1503
|
+
*
|
|
1504
|
+
* 注意:最后一笔内盘买入通常触发毕业,GasLimit 设为 8,000,000
|
|
1505
1505
|
*
|
|
1506
1506
|
* @param params - 签名参数
|
|
1507
|
-
* @returns
|
|
1507
|
+
* @returns 签名后的交易列表及元数据(只有一个 handleOps 交易)
|
|
1508
1508
|
*/
|
|
1509
1509
|
async bundleCreateToDexSign(params) {
|
|
1510
1510
|
const { tokenInfo, tokenAddress, payerPrivateKey, curveBuyerPrivateKeys, curveBuyAmounts, enableDexBuy = false, dexBuyerPrivateKeys = [], dexBuyAmounts = [], config = {} } = params;
|
|
@@ -1562,7 +1562,7 @@ export class BundleExecutor {
|
|
|
1562
1562
|
// ✅ 预计算所有买入金额
|
|
1563
1563
|
const curveBuyData = curveBuyerWallets.map((wallet, i) => {
|
|
1564
1564
|
const buyWei = parseOkb(curveBuyAmounts[i]);
|
|
1565
|
-
const gasLimit =
|
|
1565
|
+
const gasLimit = 8000000n; // 统一给 800W,不再区分是否最后一笔
|
|
1566
1566
|
return { wallet, info: curveBuyerInfos[i], buyWei, gasLimit };
|
|
1567
1567
|
});
|
|
1568
1568
|
totalCurveBuyWei = curveBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
|
|
@@ -1585,50 +1585,9 @@ export class BundleExecutor {
|
|
|
1585
1585
|
const signedBuyOp = await aaManager.signUserOp(buyOpRes.userOp, wallet);
|
|
1586
1586
|
return signedBuyOp.userOp;
|
|
1587
1587
|
});
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
//
|
|
1591
|
-
const feeData = await provider.getFeeData();
|
|
1592
|
-
const gasPrice = feeData.gasPrice ?? 100000000n;
|
|
1593
|
-
const chainId = (await provider.getNetwork()).chainId;
|
|
1594
|
-
let currentNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
|
|
1595
|
-
const DEFAULT_PREFUND_ESTIMATE = parseOkb('0.002'); // 预估每个 UserOp 的 prefund
|
|
1596
|
-
const BUFFER_WEI = parseOkb('0.0005'); // 缓冲金额
|
|
1597
|
-
for (let i = 0; i < curveBuyerWallets.length; i++) {
|
|
1598
|
-
const buyerSender = curveBuyerInfos[i].sender;
|
|
1599
|
-
const buyWei = curveBuyData[i].buyWei;
|
|
1600
|
-
// 计算需要转入的金额:买入金额 + prefund + 缓冲
|
|
1601
|
-
const requiredAmount = buyWei + DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI;
|
|
1602
|
-
// 检查买家 AA 账户当前余额
|
|
1603
|
-
const currentBalance = await provider.getBalance(buyerSender);
|
|
1604
|
-
if (currentBalance < requiredAmount) {
|
|
1605
|
-
const transferAmount = requiredAmount - currentBalance;
|
|
1606
|
-
console.log(`[内盘买家${i + 1}] 向 AA 账户 ${buyerSender} 转入 ${formatOkb(transferAmount)} OKB`);
|
|
1607
|
-
const fundTxRequest = {
|
|
1608
|
-
to: buyerSender,
|
|
1609
|
-
value: transferAmount,
|
|
1610
|
-
nonce: currentNonce,
|
|
1611
|
-
gasLimit: 21000n,
|
|
1612
|
-
gasPrice,
|
|
1613
|
-
chainId
|
|
1614
|
-
};
|
|
1615
|
-
const signedFundTx = await payerWallet.signTransaction(fundTxRequest);
|
|
1616
|
-
signedTransactions.push(signedFundTx);
|
|
1617
|
-
currentNonce++;
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
// 签名第一个 handleOps
|
|
1621
|
-
const signedMainTx = await this.signHandleOpsTx({
|
|
1622
|
-
ops: ops1,
|
|
1623
|
-
payerWallet: payerWallet,
|
|
1624
|
-
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1625
|
-
nonce: currentNonce,
|
|
1626
|
-
gasLimit: effConfig.gasLimit,
|
|
1627
|
-
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1628
|
-
});
|
|
1629
|
-
signedTransactions.push(signedMainTx);
|
|
1630
|
-
currentNonce++;
|
|
1631
|
-
// --- 4. 构建外盘买入 handleOps (如果启用) ---
|
|
1588
|
+
// ✅ 使用 allOps 收集所有 UserOps,最终合并到一个 handleOps 中
|
|
1589
|
+
const allOps = [...ops1, ...signedCurveBuyOps];
|
|
1590
|
+
// --- 4. 构建外盘买入 Ops (如果启用) ---
|
|
1632
1591
|
if (enableDexBuy && dexBuyerPrivateKeys.length > 0) {
|
|
1633
1592
|
const dexBuyerWallets = dexBuyerPrivateKeys.map(pk => createWallet(pk, config));
|
|
1634
1593
|
const dexBuyerInfos = await mapWithConcurrency(dexBuyerWallets, 5, async (w) => {
|
|
@@ -1636,7 +1595,6 @@ export class BundleExecutor {
|
|
|
1636
1595
|
nonceMap.init(info.sender, info.nonce);
|
|
1637
1596
|
return info;
|
|
1638
1597
|
});
|
|
1639
|
-
const ops2 = [];
|
|
1640
1598
|
const deadline = Math.floor(Date.now() / 1000) + 1200; // 20 min
|
|
1641
1599
|
const dexType = (params.lpFeeProfile !== undefined && params.lpFeeProfile >= 0) ? 'V3' : 'V2';
|
|
1642
1600
|
// ✅ 预计算所有外盘买入金额
|
|
@@ -1645,31 +1603,7 @@ export class BundleExecutor {
|
|
|
1645
1603
|
return { wallet, info: dexBuyerInfos[i], buyWei };
|
|
1646
1604
|
});
|
|
1647
1605
|
totalDexBuyWei = dexBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
|
|
1648
|
-
//
|
|
1649
|
-
for (let i = 0; i < dexBuyerWallets.length; i++) {
|
|
1650
|
-
const buyerSender = dexBuyerInfos[i].sender;
|
|
1651
|
-
const buyWei = dexBuyData[i].buyWei;
|
|
1652
|
-
// 计算需要转入的金额:买入金额 + prefund + 缓冲
|
|
1653
|
-
const requiredAmount = buyWei + DEFAULT_PREFUND_ESTIMATE + BUFFER_WEI;
|
|
1654
|
-
// 检查买家 AA 账户当前余额
|
|
1655
|
-
const dexBuyerBalance = await provider.getBalance(buyerSender);
|
|
1656
|
-
if (dexBuyerBalance < requiredAmount) {
|
|
1657
|
-
const transferAmount = requiredAmount - dexBuyerBalance;
|
|
1658
|
-
console.log(`[外盘买家${i + 1}] 向 AA 账户 ${buyerSender} 转入 ${formatOkb(transferAmount)} OKB`);
|
|
1659
|
-
const fundTxRequest = {
|
|
1660
|
-
to: buyerSender,
|
|
1661
|
-
value: transferAmount,
|
|
1662
|
-
nonce: currentNonce,
|
|
1663
|
-
gasLimit: 21000n,
|
|
1664
|
-
gasPrice,
|
|
1665
|
-
chainId
|
|
1666
|
-
};
|
|
1667
|
-
const signedFundTx = await payerWallet.signTransaction(fundTxRequest);
|
|
1668
|
-
signedTransactions.push(signedFundTx);
|
|
1669
|
-
currentNonce++;
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
// ✅ 并行构建和签名所有外盘买入 UserOps
|
|
1606
|
+
// ✅ 并行构建和签名所有外盘买入 UserOps(假设买家 AA 账户已预先充值)
|
|
1673
1607
|
const signedDexBuyOps = await mapWithConcurrency(dexBuyData, 5, async (data) => {
|
|
1674
1608
|
const { wallet, info, buyWei } = data;
|
|
1675
1609
|
// ✅ 外盘买入:使用 DEX Router 进行交换
|
|
@@ -1698,26 +1632,16 @@ export class BundleExecutor {
|
|
|
1698
1632
|
sender: info.sender,
|
|
1699
1633
|
callData: dexBuyCallData,
|
|
1700
1634
|
nonce: nonceMap.next(info.sender),
|
|
1701
|
-
initCode: '0x'
|
|
1702
|
-
deployed:
|
|
1635
|
+
initCode: info.deployed ? '0x' : (await aaManager.generateInitCode(wallet.address)),
|
|
1636
|
+
deployed: info.deployed,
|
|
1703
1637
|
fixedGas: { callGasLimit: 600000n }
|
|
1704
1638
|
});
|
|
1705
1639
|
const signedDexBuyOp = await aaManager.signUserOp(dexBuyOpRes.userOp, wallet);
|
|
1706
1640
|
return signedDexBuyOp.userOp;
|
|
1707
1641
|
});
|
|
1708
|
-
|
|
1709
|
-
const signedDexTx = await this.signHandleOpsTx({
|
|
1710
|
-
ops: ops2,
|
|
1711
|
-
payerWallet: payerWallet,
|
|
1712
|
-
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1713
|
-
nonce: currentNonce,
|
|
1714
|
-
gasLimit: effConfig.gasLimit,
|
|
1715
|
-
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1716
|
-
});
|
|
1717
|
-
signedTransactions.push(signedDexTx);
|
|
1718
|
-
currentNonce++;
|
|
1642
|
+
allOps.push(...signedDexBuyOps);
|
|
1719
1643
|
}
|
|
1720
|
-
// --- 5. 利润提取 (AA 内部 UserOp
|
|
1644
|
+
// --- 5. 利润提取 (AA 内部 UserOp,合并到同一个 handleOps) ---
|
|
1721
1645
|
let totalProfitWei = 0n;
|
|
1722
1646
|
if (profitSettings.extractProfit) {
|
|
1723
1647
|
totalProfitWei += calculateProfitWei(totalCurveBuyWei, profitSettings.profitBps);
|
|
@@ -1725,36 +1649,37 @@ export class BundleExecutor {
|
|
|
1725
1649
|
totalProfitWei += calculateProfitWei(totalDexBuyWei, profitSettings.profitBps);
|
|
1726
1650
|
}
|
|
1727
1651
|
if (totalProfitWei > 0n) {
|
|
1728
|
-
// ✅ 使用 Payer AA 账户发起利润转账 UserOp
|
|
1652
|
+
// ✅ 使用 Payer AA 账户发起利润转账 UserOp
|
|
1729
1653
|
const profitCallData = encodeExecute(profitSettings.profitRecipient, totalProfitWei, '0x');
|
|
1730
|
-
const
|
|
1731
|
-
const { userOp: profitOp, prefundWei: profitPrefund } = await aaManager.buildUserOpWithFixedGas({
|
|
1654
|
+
const { userOp: profitOp } = await aaManager.buildUserOpWithFixedGas({
|
|
1732
1655
|
ownerWallet: payerWallet,
|
|
1733
1656
|
sender: payerAccount.sender,
|
|
1734
1657
|
nonce: nonceMap.next(payerAccount.sender),
|
|
1735
|
-
initCode:
|
|
1658
|
+
initCode: '0x', // Payer 已在发币时部署
|
|
1736
1659
|
callData: profitCallData,
|
|
1737
|
-
deployed:
|
|
1660
|
+
deployed: true,
|
|
1738
1661
|
fixedGas: {
|
|
1739
1662
|
...(effConfig.fixedGas ?? {}),
|
|
1740
1663
|
callGasLimit: effConfig.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_WITHDRAW,
|
|
1741
1664
|
},
|
|
1742
1665
|
});
|
|
1743
|
-
// 确保 Payer AA 账户有足够余额支付利润转账
|
|
1744
|
-
await aaManager.ensureSenderBalance(payerWallet, payerAccount.sender, totalProfitWei + profitPrefund + parseOkb('0.0001'), 'profit-transfer-fund');
|
|
1745
1666
|
const signedProfitOp = await aaManager.signUserOp(profitOp, payerWallet);
|
|
1746
|
-
|
|
1747
|
-
const signedProfitHandleOpsTx = await this.signHandleOpsTx({
|
|
1748
|
-
ops: [signedProfitOp.userOp],
|
|
1749
|
-
payerWallet: payerWallet,
|
|
1750
|
-
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1751
|
-
nonce: currentNonce,
|
|
1752
|
-
gasLimit: effConfig.gasLimit,
|
|
1753
|
-
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1754
|
-
});
|
|
1755
|
-
signedTransactions.push(signedProfitHandleOpsTx);
|
|
1667
|
+
allOps.push(signedProfitOp.userOp);
|
|
1756
1668
|
}
|
|
1757
1669
|
}
|
|
1670
|
+
// ✅ 获取 Payer nonce(假设买家 AA 账户已预先充值)
|
|
1671
|
+
const currentNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
|
|
1672
|
+
// ✅ 签名唯一的 handleOps(包含:发币 + 内盘买入 + 外盘买入 + 利润转账)
|
|
1673
|
+
const signedMainTx = await this.signHandleOpsTx({
|
|
1674
|
+
ops: allOps,
|
|
1675
|
+
payerWallet: payerWallet,
|
|
1676
|
+
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1677
|
+
nonce: currentNonce,
|
|
1678
|
+
gasLimit: effConfig.gasLimit,
|
|
1679
|
+
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1680
|
+
});
|
|
1681
|
+
signedTransactions.push(signedMainTx);
|
|
1682
|
+
console.log(`[bundleCreateToDexSign] 合并到一个 handleOps: ${allOps.length} 个 UserOps(发币:1, 内盘:${curveBuyerWallets.length}, 外盘:${dexBuyerPrivateKeys.length}, 利润:${totalProfitWei > 0n ? 1 : 0})`);
|
|
1758
1683
|
return {
|
|
1759
1684
|
signedTransactions,
|
|
1760
1685
|
tokenAddress,
|