four-flap-meme-sdk 1.5.61 → 1.5.63

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.
@@ -131,7 +131,7 @@ export class BundleExecutor {
131
131
  /**
132
132
  * 执行 handleOps 并解析结果
133
133
  */
134
- async runHandleOps(label, ops, bundlerSigner, beneficiary) {
134
+ async runHandleOps(label, ops, bundlerSigner, beneficiary, overrides) {
135
135
  if (ops.length === 0) {
136
136
  console.log(`\n[${label}] 没有 ops,跳过`);
137
137
  return null;
@@ -142,7 +142,16 @@ export class BundleExecutor {
142
142
  console.log(`\n[${label}] 发送 handleOps,ops=${ops.length} ...`);
143
143
  // 使用 bundlerSigner 创建新的合约实例以调用 handleOps
144
144
  const entryPointWithSigner = new Contract(entryPointAddress, ENTRYPOINT_ABI, bundlerSigner);
145
- const tx = await entryPointWithSigner.handleOps(ops, beneficiary, { gasPrice: feeData.gasPrice ?? 100000000n });
145
+ // 优先使用手动指定的 gas 配置,其次使用实例全局配置中的配置,最后使用网络获取的值或默认值
146
+ const gasPrice = overrides?.gasPrice ??
147
+ (this.config.minGasPriceGwei ? ethers.parseUnits(this.config.minGasPriceGwei.toString(), 'gwei') : undefined) ??
148
+ feeData.gasPrice ??
149
+ 100000000n;
150
+ const gasLimit = overrides?.gasLimit ?? this.config.gasLimit;
151
+ const tx = await entryPointWithSigner.handleOps(ops, beneficiary, {
152
+ gasPrice,
153
+ ...(gasLimit ? { gasLimit } : {})
154
+ });
146
155
  console.log(`[${label}] txHash:`, tx.hash);
147
156
  const receipt = await tx.wait();
148
157
  console.log(`[${label}] mined block=${receipt.blockNumber} status=${receipt.status}`);
@@ -189,9 +198,12 @@ export class BundleExecutor {
189
198
  const epIface = new Interface(ENTRYPOINT_ABI);
190
199
  const data = epIface.encodeFunctionData('handleOps', [params.ops, params.beneficiary]);
191
200
  const feeData = await provider.getFeeData();
192
- const gasPrice = params.gasPrice ?? feeData.gasPrice ?? 100000000n;
201
+ const gasPrice = params.gasPrice ??
202
+ (this.config.minGasPriceGwei ? ethers.parseUnits(this.config.minGasPriceGwei.toString(), 'gwei') : undefined) ??
203
+ feeData.gasPrice ??
204
+ 100000000n;
193
205
  const nonce = params.nonce ?? await provider.getTransactionCount(params.payerWallet.address, 'pending');
194
- let gasLimit = params.gasLimit;
206
+ let gasLimit = params.gasLimit ?? this.config.gasLimit;
195
207
  if (!gasLimit) {
196
208
  try {
197
209
  const est = await provider.estimateGas({
@@ -675,14 +687,24 @@ export class BundleExecutor {
675
687
  }
676
688
  });
677
689
  const initCodes = accountInfos.map((ai, i) => ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address));
678
- const { userOps: buyUserOps, prefundWeis } = await this.aaManager.buildUserOpsWithBundlerEstimateBatch({
679
- ops: accountInfos.map((ai, i) => ({
690
+ // 使用固定 Gas 构建买入 UserOps(避免 Bundler 估算对未部署账户不准确)
691
+ const buyNonces = accountInfos.map((ai) => nonceMap.next(ai.sender));
692
+ const buyUserOpsBuilt = await mapWithConcurrency(accountInfos, 6, async (ai, i) => {
693
+ return this.aaManager.buildUserOpWithFixedGas({
694
+ ownerWallet: wallets[i],
680
695
  sender: ai.sender,
681
- nonce: nonceMap.next(ai.sender),
682
696
  callData: buyCallDatas[i],
697
+ nonce: buyNonces[i],
683
698
  initCode: initCodes[i],
684
- })),
699
+ deployed: ai.deployed,
700
+ fixedGas: {
701
+ ...(effConfig.fixedGas ?? {}),
702
+ callGasLimit: effConfig.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_BUY,
703
+ },
704
+ });
685
705
  });
706
+ const buyUserOps = buyUserOpsBuilt.map((r) => r.userOp);
707
+ const prefundWeis = buyUserOpsBuilt.map((r) => r.prefundWei);
686
708
  // 补足 prefund + 买入金额(使用扣除利润后的金额)
687
709
  await mapWithConcurrency(accountInfos, 6, async (ai, i) => {
688
710
  if (useNativeToken) {
@@ -726,7 +748,10 @@ export class BundleExecutor {
726
748
  }
727
749
  // 2. 执行买入 + 利润转账(同一笔 handleOps)
728
750
  const allBuyOps = [...buyOps, ...profitOps];
729
- const buyResult = await this.runHandleOps('buyBundle', allBuyOps, bundlerSigner, beneficiary);
751
+ const buyResult = await this.runHandleOps('buyBundle', allBuyOps, bundlerSigner, beneficiary, {
752
+ gasLimit: effConfig.gasLimit,
753
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
754
+ });
730
755
  if (!buyResult) {
731
756
  throw new Error('买入交易失败');
732
757
  }
@@ -825,7 +850,11 @@ export class BundleExecutor {
825
850
  });
826
851
  sellOps.push(...signedSells);
827
852
  }
828
- const sellResult = await this.runHandleOps('sellBundle', sellOps, bundlerSigner, beneficiary);
853
+ const effConfig = { ...(this.config ?? {}), ...(config ?? {}) };
854
+ const sellResult = await this.runHandleOps('sellBundle', sellOps, bundlerSigner, beneficiary, {
855
+ gasLimit: effConfig.gasLimit,
856
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
857
+ });
829
858
  if (!sellResult) {
830
859
  throw new Error('卖出交易失败');
831
860
  }
@@ -874,7 +903,10 @@ export class BundleExecutor {
874
903
  withdrawOps.push(op);
875
904
  }
876
905
  if (withdrawOps.length > 0) {
877
- withdrawResult = await this.runHandleOps('withdrawBundle', withdrawOps, bundlerSigner, beneficiary) ?? undefined;
906
+ withdrawResult = await this.runHandleOps('withdrawBundle', withdrawOps, bundlerSigner, beneficiary, {
907
+ gasLimit: effConfig.gasLimit,
908
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
909
+ }) ?? undefined;
878
910
  }
879
911
  }
880
912
  return {
@@ -915,8 +947,8 @@ export class BundleExecutor {
915
947
  const nonceMap = new AANonceMap();
916
948
  for (const ai of accountInfos)
917
949
  nonceMap.init(ai.sender, ai.nonce);
918
- const effProfitCfgBuySell = { ...(this.config ?? {}), ...(config ?? {}) };
919
- const profitSettingsBuySell = resolveProfitSettings(effProfitCfgBuySell);
950
+ const effConfig = { ...(this.config ?? {}), ...(config ?? {}) };
951
+ const profitSettingsBuySell = resolveProfitSettings(effConfig);
920
952
  // ✅ 确定 inputToken:如果传入了 quoteToken 且非零地址,则使用它;否则使用零地址(原生代币)
921
953
  const inputToken = quoteToken && quoteToken !== ZERO_ADDRESS ? quoteToken : ZERO_ADDRESS;
922
954
  const useNativeToken = inputToken === ZERO_ADDRESS;
@@ -947,7 +979,7 @@ export class BundleExecutor {
947
979
  // ✅ ERC20 购买:获取代币利润等值的原生代币(OKB)报价
948
980
  let nativeBuyProfitAmount = totalBuyProfitWei; // 原生代币购买时直接使用
949
981
  if (!useNativeToken && profitSettingsBuySell.extractProfit && totalBuyProfitWei > 0n) {
950
- const dexQuery = new DexQuery(effProfitCfgBuySell);
982
+ const dexQuery = new DexQuery(effConfig);
951
983
  try {
952
984
  nativeBuyProfitAmount = await dexQuery.quoteTokenToOkb(totalBuyProfitWei, inputToken);
953
985
  }
@@ -1012,14 +1044,24 @@ export class BundleExecutor {
1012
1044
  }
1013
1045
  });
1014
1046
  const initCodes = accountInfos.map((ai, i) => (ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address)));
1015
- const { userOps: buyUserOps, prefundWeis } = await this.aaManager.buildUserOpsWithBundlerEstimateBatch({
1016
- ops: accountInfos.map((ai, i) => ({
1047
+ // 使用固定 Gas 构建买入 UserOps(避免 Bundler 估算对未部署账户不准确)
1048
+ const buyNonces = accountInfos.map((ai) => nonceMap.next(ai.sender));
1049
+ const buyUserOpsBuilt = await mapWithConcurrency(accountInfos, 6, async (ai, i) => {
1050
+ return this.aaManager.buildUserOpWithFixedGas({
1051
+ ownerWallet: wallets[i],
1017
1052
  sender: ai.sender,
1018
- nonce: nonceMap.next(ai.sender),
1019
1053
  callData: buyCallDatas[i],
1054
+ nonce: buyNonces[i],
1020
1055
  initCode: initCodes[i],
1021
- })),
1056
+ deployed: ai.deployed,
1057
+ fixedGas: {
1058
+ ...(effConfig.fixedGas ?? {}),
1059
+ callGasLimit: effConfig.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_BUY,
1060
+ },
1061
+ });
1022
1062
  });
1063
+ const buyUserOps = buyUserOpsBuilt.map((r) => r.userOp);
1064
+ const prefundWeis = buyUserOpsBuilt.map((r) => r.prefundWei);
1023
1065
  await mapWithConcurrency(accountInfos, 6, async (ai, i) => {
1024
1066
  const buyWei = buyWeis[i] ?? 0n;
1025
1067
  if (useNativeToken) {
@@ -1050,8 +1092,8 @@ export class BundleExecutor {
1050
1092
  callData: profitCallData,
1051
1093
  deployed: accountInfos[maxProfitIndex].deployed,
1052
1094
  fixedGas: {
1053
- ...(effProfitCfgBuySell.fixedGas ?? {}),
1054
- callGasLimit: effProfitCfgBuySell.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_WITHDRAW,
1095
+ ...(effConfig.fixedGas ?? {}),
1096
+ callGasLimit: effConfig.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_WITHDRAW,
1055
1097
  },
1056
1098
  });
1057
1099
  await this.aaManager.ensureSenderBalance(profitOwner, profitSender, nativeBuyProfitAmount + profitPrefund + parseOkb('0.0001'), `profit-transfer-fund`);
@@ -1059,7 +1101,10 @@ export class BundleExecutor {
1059
1101
  profitOps.push(signedProfit.userOp);
1060
1102
  }
1061
1103
  const allBuyOps = [...buyOps, ...profitOps];
1062
- const buyResult = await this.runHandleOps('buyBundle', allBuyOps, bundlerSigner, beneficiary);
1104
+ const buyResult = await this.runHandleOps('buyBundle', allBuyOps, bundlerSigner, beneficiary, {
1105
+ gasLimit: effConfig.gasLimit,
1106
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1107
+ });
1063
1108
  if (!buyResult) {
1064
1109
  throw new Error('买入交易失败');
1065
1110
  }
@@ -1087,7 +1132,10 @@ export class BundleExecutor {
1087
1132
  });
1088
1133
  for (const ops of sellPerWallet)
1089
1134
  sellOps.push(...ops);
1090
- const sellResult = await this.runHandleOps('sellBundle', sellOps, bundlerSigner, beneficiary);
1135
+ const sellResult = await this.runHandleOps('sellBundle', sellOps, bundlerSigner, beneficiary, {
1136
+ gasLimit: effConfig.gasLimit,
1137
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1138
+ });
1091
1139
  if (!sellResult) {
1092
1140
  throw new Error('卖出交易失败');
1093
1141
  }
@@ -1132,7 +1180,10 @@ export class BundleExecutor {
1132
1180
  withdrawOps.push(op);
1133
1181
  }
1134
1182
  if (withdrawOps.length > 0) {
1135
- withdrawResult = await this.runHandleOps('withdrawBundle', withdrawOps, bundlerSigner, beneficiary) ?? undefined;
1183
+ withdrawResult = await this.runHandleOps('withdrawBundle', withdrawOps, bundlerSigner, beneficiary, {
1184
+ gasLimit: effConfig.gasLimit,
1185
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1186
+ }) ?? undefined;
1136
1187
  if (profitSettingsBuySell.extractProfit) {
1137
1188
  const totalProfitForTail = nativeBuyProfitAmount + totalSellWithdrawProfitWei;
1138
1189
  if (totalProfitForTail > 0n) {
@@ -1356,7 +1407,9 @@ export class BundleExecutor {
1356
1407
  ops,
1357
1408
  payerWallet: payer,
1358
1409
  beneficiary: useBeneficiary,
1359
- nonce: startNonce
1410
+ nonce: startNonce,
1411
+ gasLimit: effConfig.gasLimit,
1412
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1360
1413
  });
1361
1414
  signedTransactions.push(signedMainTx);
1362
1415
  // === 2. 利润提取交易(独立的 EOA 转账)===
@@ -1415,7 +1468,8 @@ export class BundleExecutor {
1415
1468
  const payerAccount = await aaManager.getAccountInfo(payerWallet.address);
1416
1469
  const nonceMap = new AANonceMap();
1417
1470
  nonceMap.init(payerAccount.sender, payerAccount.nonce);
1418
- const profitSettings = resolveProfitSettings(config);
1471
+ const effConfig = { ...(this.config ?? {}), ...(config ?? {}) };
1472
+ const profitSettings = resolveProfitSettings(effConfig);
1419
1473
  const signedTransactions = [];
1420
1474
  let totalCurveBuyWei = 0n;
1421
1475
  let totalDexBuyWei = 0n;
@@ -1490,7 +1544,9 @@ export class BundleExecutor {
1490
1544
  ops: ops1,
1491
1545
  payerWallet: payerWallet,
1492
1546
  beneficiary: params.beneficiary ?? payerWallet.address,
1493
- nonce: startNonce
1547
+ nonce: startNonce,
1548
+ gasLimit: effConfig.gasLimit,
1549
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1494
1550
  });
1495
1551
  signedTransactions.push(signedMainTx);
1496
1552
  // --- 4. 构建外盘买入 handleOps (如果启用) ---
@@ -1533,7 +1589,9 @@ export class BundleExecutor {
1533
1589
  ops: ops2,
1534
1590
  payerWallet: payerWallet,
1535
1591
  beneficiary: params.beneficiary ?? payerWallet.address,
1536
- nonce: startNonce + 1
1592
+ nonce: startNonce + 1,
1593
+ gasLimit: effConfig.gasLimit,
1594
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1537
1595
  });
1538
1596
  signedTransactions.push(signedDexTx);
1539
1597
  }
@@ -1712,7 +1770,11 @@ export class BundleExecutor {
1712
1770
  };
1713
1771
  }
1714
1772
  // ============ 非 signOnly 模式:执行 handleOps ============
1715
- const approveResult = await this.runHandleOps('preApproveBundle', approveOps, bundlerSigner, beneficiary);
1773
+ const effConfig = { ...(this.config ?? {}), ...(config ?? {}) };
1774
+ const approveResult = await this.runHandleOps('preApproveBundle', approveOps, bundlerSigner, beneficiary, {
1775
+ gasLimit: effConfig.gasLimit,
1776
+ gasPrice: effConfig.minGasPriceGwei ? ethers.parseUnits(effConfig.minGasPriceGwei.toString(), 'gwei') : undefined
1777
+ });
1716
1778
  if (!approveResult) {
1717
1779
  throw new Error('预授权交易失败');
1718
1780
  }
@@ -76,6 +76,10 @@ export interface XLayerConfig {
76
76
  timeoutMs?: number;
77
77
  /** Gas 估算安全余量倍数 */
78
78
  gasLimitMultiplier?: number;
79
+ /** Payer handleOps 交易的 gasLimit(手动覆盖) */
80
+ gasLimit?: bigint;
81
+ /** Payer handleOps 交易的最小 gasPrice (Gwei) */
82
+ minGasPriceGwei?: number;
79
83
  /** 利润尾笔原生转账 gasLimit(默认 21000n) */
80
84
  profitTailGasLimit?: bigint;
81
85
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.61",
3
+ "version": "1.5.63",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",