four-flap-meme-sdk 1.5.96 → 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 +65 -8
- 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';
|
|
@@ -1569,9 +1569,11 @@ export class BundleExecutor {
|
|
|
1569
1569
|
});
|
|
1570
1570
|
totalCurveBuyWei = curveBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
|
|
1571
1571
|
// ✅ 并行构建和签名所有内盘买入 UserOps
|
|
1572
|
+
// ✅ 使用 encodeBuyCallV3(支持 extensionData),与 V4 代币创建保持一致
|
|
1573
|
+
const extensionData = params.extensionData ?? '0x';
|
|
1572
1574
|
const signedCurveBuyOps = await mapWithConcurrency(curveBuyData, 5, async (data) => {
|
|
1573
1575
|
const { wallet, info, buyWei, gasLimit } = data;
|
|
1574
|
-
const buyData =
|
|
1576
|
+
const buyData = encodeBuyCallV3(tokenAddress, buyWei, 0n, extensionData);
|
|
1575
1577
|
const buyCallData = encodeExecute(FLAP_PORTAL, buyWei, buyData);
|
|
1576
1578
|
const buyOpRes = await aaManager.buildUserOpWithFixedGas({
|
|
1577
1579
|
ownerWallet: wallet,
|
|
@@ -1586,17 +1588,48 @@ export class BundleExecutor {
|
|
|
1586
1588
|
return signedBuyOp.userOp;
|
|
1587
1589
|
});
|
|
1588
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
|
+
}
|
|
1589
1622
|
// 签名第一个 handleOps
|
|
1590
|
-
const startNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
|
|
1591
1623
|
const signedMainTx = await this.signHandleOpsTx({
|
|
1592
1624
|
ops: ops1,
|
|
1593
1625
|
payerWallet: payerWallet,
|
|
1594
1626
|
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1595
|
-
nonce:
|
|
1627
|
+
nonce: currentNonce,
|
|
1596
1628
|
gasLimit: effConfig.gasLimit,
|
|
1597
1629
|
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1598
1630
|
});
|
|
1599
1631
|
signedTransactions.push(signedMainTx);
|
|
1632
|
+
currentNonce++;
|
|
1600
1633
|
// --- 4. 构建外盘买入 handleOps (如果启用) ---
|
|
1601
1634
|
if (enableDexBuy && dexBuyerPrivateKeys.length > 0) {
|
|
1602
1635
|
const dexBuyerWallets = dexBuyerPrivateKeys.map(pk => createWallet(pk, config));
|
|
@@ -1614,10 +1647,34 @@ export class BundleExecutor {
|
|
|
1614
1647
|
return { wallet, info: dexBuyerInfos[i], buyWei };
|
|
1615
1648
|
});
|
|
1616
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
|
+
}
|
|
1617
1674
|
// ✅ 并行构建和签名所有外盘买入 UserOps
|
|
1618
1675
|
const signedDexBuyOps = await mapWithConcurrency(dexBuyData, 5, async (data) => {
|
|
1619
1676
|
const { wallet, info, buyWei } = data;
|
|
1620
|
-
// ✅ 外盘买入:使用
|
|
1677
|
+
// ✅ 外盘买入:使用 DEX Router 进行交换
|
|
1621
1678
|
let swapData;
|
|
1622
1679
|
let routerAddress;
|
|
1623
1680
|
if (dexType === 'V3') {
|
|
@@ -1655,11 +1712,12 @@ export class BundleExecutor {
|
|
|
1655
1712
|
ops: ops2,
|
|
1656
1713
|
payerWallet: payerWallet,
|
|
1657
1714
|
beneficiary: params.beneficiary ?? payerWallet.address,
|
|
1658
|
-
nonce:
|
|
1715
|
+
nonce: currentNonce,
|
|
1659
1716
|
gasLimit: effConfig.gasLimit,
|
|
1660
1717
|
gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
|
|
1661
1718
|
});
|
|
1662
1719
|
signedTransactions.push(signedDexTx);
|
|
1720
|
+
currentNonce++;
|
|
1663
1721
|
}
|
|
1664
1722
|
// --- 5. 利润提取 (Direct EOA transfer) ---
|
|
1665
1723
|
let totalProfitWei = 0n;
|
|
@@ -1669,12 +1727,11 @@ export class BundleExecutor {
|
|
|
1669
1727
|
totalProfitWei += calculateProfitWei(totalDexBuyWei, profitSettings.profitBps);
|
|
1670
1728
|
}
|
|
1671
1729
|
if (totalProfitWei > 0n) {
|
|
1672
|
-
const profitTxNonce = startNonce + (enableDexBuy ? 2 : 1);
|
|
1673
1730
|
const signedProfitTx = await this.signProfitTransaction({
|
|
1674
1731
|
payerWallet,
|
|
1675
1732
|
profitWei: totalProfitWei,
|
|
1676
1733
|
recipient: profitSettings.profitRecipient,
|
|
1677
|
-
nonce:
|
|
1734
|
+
nonce: currentNonce
|
|
1678
1735
|
});
|
|
1679
1736
|
signedTransactions.push(signedProfitTx);
|
|
1680
1737
|
}
|