hermes-swap 0.6.10 → 0.6.11

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.
@@ -132,6 +132,15 @@ var _Aggregator = class {
132
132
  }
133
133
  throw new Error(`No builder config for chain: ${chain}`);
134
134
  }
135
+ getDefaultBundleBlockCount(chain) {
136
+ if (!chain)
137
+ return 1;
138
+ if (this.builderConfigMap.has(chain))
139
+ return 3;
140
+ if (chain === import_types.ChainNameEnum.ETH && this.flashbotSigner)
141
+ return 3;
142
+ return 1;
143
+ }
135
144
  getSequencerRpcs(config) {
136
145
  const merged = {
137
146
  ..._Aggregator.DEFAULT_SEQUENCER_RPC_BY_CHAIN
@@ -175,6 +184,16 @@ var _Aggregator = class {
175
184
  ]
176
185
  };
177
186
  }
187
+ static getJsonRpcErrorMessage(data) {
188
+ var _a;
189
+ if (!(data == null ? void 0 : data.error))
190
+ return null;
191
+ if (typeof data.error === "string")
192
+ return data.error;
193
+ if (typeof ((_a = data.error) == null ? void 0 : _a.message) === "string")
194
+ return data.error.message;
195
+ return JSON.stringify(data.error);
196
+ }
178
197
  async sendBundle(chain, rawTxs, targetBlock, signer) {
179
198
  const builderCfg = this.getBuilderConfig(chain);
180
199
  const body = this.buildBundleRequestBody(builderCfg, rawTxs, targetBlock);
@@ -190,6 +209,14 @@ var _Aggregator = class {
190
209
  const ts = Date.now();
191
210
  try {
192
211
  const response = await import_axios.default.post(url, body, { headers });
212
+ const rpcErrorMessage = _Aggregator.getJsonRpcErrorMessage(response.data);
213
+ if (rpcErrorMessage) {
214
+ failed++;
215
+ const detail2 = `[FAIL] ${name}: ${rpcErrorMessage}`;
216
+ details.push(detail2);
217
+ _Aggregator.traceLog(chain, "error", `Builder[${name}] 发送失败, targetBlock=${targetBlock}, 耗时=${Date.now() - ts}ms, error=${rpcErrorMessage}, resp=${JSON.stringify(response.data)}`);
218
+ return;
219
+ }
193
220
  sent++;
194
221
  const detail = `[OK] ${name}`;
195
222
  details.push(detail);
@@ -555,7 +582,14 @@ var _Aggregator = class {
555
582
  }
556
583
  receipt = flashbotsReceipt;
557
584
  } else {
558
- receipt = await this.sendContractTx(params.chain, aggregator, "multiSwap", [params.user, params.amountInWeis, swapParamsList, params.minAmountOutLists, params.totalMinAmountOut], txReq, traceReq);
585
+ receipt = await this.sendContractTx(
586
+ params.chain,
587
+ aggregator,
588
+ "multiSwap",
589
+ [params.user, params.amountInWeis, swapParamsList, params.minAmountOutLists, params.totalMinAmountOut],
590
+ txReq,
591
+ traceReq
592
+ );
559
593
  txHash = receipt.hash;
560
594
  }
561
595
  let amountOutList = null;
@@ -971,9 +1005,12 @@ var _Aggregator = class {
971
1005
  const block = await provider.getBlock(blockNumber, true);
972
1006
  if (!block)
973
1007
  return false;
974
- if (block.transactions.some((hash) => hash === txHash))
975
- return true;
976
- return block.prefetchedTransactions.some((tx) => tx.hash === txHash);
1008
+ const normalizedHash = txHash.toLowerCase();
1009
+ const transactions = block.prefetchedTransactions ?? block.transactions;
1010
+ return transactions.some((tx) => {
1011
+ const hash = typeof tx === "string" ? tx : tx.hash;
1012
+ return (hash == null ? void 0 : hash.toLowerCase()) === normalizedHash;
1013
+ });
977
1014
  } catch {
978
1015
  return false;
979
1016
  }
@@ -1019,10 +1056,23 @@ var _Aggregator = class {
1019
1056
  cleanup();
1020
1057
  resolve(receipt);
1021
1058
  };
1059
+ const finishWithFallbackCheck = async () => {
1060
+ if (settled)
1061
+ return;
1062
+ try {
1063
+ const receipt = await provider.getTransactionReceipt(txHash);
1064
+ if (receipt && targetBlockSet.has(receipt.blockNumber)) {
1065
+ finish(receipt);
1066
+ return;
1067
+ }
1068
+ } catch {
1069
+ }
1070
+ finish(null);
1071
+ };
1022
1072
  const scheduleInspect = (fromBlock, toBlock) => {
1023
1073
  if (fromBlock > toBlock) {
1024
1074
  if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
1025
- finish(null);
1075
+ finishWithFallbackCheck();
1026
1076
  }
1027
1077
  return;
1028
1078
  }
@@ -1052,7 +1102,7 @@ var _Aggregator = class {
1052
1102
  return;
1053
1103
  }
1054
1104
  if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
1055
- finish(null);
1105
+ finishWithFallbackCheck();
1056
1106
  }
1057
1107
  };
