four-flap-meme-sdk 1.5.27 → 1.5.29
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/types.d.ts +3 -0
- package/dist/contracts/tm-bundle-merkle/utils.js +40 -32
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/xlayer/aa-account.d.ts +21 -0
- package/dist/xlayer/aa-account.js +52 -0
- package/dist/xlayer/bundle.d.ts +1 -44
- package/dist/xlayer/bundle.js +1 -396
- package/dist/xlayer/dex-bundle-swap.d.ts +30 -0
- package/dist/xlayer/dex-bundle-swap.js +295 -0
- package/dist/xlayer/index.d.ts +22 -5
- package/dist/xlayer/index.js +33 -17
- package/dist/xlayer/portal-bundle-swap.d.ts +26 -0
- package/dist/xlayer/portal-bundle-swap.js +277 -0
- package/dist/xlayer/types.d.ts +31 -0
- package/dist/xlayer/types.js +50 -1
- package/package.json +1 -1
|
@@ -284,6 +284,7 @@ export type DisperseMerkleResult = MerkleSignedResult;
|
|
|
284
284
|
export type SweepMerkleParams = {
|
|
285
285
|
sourcePrivateKeys: string[];
|
|
286
286
|
target: string;
|
|
287
|
+
targetPrivateKey?: string;
|
|
287
288
|
ratioPct?: number;
|
|
288
289
|
ratios?: number[];
|
|
289
290
|
amount?: AmountLike;
|
|
@@ -306,6 +307,8 @@ export type SweepMerkleParams = {
|
|
|
306
307
|
export type SweepSignParams = {
|
|
307
308
|
sourcePrivateKeys: string[];
|
|
308
309
|
target: string;
|
|
310
|
+
/** ✅ 新增:归集目标地址的私钥(用于支付利润,不提供则由归集金额最大的源钱包支付) */
|
|
311
|
+
targetPrivateKey?: string;
|
|
309
312
|
ratioPct?: number;
|
|
310
313
|
ratios?: number[];
|
|
311
314
|
amount?: AmountLike;
|
|
@@ -641,7 +641,7 @@ export async function disperseWithBundleMerkle(params) {
|
|
|
641
641
|
* ✅ 优化版:支持 startNonce 参数避免并行调用时的 nonce 冲突
|
|
642
642
|
*/
|
|
643
643
|
export async function sweepWithBundleMerkle(params) {
|
|
644
|
-
const { sourcePrivateKeys, target, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
|
|
644
|
+
const { sourcePrivateKeys, target, targetPrivateKey, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
|
|
645
645
|
// 快速返回空结果
|
|
646
646
|
if (!sourcePrivateKeys || sourcePrivateKeys.length === 0) {
|
|
647
647
|
return {
|
|
@@ -658,6 +658,8 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
658
658
|
});
|
|
659
659
|
const isNative = _isNativeTokenAddress(tokenAddress);
|
|
660
660
|
const txType = getTxType(config);
|
|
661
|
+
// ✅ 如果提供了 targetPrivateKey,创建 targetWallet 用于支付利润
|
|
662
|
+
const targetWallet = targetPrivateKey ? new Wallet(targetPrivateKey, provider) : null;
|
|
661
663
|
// 归集比例处理
|
|
662
664
|
const clamp = (n) => (typeof n === 'number' && Number.isFinite(n)
|
|
663
665
|
? Math.max(0, Math.min(100, Math.floor(n)))
|
|
@@ -787,17 +789,19 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
787
789
|
}
|
|
788
790
|
}
|
|
789
791
|
}
|
|
790
|
-
// ✅
|
|
792
|
+
// ✅ 第二步:生成归集交易
|
|
793
|
+
// ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
|
|
794
|
+
const useTargetAsPayer = targetWallet !== null;
|
|
795
|
+
const profitPayerWallet = useTargetAsPayer ? targetWallet : (maxSweepIndex >= 0 ? wallets[maxSweepIndex] : null);
|
|
791
796
|
// ✅ 先为支付者预留 nonce,确保 nonce 连续
|
|
792
797
|
let payerProfitNonce;
|
|
793
|
-
if (extractProfit && totalProfit > 0n &&
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
payerProfitNonce = nonces[1]; // 利润交易的 nonce
|
|
798
|
+
if (extractProfit && totalProfit > 0n && profitPayerWallet) {
|
|
799
|
+
const nonces = await nonceManager.getNextNonceBatch(profitPayerWallet, useTargetAsPayer ? 1 : 2);
|
|
800
|
+
payerProfitNonce = useTargetAsPayer ? nonces[0] : nonces[1]; // targetWallet 只需要 1 个 nonce
|
|
797
801
|
}
|
|
798
802
|
// ✅ 优化:批量获取所有钱包的 nonce(JSON-RPC 批量请求)
|
|
799
|
-
//
|
|
800
|
-
const walletsToSweep = wallets.filter((_, i) => sweepAmounts[i] > 0n && i !== maxSweepIndex);
|
|
803
|
+
// 过滤出需要归集的钱包(如果用 targetWallet 支付利润,则不排除 maxSweepIndex)
|
|
804
|
+
const walletsToSweep = wallets.filter((_, i) => sweepAmounts[i] > 0n && (useTargetAsPayer || i !== maxSweepIndex));
|
|
801
805
|
const nonces = walletsToSweep.length > 0
|
|
802
806
|
? await nonceManager.getNextNoncesForWallets(walletsToSweep)
|
|
803
807
|
: [];
|
|
@@ -807,8 +811,8 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
807
811
|
if (toSend <= 0n)
|
|
808
812
|
return null;
|
|
809
813
|
let actualToSend = toSend;
|
|
810
|
-
if (extractProfit) {
|
|
811
|
-
// ✅
|
|
814
|
+
if (extractProfit && !useTargetAsPayer) {
|
|
815
|
+
// ✅ 如果由源钱包支付利润,支付者扣除所有利润总和;其他钱包不扣利润,归集干净
|
|
812
816
|
if (i === maxSweepIndex && totalProfit > 0n) {
|
|
813
817
|
actualToSend = toSend - totalProfit; // 支付者扣除所有利润总和
|
|
814
818
|
}
|
|
@@ -816,9 +820,10 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
816
820
|
actualToSend = toSend; // 其他钱包不扣利润,归集全部
|
|
817
821
|
}
|
|
818
822
|
}
|
|
823
|
+
// ✅ 如果由 targetWallet 支付利润,所有源钱包都归集全部金额
|
|
819
824
|
// ✅ 支付者使用预留的第一个 nonce,其他钱包使用批量获取的 nonce
|
|
820
825
|
let nonce;
|
|
821
|
-
if (i === maxSweepIndex && payerProfitNonce !== undefined) {
|
|
826
|
+
if (!useTargetAsPayer && i === maxSweepIndex && payerProfitNonce !== undefined) {
|
|
822
827
|
nonce = payerProfitNonce - 1; // 使用预留的第一个 nonce
|
|
823
828
|
}
|
|
824
829
|
else {
|
|
@@ -838,11 +843,10 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
838
843
|
const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
|
|
839
844
|
signedTxs.push(...allTxs);
|
|
840
845
|
// ✅ 第三步:利润多跳转账(强制 2 跳中转)
|
|
841
|
-
if (extractProfit && totalProfit > 0n &&
|
|
842
|
-
const payerWallet = wallets[maxSweepIndex];
|
|
846
|
+
if (extractProfit && totalProfit > 0n && profitPayerWallet && payerProfitNonce !== undefined) {
|
|
843
847
|
const profitHopResult = await buildProfitHopTransactions({
|
|
844
848
|
provider,
|
|
845
|
-
payerWallet,
|
|
849
|
+
payerWallet: profitPayerWallet,
|
|
846
850
|
profitAmount: totalProfit,
|
|
847
851
|
profitRecipient: getProfitRecipient(),
|
|
848
852
|
hopCount: PROFIT_HOP_COUNT,
|
|
@@ -926,10 +930,15 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
926
930
|
if (extractProfit && totalProfit > 0n) {
|
|
927
931
|
nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
|
|
928
932
|
}
|
|
933
|
+
// ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
|
|
934
|
+
const useTargetAsPayerErc20 = targetWallet !== null;
|
|
935
|
+
const profitPayerWalletErc20 = useTargetAsPayerErc20 ? targetWallet : (maxSweepIndex >= 0 ? wallets[maxSweepIndex] : null);
|
|
929
936
|
// ✅ 如果需要提取利润,检查支付者是否有足够 BNB 支付利润转账的额外 gas
|
|
930
|
-
if (extractProfit && nativeProfitAmount > 0n &&
|
|
931
|
-
const payerBnbBalance =
|
|
932
|
-
|
|
937
|
+
if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20 && config.checkBnbForErc20NoHop) {
|
|
938
|
+
const payerBnbBalance = useTargetAsPayerErc20
|
|
939
|
+
? await provider.getBalance(target)
|
|
940
|
+
: (bnbBalances[maxSweepIndex] ?? 0n);
|
|
941
|
+
const payerNeedGas = (useTargetAsPayerErc20 ? 0n : finalGasLimit * gasPrice) + profitTxGas + nativeProfitAmount;
|
|
933
942
|
// 如果支付者 BNB 余额不足,跳过利润提取
|
|
934
943
|
if (payerBnbBalance < payerNeedGas) {
|
|
935
944
|
nativeProfitAmount = 0n; // 跳过利润提取
|
|
@@ -938,14 +947,13 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
938
947
|
// ✅ 第二步:生成归集交易(ERC20 归集不扣除代币,利润从 BNB 支付)
|
|
939
948
|
// ✅ 先为支付者预留 nonce,确保 nonce 连续
|
|
940
949
|
let payerProfitNonce;
|
|
941
|
-
if (extractProfit && nativeProfitAmount > 0n &&
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
payerProfitNonce = nonces[1]; // 利润交易的 nonce
|
|
950
|
+
if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20) {
|
|
951
|
+
const nonces = await nonceManager.getNextNonceBatch(profitPayerWalletErc20, useTargetAsPayerErc20 ? 1 : 2);
|
|
952
|
+
payerProfitNonce = useTargetAsPayerErc20 ? nonces[0] : nonces[1];
|
|
945
953
|
}
|
|
946
954
|
// ✅ 优化:批量获取所有钱包的 nonce(JSON-RPC 批量请求)
|
|
947
|
-
//
|
|
948
|
-
const walletsToSweepErc20 = wallets.filter((_, i) => sweepAmounts[i] > 0n && i !== maxSweepIndex);
|
|
955
|
+
// 过滤出需要归集的钱包(如果用 targetWallet 支付利润,则不排除 maxSweepIndex)
|
|
956
|
+
const walletsToSweepErc20 = wallets.filter((_, i) => sweepAmounts[i] > 0n && (useTargetAsPayerErc20 || i !== maxSweepIndex));
|
|
949
957
|
const noncesErc20 = walletsToSweepErc20.length > 0
|
|
950
958
|
? await nonceManager.getNextNoncesForWallets(walletsToSweepErc20)
|
|
951
959
|
: [];
|
|
@@ -958,7 +966,7 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
958
966
|
const actualToSend = toSend;
|
|
959
967
|
// ✅ 支付者使用预留的第一个 nonce,其他钱包使用批量获取的 nonce
|
|
960
968
|
let nonce;
|
|
961
|
-
if (i === maxSweepIndex && payerProfitNonce !== undefined) {
|
|
969
|
+
if (!useTargetAsPayerErc20 && i === maxSweepIndex && payerProfitNonce !== undefined) {
|
|
962
970
|
nonce = payerProfitNonce - 1; // 使用预留的第一个 nonce
|
|
963
971
|
}
|
|
964
972
|
else {
|
|
@@ -980,12 +988,11 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
980
988
|
const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
|
|
981
989
|
signedTxs.push(...allTxs);
|
|
982
990
|
// ✅ 第三步:利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
|
|
983
|
-
if (extractProfit && nativeProfitAmount > 0n &&
|
|
984
|
-
const payerWallet = wallets[maxSweepIndex];
|
|
991
|
+
if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20 && payerProfitNonce !== undefined) {
|
|
985
992
|
totalProfit = nativeProfitAmount; // 更新为原生代币利润
|
|
986
993
|
const profitHopResult = await buildProfitHopTransactions({
|
|
987
994
|
provider,
|
|
988
|
-
payerWallet,
|
|
995
|
+
payerWallet: profitPayerWalletErc20,
|
|
989
996
|
profitAmount: nativeProfitAmount,
|
|
990
997
|
profitRecipient: getProfitRecipient(),
|
|
991
998
|
hopCount: PROFIT_HOP_COUNT,
|
|
@@ -1326,7 +1333,7 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
1326
1333
|
}
|
|
1327
1334
|
// ========== 第7步:计算利润并添加利润转账 ==========
|
|
1328
1335
|
if (extractProfit && totalAmountBeforeProfit > 0n) {
|
|
1329
|
-
//
|
|
1336
|
+
// ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
|
|
1330
1337
|
let maxSweepIndex = -1;
|
|
1331
1338
|
let maxSweepAmount = 0n;
|
|
1332
1339
|
for (let i = 0; i < sweepAmounts.length; i++) {
|
|
@@ -1335,6 +1342,8 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
1335
1342
|
maxSweepIndex = i;
|
|
1336
1343
|
}
|
|
1337
1344
|
}
|
|
1345
|
+
const useTargetAsPayerHop = targetWallet !== null;
|
|
1346
|
+
const profitPayerWalletHop = useTargetAsPayerHop ? targetWallet : (maxSweepIndex >= 0 ? sourceWallets[maxSweepIndex] : null);
|
|
1338
1347
|
// 计算总代币利润
|
|
1339
1348
|
let totalTokenProfit = 0n;
|
|
1340
1349
|
for (let i = 0; i < sweepAmounts.length; i++) {
|
|
@@ -1355,12 +1364,11 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
1355
1364
|
totalProfit = nativeProfitAmount;
|
|
1356
1365
|
}
|
|
1357
1366
|
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
1358
|
-
if (nativeProfitAmount > 0n &&
|
|
1359
|
-
const
|
|
1360
|
-
const profitNonce = await nonceManager.getNextNonce(payerWallet);
|
|
1367
|
+
if (nativeProfitAmount > 0n && profitPayerWalletHop) {
|
|
1368
|
+
const profitNonce = await nonceManager.getNextNonce(profitPayerWalletHop);
|
|
1361
1369
|
const profitHopResult = await buildProfitHopTransactions({
|
|
1362
1370
|
provider,
|
|
1363
|
-
payerWallet,
|
|
1371
|
+
payerWallet: profitPayerWalletHop,
|
|
1364
1372
|
profitAmount: nativeProfitAmount,
|
|
1365
1373
|
profitRecipient: getProfitRecipient(),
|
|
1366
1374
|
hopCount: PROFIT_HOP_COUNT,
|
package/dist/index.d.ts
CHANGED
|
@@ -53,4 +53,4 @@ export { submitDirectToRpc, submitDirectToRpcSequential, // ✅ 新增:顺序
|
|
|
53
53
|
submitDirectToRpcParallel, type DirectSubmitConfig, type DirectSubmitResult, type DirectTxResult } from './contracts/tm-bundle-merkle/submit.js';
|
|
54
54
|
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
55
|
export * as XLayer from './xlayer/index.js';
|
|
56
|
-
export { bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell,
|
|
56
|
+
export { bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell, bundleSwapSign as xlayerBundleSwapSign, bundleBatchSwapSign as xlayerBundleBatchSwapSign, createBundleExecutor as xlayerCreateBundleExecutor, BundleExecutor as XLayerBundleExecutor, makeVolume as xlayerMakeVolume, singleRoundVolume as xlayerSingleRoundVolume, createVolumeExecutor as xlayerCreateVolumeExecutor, VolumeExecutor as XLayerVolumeExecutor, createDexExecutor as xlayerCreateDexExecutor, createDexQuery as xlayerCreateDexQuery, quoteOkbToToken as xlayerQuoteOkbToToken, quoteTokenToOkb as xlayerQuoteTokenToOkb, DexExecutor as XLayerDexExecutor, DexQuery as XLayerDexQuery, createAAAccountManager as xlayerCreateAAAccountManager, predictSender as xlayerPredictSender, createWallet as xlayerCreateWallet, AAAccountManager as XLayerAAAccountManager, generateAAWallets as xlayerGenerateAAWallets, generateAAWalletsFromMnemonic as xlayerGenerateAAWalletsFromMnemonic, predictSendersFromPrivateKeys as xlayerPredictSendersFromPrivateKeys, createBundlerClient as xlayerCreateBundlerClient, BundlerClient as XLayerBundlerClient, createPortalQuery as xlayerCreatePortalQuery, PortalQuery as XLayerPortalQuery, encodeBuyCall as xlayerEncodeBuyCall, encodeSellCall as xlayerEncodeSellCall, encodeApproveCall as xlayerEncodeApproveCall, parseOkb as xlayerParseOkb, formatOkb as xlayerFormatOkb, XLAYER_CHAIN_ID, FLAP_PORTAL as XLAYER_FLAP_PORTAL, ENTRYPOINT_V06 as XLAYER_ENTRYPOINT, SIMPLE_ACCOUNT_FACTORY as XLAYER_FACTORY, PARTICLE_BUNDLER_URL as XLAYER_BUNDLER_URL, WOKB as XLAYER_WOKB, POTATOSWAP_V2_ROUTER as XLAYER_POTATOSWAP_ROUTER, type XLayerConfig, type BundleBuyParams as XLayerBundleBuyParams, type BundleSellParams as XLayerBundleSellParams, type BundleBuySellParams as XLayerBundleBuySellParams, type BundleSwapParams as XLayerBundleSwapParams, type BundleSwapSignParams as XLayerBundleSwapSignParams, type BundleBatchSwapParams as XLayerBundleBatchSwapParams, type BundleBatchSwapSignParams as XLayerBundleBatchSwapSignParams, type VolumeParams as XLayerVolumeParams, type BundleBuyResult as XLayerBundleBuyResult, type BundleSellResult as XLayerBundleSellResult, type BundleBuySellResult as XLayerBundleBuySellResult, type BundleSwapResult as XLayerBundleSwapResult, type BundleSwapSignResult as XLayerBundleSwapSignResult, type BundleBatchSwapResult as XLayerBundleBatchSwapResult, type BundleBatchSwapSignResult as XLayerBundleBatchSwapSignResult, type VolumeResult as XLayerVolumeResult, type HandleOpsResult as XLayerHandleOpsResult, type AAAccount as XLayerAAAccount, type UserOperation as XLayerUserOperation, type GeneratedAAWallet as XLayerGeneratedAAWallet, type GenerateAAWalletsParams as XLayerGenerateAAWalletsParams, type GenerateAAWalletsResult as XLayerGenerateAAWalletsResult, } from './xlayer/index.js';
|
package/dist/index.js
CHANGED
|
@@ -102,7 +102,7 @@ DIRECT_ROUTERS, } from './dex/index.js';
|
|
|
102
102
|
export * as XLayer from './xlayer/index.js';
|
|
103
103
|
export {
|
|
104
104
|
// 捆绑交易
|
|
105
|
-
bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell,
|
|
105
|
+
bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell, bundleSwapSign as xlayerBundleSwapSign, bundleBatchSwapSign as xlayerBundleBatchSwapSign, createBundleExecutor as xlayerCreateBundleExecutor, BundleExecutor as XLayerBundleExecutor,
|
|
106
106
|
// 刷量
|
|
107
107
|
makeVolume as xlayerMakeVolume, singleRoundVolume as xlayerSingleRoundVolume, createVolumeExecutor as xlayerCreateVolumeExecutor, VolumeExecutor as XLayerVolumeExecutor,
|
|
108
108
|
// DEX 交易
|
|
@@ -165,6 +165,27 @@ export declare class AAAccountManager {
|
|
|
165
165
|
useBundlerEstimate?: boolean;
|
|
166
166
|
callGasLimit?: bigint;
|
|
167
167
|
}): Promise<SignedUserOp>;
|
|
168
|
+
/**
|
|
169
|
+
* 获取 ERC20 代币余额
|
|
170
|
+
*/
|
|
171
|
+
getErc20Balance(tokenAddress: string, accountAddress: string): Promise<bigint>;
|
|
172
|
+
/**
|
|
173
|
+
* 获取 ERC20 代币授权额度
|
|
174
|
+
*/
|
|
175
|
+
getErc20Allowance(tokenAddress: string, owner: string, spender: string): Promise<bigint>;
|
|
176
|
+
/**
|
|
177
|
+
* 构建并签名 UserOperation(基于已有状态,支持 signOnly)
|
|
178
|
+
*/
|
|
179
|
+
buildUserOpWithState(params: {
|
|
180
|
+
ownerWallet: Wallet;
|
|
181
|
+
sender: string;
|
|
182
|
+
nonce: bigint;
|
|
183
|
+
initCode: string;
|
|
184
|
+
callData: string;
|
|
185
|
+
signOnly?: boolean;
|
|
186
|
+
gasPolicy?: GasPolicy;
|
|
187
|
+
fixedGas?: FixedGasConfig;
|
|
188
|
+
}): Promise<SignedUserOp>;
|
|
168
189
|
/**
|
|
169
190
|
* 确保 Sender 有足够的 OKB 余额
|
|
170
191
|
*
|
|
@@ -526,6 +526,58 @@ export class AAAccountManager {
|
|
|
526
526
|
const signed = await this.signUserOp(userOp, params.ownerWallet);
|
|
527
527
|
return { ...signed, prefundWei };
|
|
528
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* 获取 ERC20 代币余额
|
|
531
|
+
*/
|
|
532
|
+
async getErc20Balance(tokenAddress, accountAddress) {
|
|
533
|
+
const erc20 = new Contract(tokenAddress, ['function balanceOf(address) view returns (uint256)'], this.provider);
|
|
534
|
+
return await erc20.balanceOf(accountAddress);
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* 获取 ERC20 代币授权额度
|
|
538
|
+
*/
|
|
539
|
+
async getErc20Allowance(tokenAddress, owner, spender) {
|
|
540
|
+
const erc20 = new Contract(tokenAddress, ['function allowance(address,address) view returns (uint256)'], this.provider);
|
|
541
|
+
return await erc20.allowance(owner, spender);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* 构建并签名 UserOperation(基于已有状态,支持 signOnly)
|
|
545
|
+
*/
|
|
546
|
+
async buildUserOpWithState(params) {
|
|
547
|
+
const { ownerWallet, sender, nonce, initCode, callData, signOnly = false } = params;
|
|
548
|
+
let userOp;
|
|
549
|
+
let prefundWei;
|
|
550
|
+
// 如果是 signOnly,强制使用 fixed gas 策略,避免触发 eth_estimateUserOperationGas (可能会因为没钱而失败)
|
|
551
|
+
const policy = signOnly ? 'fixed' : (params.gasPolicy || this.defaultGasPolicy || 'fixed');
|
|
552
|
+
const buildParams = {
|
|
553
|
+
ownerWallet,
|
|
554
|
+
sender,
|
|
555
|
+
nonce,
|
|
556
|
+
initCode,
|
|
557
|
+
callData,
|
|
558
|
+
};
|
|
559
|
+
if (policy === 'fixed') {
|
|
560
|
+
const result = await this.buildUserOpWithFixedGas({
|
|
561
|
+
...buildParams,
|
|
562
|
+
deployed: initCode === '0x',
|
|
563
|
+
fixedGas: params.fixedGas || this.defaultFixedGas,
|
|
564
|
+
});
|
|
565
|
+
userOp = result.userOp;
|
|
566
|
+
prefundWei = result.prefundWei;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
// 默认用 localEstimate
|
|
570
|
+
const result = await this.buildUserOpWithLocalEstimate(buildParams);
|
|
571
|
+
userOp = result.userOp;
|
|
572
|
+
prefundWei = result.prefundWei;
|
|
573
|
+
}
|
|
574
|
+
// 只有非 signOnly 模式才执行 ensureSenderBalance
|
|
575
|
+
if (!signOnly) {
|
|
576
|
+
await this.ensureSenderBalance(ownerWallet, sender, prefundWei, 'buildUserOpWithState');
|
|
577
|
+
}
|
|
578
|
+
const signed = await this.signUserOp(userOp, ownerWallet);
|
|
579
|
+
return { ...signed, prefundWei };
|
|
580
|
+
}
|
|
529
581
|
/**
|
|
530
582
|
* 确保 Sender 有足够的 OKB 余额
|
|
531
583
|
*
|
package/dist/xlayer/bundle.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - 买卖一体化:买入 -> 授权 -> 卖出 -> 归集
|
|
8
8
|
* - OKB 归集:将 sender 的 OKB 转回 owner
|
|
9
9
|
*/
|
|
10
|
-
import type { XLayerConfig, BundleBuyParams, BundleBuyResult, BundleSellParams, BundleSellResult, BundleBuySellParams, BundleBuySellResult
|
|
10
|
+
import type { XLayerConfig, BundleBuyParams, BundleBuyResult, BundleSellParams, BundleSellResult, BundleBuySellParams, BundleBuySellResult } from './types.js';
|
|
11
11
|
import { AAAccountManager } from './aa-account.js';
|
|
12
12
|
import { PortalQuery } from './portal-ops.js';
|
|
13
13
|
/**
|
|
@@ -42,15 +42,6 @@ export declare class BundleExecutor {
|
|
|
42
42
|
*/
|
|
43
43
|
private signHandleOpsTx;
|
|
44
44
|
private getErc20Decimals;
|
|
45
|
-
/**
|
|
46
|
-
* 构建买入 UserOp(已知 sender/nonce/initCode 的版本)
|
|
47
|
-
*/
|
|
48
|
-
private buildBuyUserOpWithState;
|
|
49
|
-
/**
|
|
50
|
-
* 构建换手所需的 UserOps(approve? + sell + buy),并返回元数据
|
|
51
|
-
*/
|
|
52
|
-
private buildSwapOps;
|
|
53
|
-
private buildBatchSwapOps;
|
|
54
45
|
/**
|
|
55
46
|
* 构建买入 UserOp
|
|
56
47
|
*/
|
|
@@ -94,24 +85,6 @@ export declare class BundleExecutor {
|
|
|
94
85
|
* 完整流程:买入 -> 授权 -> 卖出 -> 归集
|
|
95
86
|
*/
|
|
96
87
|
bundleBuySell(params: BundleBuySellParams): Promise<BundleBuySellResult>;
|
|
97
|
-
/**
|
|
98
|
-
* ✅ 捆绑换手(AA):卖方卖出 → 买方买入,同一笔 handleOps 原子执行
|
|
99
|
-
*/
|
|
100
|
-
bundleSwap(params: BundleSwapParams): Promise<BundleSwapResult>;
|
|
101
|
-
/**
|
|
102
|
-
* ✅ 捆绑换手(AA,仅签名):返回 raw signed tx 列表(像 BSC 捆绑一样交给后端提交)
|
|
103
|
-
* - signedTransactions[0] = handleOps tx(payer 签名)
|
|
104
|
-
* - 如果传入 routeAddress,则 signedTransactions[1] = tailTx(nonce+1)
|
|
105
|
-
*/
|
|
106
|
-
bundleSwapSign(params: BundleSwapSignParams): Promise<BundleSwapSignResult>;
|
|
107
|
-
/**
|
|
108
|
-
* ✅ 批量捆绑换手(AA):一卖多买,同一笔 handleOps 原子执行
|
|
109
|
-
*/
|
|
110
|
-
bundleBatchSwap(params: BundleBatchSwapParams): Promise<BundleBatchSwapResult>;
|
|
111
|
-
/**
|
|
112
|
-
* ✅ 批量捆绑换手(AA,仅签名)
|
|
113
|
-
*/
|
|
114
|
-
bundleBatchSwapSign(params: BundleBatchSwapSignParams): Promise<BundleBatchSwapSignResult>;
|
|
115
88
|
}
|
|
116
89
|
/**
|
|
117
90
|
* 创建捆绑交易执行器
|
|
@@ -129,19 +102,3 @@ export declare function bundleSell(params: BundleSellParams): Promise<BundleSell
|
|
|
129
102
|
* 快速捆绑买卖
|
|
130
103
|
*/
|
|
131
104
|
export declare function bundleBuySell(params: BundleBuySellParams): Promise<BundleBuySellResult>;
|
|
132
|
-
/**
|
|
133
|
-
* 快速捆绑换手(链上执行)
|
|
134
|
-
*/
|
|
135
|
-
export declare function bundleSwap(params: BundleSwapParams): Promise<BundleSwapResult>;
|
|
136
|
-
/**
|
|
137
|
-
* 快速捆绑换手(仅签名,返回 raw signed tx)
|
|
138
|
-
*/
|
|
139
|
-
export declare function bundleSwapSign(params: BundleSwapSignParams): Promise<BundleSwapSignResult>;
|
|
140
|
-
/**
|
|
141
|
-
* 快速批量捆绑换手(链上执行)
|
|
142
|
-
*/
|
|
143
|
-
export declare function bundleBatchSwap(params: BundleBatchSwapParams): Promise<BundleBatchSwapResult>;
|
|
144
|
-
/**
|
|
145
|
-
* 快速批量捆绑换手(仅签名)
|
|
146
|
-
*/
|
|
147
|
-
export declare function bundleBatchSwapSign(params: BundleBatchSwapSignParams): Promise<BundleBatchSwapSignResult>;
|