1058
1108
  const onBlock = (blockNumber) => {
@@ -1065,7 +1115,7 @@ var _Aggregator = class {
1065
1115
  }
1066
1116
  if (fromBlock > toBlock) {
1067
1117
  if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
1068
- finish(null);
1118
+ finishWithFallbackCheck();
1069
1119
  }
1070
1120
  return;
1071
1121
  }
@@ -1083,7 +1133,8 @@ var _Aggregator = class {
1083
1133
  const toBlock = Math.min(latestBlock, maxTargetBlock);
1084
1134
  scheduleInspect(sortedTargetBlocks[0], toBlock);
1085
1135
  await inspectionChain;
1086
- finish(null);
1136
+ if (!settled)
1137
+ await finishWithFallbackCheck();
1087
1138
  }, _Aggregator.BUNDLE_INCLUSION_TIMEOUT_MS);
1088
1139
  provider.on("block", onBlock);
1089
1140
  provider.getBlockNumber().then(
@@ -1299,7 +1350,7 @@ var _Aggregator = class {
1299
1350
  }
1300
1351
  async submitBundleTx(chain, wallet, txReq, to, data, value, bundleBlockCount, traceReq) {
1301
1352
  if (bundleBlockCount == null) {
1302
- bundleBlockCount = this.builderConfigMap.has(chain) ? 3 : 1;
1353
+ bundleBlockCount = this.getDefaultBundleBlockCount(chain);
1303
1354
  }
1304
1355
  const builderCfg = this.getBuilderConfig(chain);
1305
1356
  if (builderCfg.authType === "flashbots" && !this.flashbotSigner) {
@@ -1354,12 +1405,36 @@ var _Aggregator = class {
1354
1405
  const ts = Date.now();
1355
1406
  try {
1356
1407
  const response = await import_axios.default.post(url, body, { headers, timeout: 3e3 });
1408
+ const rpcErrorMessage = _Aggregator.getJsonRpcErrorMessage(response.data);
1409
+ if (rpcErrorMessage) {
1410
+ totalFailed++;
1411
+ this.trace(
1412
+ chain,
1413
+ traceReq,
1414
+ "error",
1415
+ "hermes-submitBundleTx-builder-失败",
1416
+ `Builder[${name}] mev_sendBundle 发送失败, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, error=${rpcErrorMessage}, resp=${JSON.stringify(response.data)}`
1417
+ );
1418
+ return;
1419
+ }
1357
1420
  totalSent++;
1358
- this.trace(chain, traceReq, "log", "hermes-submitBundleTx-builder-成功", `Builder[${name}] mev_sendBundle 发送成功, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`);
1421
+ this.trace(
1422
+ chain,
1423
+ traceReq,
1424
+ "log",
1425
+ "hermes-submitBundleTx-builder-成功",
1426
+ `Builder[${name}] mev_sendBundle 发送成功, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`
1427
+ );
1359
1428
  } catch (error) {
1360
1429
  totalFailed++;
1361
1430
  const msg = (error == null ? void 0 : error.response) ? JSON.stringify(error.response.data) : (error == null ? void 0 : error.message) ?? String(error);
1362
- this.trace(chain, traceReq, "error", "hermes-submitBundleTx-builder-失败", `Builder[${name}] mev_sendBundle 发送失败, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, error=${msg}`);
1431
+ this.trace(
1432
+ chain,
1433
+ traceReq,
1434
+ "error",
1435
+ "hermes-submitBundleTx-builder-失败",
1436
+ `Builder[${name}] mev_sendBundle 发送失败, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, error=${msg}`
1437
+ );
1363
1438
  }
1364
1439
  })()
1365
1440
  ];
@@ -1373,6 +1448,18 @@ var _Aggregator = class {
1373
1448
  const ts = Date.now();
1374
1449
  try {
1375
1450
  const response = await import_axios.default.post(url, body, { headers, timeout: 3e3 });
1451
+ const rpcErrorMessage = _Aggregator.getJsonRpcErrorMessage(response.data);
1452
+ if (rpcErrorMessage) {
1453
+ totalFailed++;
1454
+ this.trace(
1455
+ chain,
1456
+ traceReq,
1457
+ "error",
1458
+ "hermes-submitBundleTx-builder-失败",
1459
+ `Builder[${name}] 发送失败, targetBlock=${block}, 耗时=${Date.now() - ts}ms, error=${rpcErrorMessage}, resp=${JSON.stringify(response.data)}`
1460
+ );
1461
+ return;
1462
+ }
1376
1463
  totalSent++;
1377
1464
  this.trace(chain, traceReq, "log", "hermes-submitBundleTx-builder-成功", `Builder[${name}] 发送成功, targetBlock=${block}, 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`);
1378
1465
  } catch (error) {
@@ -1410,13 +1497,7 @@ var _Aggregator = class {
1410
1497
  `Bundle上链确认, txHash=${receipt.hash}, blockNumber=${receipt.blockNumber}, 出块时间=${blockTs}, gasUsed=${receipt.gasUsed}, 等待耗时=${Date.now() - waitTs}ms`
1411
1498
  );
1412
1499
  } else {
1413
- this.trace(
1414
- chain,
1415
- traceReq,
1416
- "warn",
1417
- "hermes-submitBundleTx-等待结束",
1418
- `Bundle未在目标区块上链, txHash=${txHash}, 目标区块=[${targetBlocks.join(",")}], 等待耗时=${Date.now() - waitTs}ms`
1419
- );
1500
+ this.trace(chain, traceReq, "warn", "hermes-submitBundleTx-等待结束", `Bundle未在目标区块上链, txHash=${txHash}, 目标区块=[${targetBlocks.join(",")}], 等待耗时=${Date.now() - waitTs}ms`);
1420
1501
  }
1421
1502
  return { receipt, txHash, targetBlocks };
1422
1503
  }
@@ -1517,7 +1598,7 @@ var _Aggregator = class {
1517
1598
  return chain === import_types.ChainNameEnum.ETH && !!this.flashbotSigner;
1518
1599
  }
1519
1600
  stripCustomFields(txReq, chain) {
1520
- const defaultBlockCount = chain && this.builderConfigMap.has(chain) ? 3 : 1;
1601
+ const defaultBlockCount = this.getDefaultBundleBlockCount(chain);
1521
1602
  const { useBundle, bundleBlockCount = defaultBlockCount, trace, ...pureTxReq } = txReq;
1522
1603
  return { pureTxReq, bundleBlockCount: this.normalizeBundleBlockCount(bundleBlockCount) };
1523
1604
  }
@@ -1552,11 +1633,23 @@ var Aggregator = _Aggregator;
1552
1633
  Aggregator.DEFAULT_ETH_BUILDERS = {
1553
1634
  "beaverbuild.org": "https://rpc.beaverbuild.org",
1554
1635
  Titan: "https://rpc.titanbuilder.xyz",
1636
+ "Titan-EU": "https://eu.rpc.titanbuilder.xyz",
1555
1637
  flashbots: "https://relay.flashbots.net",
1556
1638
  // bloXroute: 'https://mev.api.blxrbdn.com', // 旧 api.blxrbdn.com 也行,需配置 Authorization 头
1557
- lightspeedbuilder: "https://rpc.lightspeedbuilder.info"
1639
+ "Builder+": "https://rpc.btcs.com",
1640
+ // BTCS 官方文档支持 eth_sendBundle
1641
+ turbobuilder: "https://rpc.turbobuilder.xyz",
1642
+ // 官方文档支持 eth_sendBundle
1643
+ lightspeedbuilder: "https://rpc.lightspeedbuilder.info",
1558
1644
  // 新增,实测直接可用
1559
- // buildernet: 'https://rpc.buildernet.org', // 新增,Flashbots 生态,需签名头(同 flashbots 格式)
1645
+ buildernet: "https://rpc.buildernet.org",
1646
+ // Flashbots 生态,使用 eth_sendBundle + X-Flashbots-Signature
1647
+ quasar: "https://rpc.quasar.win",
1648
+ // Quasar 文档支持 eth_sendBundle,认证沿用 X-Flashbots-Signature
1649
+ bananabuild: "https://rpc.bananabuild.org",
1650
+ // 官方文档支持 eth_sendBundle
1651
+ snailbuilder: "https://rpc.snailbuilder.sh"
1652
+ // 官网声明支持 Flashbots 同结构 bundle API
1560
1653
  // nfactorial: 'https://rpc.nfactorial.xyz', // 新增,支持 bundle rebate
1561
1654
  };
1562
1655
  Aggregator.DEFAULT_SEQUENCER_RPC_BY_CHAIN = {
@@ -26,9 +26,11 @@ declare class Aggregator {
26
26
  getAggregatorAddress(chain: ChainNameEnum): string;
27
27
  signRequestBody(body: unknown, signer: ethers.Wallet): Promise<string>;
28
28
  private getBuilderConfig;
29
+ private getDefaultBundleBlockCount;
29
30
  private getSequencerRpcs;
30
31
  private buildBundleRequestBody;
31
32
  private buildFlashbotsMevBundleRequestBody;
33
+ private static getJsonRpcErrorMessage;
32
34
  sendBundle(chain: ChainNameEnum, rawTxs: string[], targetBlock: number, signer?: ethers.Wallet): Promise<{
33
35
  sent: number;
34
36
  failed: number;
@@ -125,6 +125,9 @@ var Hermes = class {
125
125
  async getQuoterSupportContracts(chain) {
126
126
  return this.quoterClient.getQuoterSupportContracts(chain);
127
127
  }
128
+ destroy() {
129
+ this.providerClient.destroy();
130
+ }
128
131
  /**
129
132
  * 生成 swapAndBridge 的 calldata
130
133
  */
@@ -56,6 +56,7 @@ declare class Hermes {
56
56
  estimateGas(estimateType: IEstimateType, params: IBridgeParams | ISwapByPathParams | ISwapAndBridgeParams | IBatchMultiSwapParams): Promise<bigint>;
57
57
  getAggregatorSupportContracts(chain: ChainNameEnum): Promise<SupportContracts[]>;
58
58
  getQuoterSupportContracts(chain: ChainNameEnum): Promise<SupportContracts[]>;
59
+ destroy(): void;
59
60
  /**
60
61
  * 生成 swapAndBridge 的 calldata
61
62
  */
@@ -62,6 +62,16 @@ var Provider = class {
62
62
  }
63
63
  return this.walletMap.get(chain);
64
64
  }
65
+ destroy() {
66
+ var _a;
67
+ for (const provider of this.providerMap.values()) {
68
+ const rpcProvider = provider;
69
+ try {
70
+ (_a = rpcProvider.destroy) == null ? void 0 : _a.call(rpcProvider);
71
+ } catch {
72
+ }
73
+ }
74
+ }
65
75
  };
66
76
  var provider_default = Provider;
67
77
  // Annotate the CommonJS export names for ESM import in node:
@@ -8,6 +8,7 @@ declare class Provider {
8
8
  getProvider(chain: ChainNameEnum): ethers.Provider;
9
9
  checkIsEnoughToken(fromTokenAddress: string, userAddress: string, amountInWei: bigint, aggregatorAddress: string, wallet: ethers.Wallet): Promise<void>;
10
10
  getWallet(chain: ChainNameEnum): ethers.Wallet;
11
+ destroy(): void;
11
12
  }
12
13
  export default Provider;
13
14
  export { Provider };
@@ -26,9 +26,11 @@ declare class Aggregator {
26
26
  getAggregatorAddress(chain: ChainNameEnum): string;
27
27
  signRequestBody(body: unknown, signer: ethers.Wallet): Promise<string>;
28
28
  private getBuilderConfig;
29
+ private getDefaultBundleBlockCount;
29
30
  private getSequencerRpcs;
30
31
  private buildBundleRequestBody;
31
32
  private buildFlashbotsMevBundleRequestBody;
33
+ private static getJsonRpcErrorMessage;
32
34
  sendBundle(chain: ChainNameEnum, rawTxs: string[], targetBlock: number, signer?: ethers.Wallet): Promise<{
33
35
  sent: number;
34
36
  failed: number;