hermes-swap 0.6.10 → 0.7.0
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/cjs/aggregator.cjs +234 -69
- package/dist/cjs/aggregator.d.ts +2 -0
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/provider.cjs +10 -0
- package/dist/cjs/provider.d.ts +1 -0
- package/dist/cjs/types.cjs +54 -0
- package/dist/cjs/types.d.ts +55 -1
- package/dist/esm/aggregator.d.ts +2 -0
- package/dist/esm/aggregator.mjs +413 -222
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.mjs +6 -0
- package/dist/esm/provider.d.ts +1 -0
- package/dist/esm/provider.mjs +23 -0
- package/dist/esm/types.d.ts +55 -1
- package/dist/esm/types.mjs +54 -0
- package/package.json +2 -2
package/dist/cjs/aggregator.cjs
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
975
|
-
|
|
976
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1136
|
+
if (!settled)
|
|
1137
|
+
await finishWithFallbackCheck();
|
|
1087
1138
|
}, _Aggregator.BUNDLE_INCLUSION_TIMEOUT_MS);
|
|
1088
1139
|
provider.on("block", onBlock);
|
|
1089
1140
|
provider.getBlockNumber().then(
|
|
@@ -1102,31 +1153,66 @@ var _Aggregator = class {
|
|
|
1102
1153
|
);
|
|
1103
1154
|
});
|
|
1104
1155
|
}
|
|
1105
|
-
async sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq) {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1156
|
+
async sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq, abortSignal) {
|
|
1157
|
+
return await new Promise((resolve, reject) => {
|
|
1158
|
+
let settled = false;
|
|
1159
|
+
let finishedCount = 0;
|
|
1160
|
+
const failures = [];
|
|
1161
|
+
const cleanup = () => {
|
|
1162
|
+
abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", onAbort);
|
|
1163
|
+
};
|
|
1164
|
+
const finishResolve = () => {
|
|
1165
|
+
if (settled)
|
|
1166
|
+
return;
|
|
1167
|
+
settled = true;
|
|
1168
|
+
cleanup();
|
|
1169
|
+
resolve();
|
|
1170
|
+
};
|
|
1171
|
+
const finishReject = () => {
|
|
1172
|
+
if (settled)
|
|
1173
|
+
return;
|
|
1174
|
+
settled = true;
|
|
1175
|
+
cleanup();
|
|
1176
|
+
const detail = failures.map((result) => `${result.label}: ${result.msg ?? "unknown error"}`).join("; ");
|
|
1177
|
+
reject(new Error(`All broadcast channels failed for ${txHash}: ${detail}`));
|
|
1178
|
+
};
|
|
1179
|
+
const onAbort = () => {
|
|
1180
|
+
finishResolve();
|
|
1181
|
+
};
|
|
1182
|
+
if (abortSignal == null ? void 0 : abortSignal.aborted) {
|
|
1183
|
+
finishResolve();
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
abortSignal == null ? void 0 : abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
1187
|
+
for (const { label, send } of channels) {
|
|
1109
1188
|
const sendTs = Date.now();
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1189
|
+
send(abortSignal).then(
|
|
1190
|
+
() => {
|
|
1191
|
+
if (settled || (abortSignal == null ? void 0 : abortSignal.aborted))
|
|
1192
|
+
return;
|
|
1193
|
+
this.trace(chain, traceReq, "log", "hermes-broadcast-channel-成功", `广播${label} OK, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1194
|
+
finishResolve();
|
|
1195
|
+
},
|
|
1196
|
+
(err) => {
|
|
1197
|
+
var _a, _b, _c, _d, _e;
|
|
1198
|
+
if (settled || (abortSignal == null ? void 0 : abortSignal.aborted))
|
|
1199
|
+
return;
|
|
1200
|
+
const msg = ((_c = (_b = (_a = err == null ? void 0 : err.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) == null ? void 0 : _c.message) ?? ((_e = (_d = err == null ? void 0 : err.response) == null ? void 0 : _d.data) == null ? void 0 : _e.message) ?? (err == null ? void 0 : err.message) ?? String(err);
|
|
1201
|
+
if (_Aggregator.isBenignBroadcastError(msg)) {
|
|
1202
|
+
this.trace(chain, traceReq, "log", "hermes-broadcast-channel-已存在", `广播${label} already-known, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1203
|
+
finishResolve();
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
this.trace(chain, traceReq, "warn", "hermes-broadcast-channel-失败", `广播${label} 失败: ${msg}, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1207
|
+
failures.push({ label, msg });
|
|
1208
|
+
finishedCount += 1;
|
|
1209
|
+
if (finishedCount === channels.length) {
|
|
1210
|
+
finishReject();
|
|
1211
|
+
}
|
|
1119
1212
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
})
|
|
1124
|
-
);
|
|
1125
|
-
if (results.some((result) => result.ok)) {
|
|
1126
|
-
return;
|
|
1127
|
-
}
|
|
1128
|
-
const detail = results.map((result) => `${result.label}: ${result.msg ?? "unknown error"}`).join("; ");
|
|
1129
|
-
throw new Error(`All broadcast channels failed for ${txHash}: ${detail}`);
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1130
1216
|
}
|
|
1131
1217
|
raceForReceipt(chain, txHash, providers, ownedProviders = [], timeoutMs = _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq) {
|
|
1132
1218
|
return new Promise((resolve, reject) => {
|
|
@@ -1186,9 +1272,9 @@ var _Aggregator = class {
|
|
|
1186
1272
|
return null;
|
|
1187
1273
|
return {
|
|
1188
1274
|
label: `Sequencer[${new URL(sequencerUrl).hostname}]`,
|
|
1189
|
-
send: async () => {
|
|
1275
|
+
send: async (signal) => {
|
|
1190
1276
|
var _a;
|
|
1191
|
-
const resp = await import_axios.default.post(sequencerUrl, { jsonrpc: "2.0", id: 1, method: "eth_sendRawTransaction", params: [signedTx] }, { timeout: 5e3 });
|
|
1277
|
+
const resp = await import_axios.default.post(sequencerUrl, { jsonrpc: "2.0", id: 1, method: "eth_sendRawTransaction", params: [signedTx] }, { timeout: 5e3, signal });
|
|
1192
1278
|
if ((_a = resp.data) == null ? void 0 : _a.error) {
|
|
1193
1279
|
throw new Error(resp.data.error.message ?? JSON.stringify(resp.data.error));
|
|
1194
1280
|
}
|
|
@@ -1237,10 +1323,17 @@ var _Aggregator = class {
|
|
|
1237
1323
|
const providers = [{ provider: mainProvider2, label: "RPC[0/主]" }];
|
|
1238
1324
|
const sequencerChannel2 = this.buildSequencerChannel(chain, signedTx2);
|
|
1239
1325
|
const channels2 = [...providers.map(({ provider, label }) => ({ label, send: () => provider.broadcastTransaction(signedTx2) })), ...sequencerChannel2 ? [sequencerChannel2] : []];
|
|
1240
|
-
const
|
|
1241
|
-
|
|
1326
|
+
const broadcastAbortController2 = new AbortController();
|
|
1327
|
+
const receiptPromise2 = this.raceForReceipt(chain, txHash2, providers, [], _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq).finally(() => {
|
|
1328
|
+
broadcastAbortController2.abort();
|
|
1329
|
+
});
|
|
1330
|
+
const broadcastPromise2 = this.sendSignedTxToChannels(chain, signedTx2, txHash2, channels2, traceReq, broadcastAbortController2.signal);
|
|
1242
1331
|
this.trace(chain, traceReq, "log", "hermes-sendContractTx-等待确认", `并行广播后开始等待确认, txHash=${txHash2}`);
|
|
1243
|
-
const receipt2 = await
|
|
1332
|
+
const receipt2 = await Promise.race([
|
|
1333
|
+
receiptPromise2,
|
|
1334
|
+
broadcastPromise2.then(() => new Promise(() => {
|
|
1335
|
+
}))
|
|
1336
|
+
]);
|
|
1244
1337
|
const blockTs2 = await this.getBlockTimestampStr(mainProvider2, receipt2.blockNumber);
|
|
1245
1338
|
this.trace(
|
|
1246
1339
|
chain,
|
|
@@ -1279,11 +1372,18 @@ var _Aggregator = class {
|
|
|
1279
1372
|
const broadcastTs = Date.now();
|
|
1280
1373
|
const sequencerChannel = this.buildSequencerChannel(chain, signedTx);
|
|
1281
1374
|
const channels = [...allProviders.map(({ provider, label }) => ({ label, send: () => provider.broadcastTransaction(signedTx) })), ...sequencerChannel ? [sequencerChannel] : []];
|
|
1282
|
-
const
|
|
1375
|
+
const broadcastAbortController = new AbortController();
|
|
1376
|
+
const receiptPromise = this.raceForReceipt(chain, txHash, allProviders, ownedProviders, _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq).finally(() => {
|
|
1377
|
+
broadcastAbortController.abort();
|
|
1378
|
+
});
|
|
1379
|
+
const broadcastPromise = this.sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq, broadcastAbortController.signal);
|
|
1283
1380
|
this.trace(chain, traceReq, "log", "hermes-sendContractTx-RPC发送前", `多RPC广播准备发送, txHash=${txHash}`);
|
|
1284
|
-
await this.sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq);
|
|
1285
1381
|
this.trace(chain, traceReq, "log", "hermes-sendContractTx-等待确认", `多RPC广播后开始等待确认, txHash=${txHash}`);
|
|
1286
|
-
const receipt = await
|
|
1382
|
+
const receipt = await Promise.race([
|
|
1383
|
+
receiptPromise,
|
|
1384
|
+
broadcastPromise.then(() => new Promise(() => {
|
|
1385
|
+
}))
|
|
1386
|
+
]);
|
|
1287
1387
|
const blockTs = await this.getBlockTimestampStr(mainProvider, receipt.blockNumber);
|
|
1288
1388
|
this.trace(
|
|
1289
1389
|
chain,
|
|
@@ -1299,7 +1399,7 @@ var _Aggregator = class {
|
|
|
1299
1399
|
}
|
|
1300
1400
|
async submitBundleTx(chain, wallet, txReq, to, data, value, bundleBlockCount, traceReq) {
|
|
1301
1401
|
if (bundleBlockCount == null) {
|
|
1302
|
-
bundleBlockCount = this.
|
|
1402
|
+
bundleBlockCount = this.getDefaultBundleBlockCount(chain);
|
|
1303
1403
|
}
|
|
1304
1404
|
const builderCfg = this.getBuilderConfig(chain);
|
|
1305
1405
|
if (builderCfg.authType === "flashbots" && !this.flashbotSigner) {
|
|
@@ -1342,6 +1442,7 @@ var _Aggregator = class {
|
|
|
1342
1442
|
let totalSent = 0;
|
|
1343
1443
|
let totalFailed = 0;
|
|
1344
1444
|
const signer = builderCfg.authType === "flashbots" ? this.flashbotSigner : void 0;
|
|
1445
|
+
const builderAbortController = new AbortController();
|
|
1345
1446
|
const fireAndForget = builderEntries.flatMap(([name, url]) => {
|
|
1346
1447
|
if (name === "flashbots" && builderCfg.authType === "flashbots" && signer) {
|
|
1347
1448
|
return [
|
|
@@ -1353,13 +1454,43 @@ var _Aggregator = class {
|
|
|
1353
1454
|
};
|
|
1354
1455
|
const ts = Date.now();
|
|
1355
1456
|
try {
|
|
1356
|
-
const response = await import_axios.default.post(url, body, { headers, timeout: 3e3 });
|
|
1457
|
+
const response = await import_axios.default.post(url, body, { headers, timeout: 3e3, signal: builderAbortController.signal });
|
|
1458
|
+
if (builderAbortController.signal.aborted)
|
|
1459
|
+
return;
|
|
1460
|
+
const rpcErrorMessage = _Aggregator.getJsonRpcErrorMessage(response.data);
|
|
1461
|
+
if (rpcErrorMessage) {
|
|
1462
|
+
totalFailed++;
|
|
1463
|
+
this.trace(
|
|
1464
|
+
chain,
|
|
1465
|
+
traceReq,
|
|
1466
|
+
"error",
|
|
1467
|
+
"hermes-submitBundleTx-builder-失败",
|
|
1468
|
+
`Builder[${name}] mev_sendBundle 发送失败, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, error=${rpcErrorMessage}, resp=${JSON.stringify(response.data)}`
|
|
1469
|
+
);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1357
1472
|
totalSent++;
|
|
1358
|
-
|
|
1473
|
+
if (builderAbortController.signal.aborted)
|
|
1474
|
+
return;
|
|
1475
|
+
this.trace(
|
|
1476
|
+
chain,
|
|
1477
|
+
traceReq,
|
|
1478
|
+
"log",
|
|
1479
|
+
"hermes-submitBundleTx-builder-成功",
|
|
1480
|
+
`Builder[${name}] mev_sendBundle 发送成功, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`
|
|
1481
|
+
);
|
|
1359
1482
|
} catch (error) {
|
|
1483
|
+
if (builderAbortController.signal.aborted)
|
|
1484
|
+
return;
|
|
1360
1485
|
totalFailed++;
|
|
1361
1486
|
const msg = (error == null ? void 0 : error.response) ? JSON.stringify(error.response.data) : (error == null ? void 0 : error.message) ?? String(error);
|
|
1362
|
-
this.trace(
|
|
1487
|
+
this.trace(
|
|
1488
|
+
chain,
|
|
1489
|
+
traceReq,
|
|
1490
|
+
"error",
|
|
1491
|
+
"hermes-submitBundleTx-builder-失败",
|
|
1492
|
+
`Builder[${name}] mev_sendBundle 发送失败, targetBlocks=[${targetBlocks.join(",")}], 耗时=${Date.now() - ts}ms, error=${msg}`
|
|
1493
|
+
);
|
|
1363
1494
|
}
|
|
1364
1495
|
})()
|
|
1365
1496
|
];
|
|
@@ -1372,34 +1503,63 @@ var _Aggregator = class {
|
|
|
1372
1503
|
}
|
|
1373
1504
|
const ts = Date.now();
|
|
1374
1505
|
try {
|
|
1375
|
-
const response = await import_axios.default.post(url, body, { headers, timeout: 3e3 });
|
|
1506
|
+
const response = await import_axios.default.post(url, body, { headers, timeout: 3e3, signal: builderAbortController.signal });
|
|
1507
|
+
if (builderAbortController.signal.aborted)
|
|
1508
|
+
return;
|
|
1509
|
+
const rpcErrorMessage = _Aggregator.getJsonRpcErrorMessage(response.data);
|
|
1510
|
+
if (rpcErrorMessage) {
|
|
1511
|
+
totalFailed++;
|
|
1512
|
+
this.trace(
|
|
1513
|
+
chain,
|
|
1514
|
+
traceReq,
|
|
1515
|
+
"error",
|
|
1516
|
+
"hermes-submitBundleTx-builder-失败",
|
|
1517
|
+
`Builder[${name}] 发送失败, targetBlock=${block}, 耗时=${Date.now() - ts}ms, error=${rpcErrorMessage}, resp=${JSON.stringify(response.data)}`
|
|
1518
|
+
);
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1376
1521
|
totalSent++;
|
|
1522
|
+
if (builderAbortController.signal.aborted)
|
|
1523
|
+
return;
|
|
1377
1524
|
this.trace(chain, traceReq, "log", "hermes-submitBundleTx-builder-成功", `Builder[${name}] 发送成功, targetBlock=${block}, 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`);
|
|
1378
1525
|
} catch (error) {
|
|
1526
|
+
if (builderAbortController.signal.aborted)
|
|
1527
|
+
return;
|
|
1379
1528
|
totalFailed++;
|
|
1380
1529
|
const msg = (error == null ? void 0 : error.response) ? JSON.stringify(error.response.data) : (error == null ? void 0 : error.message) ?? String(error);
|
|
1381
1530
|
this.trace(chain, traceReq, "error", "hermes-submitBundleTx-builder-失败", `Builder[${name}] 发送失败, targetBlock=${block}, 耗时=${Date.now() - ts}ms, error=${msg}`);
|
|
1382
1531
|
}
|
|
1383
1532
|
});
|
|
1384
1533
|
});
|
|
1385
|
-
const
|
|
1386
|
-
const inclusionPromise = this.waitForBundleInclusion(provider, txHash, targetBlocks,
|
|
1534
|
+
const inclusionAbortController = new AbortController();
|
|
1535
|
+
const inclusionPromise = this.waitForBundleInclusion(provider, txHash, targetBlocks, inclusionAbortController.signal).finally(() => {
|
|
1536
|
+
builderAbortController.abort();
|
|
1537
|
+
});
|
|
1387
1538
|
const waitTs = Date.now();
|
|
1388
1539
|
this.trace(chain, traceReq, "log", "hermes-submitBundleTx-RPC发送前", `Bundle 请求开始发送, txHash=${txHash}, targetBlocks=[${targetBlocks.join(",")}]`);
|
|
1389
|
-
const
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
})
|
|
1540
|
+
const sendPromise = Promise.all(fireAndForget).then(() => {
|
|
1541
|
+
this.trace(
|
|
1542
|
+
chain,
|
|
1543
|
+
traceReq,
|
|
1544
|
+
"log",
|
|
1545
|
+
"hermes-submitBundleTx-RPC已发送",
|
|
1546
|
+
`Bundle发送完成, 成功=${totalSent}, 失败=${totalFailed}, 总请求=${fireAndForget.length}, 耗时=${Date.now() - sendBundleTs}ms, txHash=${txHash}`
|
|
1547
|
+
);
|
|
1548
|
+
return { totalSent, totalFailed };
|
|
1549
|
+
});
|
|
1550
|
+
const firstResult = await Promise.race([
|
|
1551
|
+
inclusionPromise.then((receipt2) => ({ kind: "receipt", receipt: receipt2 })),
|
|
1552
|
+
sendPromise.then((summary) => ({ kind: "sendDone", summary }))
|
|
1402
1553
|
]);
|
|
1554
|
+
let receipt;
|
|
1555
|
+
if (firstResult.kind === "receipt") {
|
|
1556
|
+
receipt = firstResult.receipt;
|
|
1557
|
+
} else {
|
|
1558
|
+
if (firstResult.summary.totalSent === 0) {
|
|
1559
|
+
inclusionAbortController.abort();
|
|
1560
|
+
}
|
|
1561
|
+
receipt = await inclusionPromise;
|
|
1562
|
+
}
|
|
1403
1563
|
if (receipt) {
|
|
1404
1564
|
const blockTs = await this.getBlockTimestampStr(provider, receipt.blockNumber);
|
|
1405
1565
|
this.trace(
|
|
@@ -1410,13 +1570,7 @@ var _Aggregator = class {
|
|
|
1410
1570
|
`Bundle上链确认, txHash=${receipt.hash}, blockNumber=${receipt.blockNumber}, 出块时间=${blockTs}, gasUsed=${receipt.gasUsed}, 等待耗时=${Date.now() - waitTs}ms`
|
|
1411
1571
|
);
|
|
1412
1572
|
} else {
|
|
1413
|
-
this.trace(
|
|
1414
|
-
chain,
|
|
1415
|
-
traceReq,
|
|
1416
|
-
"warn",
|
|
1417
|
-
"hermes-submitBundleTx-等待结束",
|
|
1418
|
-
`Bundle未在目标区块上链, txHash=${txHash}, 目标区块=[${targetBlocks.join(",")}], 等待耗时=${Date.now() - waitTs}ms`
|
|
1419
|
-
);
|
|
1573
|
+
this.trace(chain, traceReq, "warn", "hermes-submitBundleTx-等待结束", `Bundle未在目标区块上链, txHash=${txHash}, 目标区块=[${targetBlocks.join(",")}], 等待耗时=${Date.now() - waitTs}ms`);
|
|
1420
1574
|
}
|
|
1421
1575
|
return { receipt, txHash, targetBlocks };
|
|
1422
1576
|
}
|
|
@@ -1517,7 +1671,7 @@ var _Aggregator = class {
|
|
|
1517
1671
|
return chain === import_types.ChainNameEnum.ETH && !!this.flashbotSigner;
|
|
1518
1672
|
}
|
|
1519
1673
|
stripCustomFields(txReq, chain) {
|
|
1520
|
-
const defaultBlockCount =
|
|
1674
|
+
const defaultBlockCount = this.getDefaultBundleBlockCount(chain);
|
|
1521
1675
|
const { useBundle, bundleBlockCount = defaultBlockCount, trace, ...pureTxReq } = txReq;
|
|
1522
1676
|
return { pureTxReq, bundleBlockCount: this.normalizeBundleBlockCount(bundleBlockCount) };
|
|
1523
1677
|
}
|
|
@@ -1552,11 +1706,22 @@ var Aggregator = _Aggregator;
|
|
|
1552
1706
|
Aggregator.DEFAULT_ETH_BUILDERS = {
|
|
1553
1707
|
"beaverbuild.org": "https://rpc.beaverbuild.org",
|
|
1554
1708
|
Titan: "https://rpc.titanbuilder.xyz",
|
|
1709
|
+
"Titan-EU": "https://eu.rpc.titanbuilder.xyz",
|
|
1555
1710
|
flashbots: "https://relay.flashbots.net",
|
|
1556
1711
|
// bloXroute: 'https://mev.api.blxrbdn.com', // 旧 api.blxrbdn.com 也行,需配置 Authorization 头
|
|
1557
|
-
|
|
1712
|
+
"Builder+": "https://rpc.btcs.com",
|
|
1713
|
+
// BTCS 官方文档支持 eth_sendBundle
|
|
1714
|
+
// turbobuilder: 'https://rpc.turbobuilder.xyz', // 官方文档支持 eth_sendBundle
|
|
1715
|
+
lightspeedbuilder: "https://rpc.lightspeedbuilder.info",
|
|
1558
1716
|
// 新增,实测直接可用
|
|
1559
|
-
|
|
1717
|
+
buildernet: "https://rpc.buildernet.org",
|
|
1718
|
+
// Flashbots 生态,使用 eth_sendBundle + X-Flashbots-Signature
|
|
1719
|
+
quasar: "https://rpc.quasar.win",
|
|
1720
|
+
// Quasar 文档支持 eth_sendBundle,认证沿用 X-Flashbots-Signature
|
|
1721
|
+
bananabuild: "https://rpc.bananabuild.org",
|
|
1722
|
+
// 官方文档支持 eth_sendBundle
|
|
1723
|
+
snailbuilder: "https://rpc.snailbuilder.sh"
|
|
1724
|
+
// 官网声明支持 Flashbots 同结构 bundle API
|
|
1560
1725
|
// nfactorial: 'https://rpc.nfactorial.xyz', // 新增,支持 bundle rebate
|
|
1561
1726
|
};
|
|
1562
1727
|
Aggregator.DEFAULT_SEQUENCER_RPC_BY_CHAIN = {
|
package/dist/cjs/aggregator.d.ts
CHANGED
|
@@ -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;
|
package/dist/cjs/index.cjs
CHANGED
package/dist/cjs/index.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/cjs/provider.cjs
CHANGED
|
@@ -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:
|
package/dist/cjs/provider.d.ts
CHANGED
|
@@ -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 };
|
package/dist/cjs/types.cjs
CHANGED
|
@@ -36,7 +36,9 @@ var import_lz_definitions = require("@layerzerolabs/lz-definitions");
|
|
|
36
36
|
var DexType = /* @__PURE__ */ ((DexType2) => {
|
|
37
37
|
DexType2["FX"] = "f(x)";
|
|
38
38
|
DexType2["UNISWAPV2"] = "uniswapv2";
|
|
39
|
+
DexType2["SUSHIV2"] = "sushiv2";
|
|
39
40
|
DexType2["UNISWAPV3"] = "uniswapv3";
|
|
41
|
+
DexType2["SUSHIV3"] = "sushiv3";
|
|
40
42
|
DexType2["UNISWAPV4"] = "uniswapv4";
|
|
41
43
|
DexType2["CURVE128"] = "curve128";
|
|
42
44
|
DexType2["CURVE256"] = "curve256";
|
|
@@ -58,6 +60,58 @@ var DexType = /* @__PURE__ */ ((DexType2) => {
|
|
|
58
60
|
DexType2["BLACKHOLEV3"] = "blackholev3";
|
|
59
61
|
DexType2["BLACKHOLEV2"] = "blackholev2";
|
|
60
62
|
DexType2["FLUID"] = "fluid";
|
|
63
|
+
DexType2["BANCOR"] = "bancor";
|
|
64
|
+
DexType2["ERC4626"] = "erc4626";
|
|
65
|
+
DexType2["DODOV2"] = "dodo-v2";
|
|
66
|
+
DexType2["AERODROMEV3"] = "aerodrome_v3";
|
|
67
|
+
DexType2["ALGEBRAINTEGRAL"] = "algebra_integral";
|
|
68
|
+
DexType2["AMBIENT"] = "ambient";
|
|
69
|
+
DexType2["ANGSTROM"] = "angstrom";
|
|
70
|
+
DexType2["APESWAP"] = "apeswap";
|
|
71
|
+
DexType2["ARCHLYV2"] = "archly_v2";
|
|
72
|
+
DexType2["BALANCER"] = "balancer";
|
|
73
|
+
DexType2["BALANCERV2"] = "balancer_v2";
|
|
74
|
+
DexType2["BALANCERV3"] = "balancer_v3";
|
|
75
|
+
DexType2["BANCORV2"] = "bancor_v2";
|
|
76
|
+
DexType2["BANCORV3"] = "bancor_v3";
|
|
77
|
+
DexType2["BASIN"] = "basin";
|
|
78
|
+
DexType2["BUNNIV2"] = "bunni_v2";
|
|
79
|
+
DexType2["CURVELENDINGPOOLS"] = "curve_lending_pools";
|
|
80
|
+
DexType2["CURVEMETAPOOL"] = "curve_metapool";
|
|
81
|
+
DexType2["CURVESTABLESWAP"] = "curve_stable_swap";
|
|
82
|
+
DexType2["CURVESTABLESWAPNG"] = "curve_stable_swap_ng";
|
|
83
|
+
DexType2["CURVETRICRYPTO"] = "curve_tricrypto";
|
|
84
|
+
DexType2["CURVETRICRYPTONG"] = "curve_tricrypto_ng";
|
|
85
|
+
DexType2["CURVETWOCRYPTO"] = "curve_twocrypto";
|
|
86
|
+
DexType2["CYPHERV2"] = "cypher_v2";
|
|
87
|
+
DexType2["DEFIPLAZA"] = "defiplaza";
|
|
88
|
+
DexType2["DFXV2"] = "dfx_v2";
|
|
89
|
+
DexType2["DODOV1"] = "dodo_v1";
|
|
90
|
+
DexType2["EKUBO"] = "ekubo";
|
|
91
|
+
DexType2["EMPIREDEX"] = "empiredex";
|
|
92
|
+
DexType2["EULERSWAP"] = "eulerswap";
|
|
93
|
+
DexType2["FLUIDDEXLITE"] = "fluid_dex_lite";
|
|
94
|
+
DexType2["FLUIDDEXT1"] = "fluid_dex_t1";
|
|
95
|
+
DexType2["INTEGRAL"] = "integral";
|
|
96
|
+
DexType2["JOEV2"] = "joe_v2";
|
|
97
|
+
DexType2["KYBERSWAPCLASSIC"] = "kyberswap_classic";
|
|
98
|
+
DexType2["KYBERSWAPELASTIC"] = "kyberswap_elastic";
|
|
99
|
+
DexType2["LISTADEX"] = "lista_dex";
|
|
100
|
+
DexType2["LUASWAP"] = "luaswap";
|
|
101
|
+
DexType2["MAVERICKV2"] = "maverick_v2";
|
|
102
|
+
DexType2["MOONISWAP"] = "mooniswap";
|
|
103
|
+
DexType2["PENDLEV2"] = "pendle_v2";
|
|
104
|
+
DexType2["RINGSWAP"] = "ring_swap";
|
|
105
|
+
DexType2["SADDLEFINANCE"] = "saddle_finance";
|
|
106
|
+
DexType2["SHIBASWAPV1"] = "shibaswap_v1";
|
|
107
|
+
DexType2["SMARDEX"] = "smardex";
|
|
108
|
+
DexType2["SOLIDLYV3"] = "solidly_v3";
|
|
109
|
+
DexType2["STABULL"] = "stabull";
|
|
110
|
+
DexType2["SUPERNOVABASIC"] = "supernova_basic";
|
|
111
|
+
DexType2["SWAPR"] = "swapr";
|
|
112
|
+
DexType2["UNISWAPV1"] = "uniswap_v1";
|
|
113
|
+
DexType2["WOMBAT"] = "wombat";
|
|
114
|
+
DexType2["YIELDBASIS"] = "yield_basis";
|
|
61
115
|
return DexType2;
|
|
62
116
|
})(DexType || {});
|
|
63
117
|
var IEstimateType = /* @__PURE__ */ ((IEstimateType2) => {
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -172,7 +172,9 @@ export interface IHermesSignalQuoteBestData {
|
|
|
172
172
|
export declare enum DexType {
|
|
173
173
|
FX = "f(x)",
|
|
174
174
|
UNISWAPV2 = "uniswapv2",
|
|
175
|
+
SUSHIV2 = "sushiv2",
|
|
175
176
|
UNISWAPV3 = "uniswapv3",
|
|
177
|
+
SUSHIV3 = "sushiv3",
|
|
176
178
|
UNISWAPV4 = "uniswapv4",
|
|
177
179
|
CURVE128 = "curve128",
|
|
178
180
|
CURVE256 = "curve256",
|
|
@@ -193,7 +195,59 @@ export declare enum DexType {
|
|
|
193
195
|
SHADOWV2 = "shadowv2",
|
|
194
196
|
BLACKHOLEV3 = "blackholev3",
|
|
195
197
|
BLACKHOLEV2 = "blackholev2",
|
|
196
|
-
FLUID = "fluid"
|
|
198
|
+
FLUID = "fluid",
|
|
199
|
+
BANCOR = "bancor",
|
|
200
|
+
ERC4626 = "erc4626",
|
|
201
|
+
DODOV2 = "dodo-v2",
|
|
202
|
+
AERODROMEV3 = "aerodrome_v3",
|
|
203
|
+
ALGEBRAINTEGRAL = "algebra_integral",
|
|
204
|
+
AMBIENT = "ambient",
|
|
205
|
+
ANGSTROM = "angstrom",
|
|
206
|
+
APESWAP = "apeswap",
|
|
207
|
+
ARCHLYV2 = "archly_v2",
|
|
208
|
+
BALANCER = "balancer",
|
|
209
|
+
BALANCERV2 = "balancer_v2",
|
|
210
|
+
BALANCERV3 = "balancer_v3",
|
|
211
|
+
BANCORV2 = "bancor_v2",
|
|
212
|
+
BANCORV3 = "bancor_v3",
|
|
213
|
+
BASIN = "basin",
|
|
214
|
+
BUNNIV2 = "bunni_v2",
|
|
215
|
+
CURVELENDINGPOOLS = "curve_lending_pools",
|
|
216
|
+
CURVEMETAPOOL = "curve_metapool",
|
|
217
|
+
CURVESTABLESWAP = "curve_stable_swap",
|
|
218
|
+
CURVESTABLESWAPNG = "curve_stable_swap_ng",
|
|
219
|
+
CURVETRICRYPTO = "curve_tricrypto",
|
|
220
|
+
CURVETRICRYPTONG = "curve_tricrypto_ng",
|
|
221
|
+
CURVETWOCRYPTO = "curve_twocrypto",
|
|
222
|
+
CYPHERV2 = "cypher_v2",
|
|
223
|
+
DEFIPLAZA = "defiplaza",
|
|
224
|
+
DFXV2 = "dfx_v2",
|
|
225
|
+
DODOV1 = "dodo_v1",
|
|
226
|
+
EKUBO = "ekubo",
|
|
227
|
+
EMPIREDEX = "empiredex",
|
|
228
|
+
EULERSWAP = "eulerswap",
|
|
229
|
+
FLUIDDEXLITE = "fluid_dex_lite",
|
|
230
|
+
FLUIDDEXT1 = "fluid_dex_t1",
|
|
231
|
+
INTEGRAL = "integral",
|
|
232
|
+
JOEV2 = "joe_v2",
|
|
233
|
+
KYBERSWAPCLASSIC = "kyberswap_classic",
|
|
234
|
+
KYBERSWAPELASTIC = "kyberswap_elastic",
|
|
235
|
+
LISTADEX = "lista_dex",
|
|
236
|
+
LUASWAP = "luaswap",
|
|
237
|
+
MAVERICKV2 = "maverick_v2",
|
|
238
|
+
MOONISWAP = "mooniswap",
|
|
239
|
+
PENDLEV2 = "pendle_v2",
|
|
240
|
+
RINGSWAP = "ring_swap",
|
|
241
|
+
SADDLEFINANCE = "saddle_finance",
|
|
242
|
+
SHIBASWAPV1 = "shibaswap_v1",
|
|
243
|
+
SMARDEX = "smardex",
|
|
244
|
+
SOLIDLYV3 = "solidly_v3",
|
|
245
|
+
STABULL = "stabull",
|
|
246
|
+
SUPERNOVABASIC = "supernova_basic",
|
|
247
|
+
SWAPR = "swapr",
|
|
248
|
+
UNISWAPV1 = "uniswap_v1",
|
|
249
|
+
WOMBAT = "wombat",
|
|
250
|
+
YIELDBASIS = "yield_basis"
|
|
197
251
|
}
|
|
198
252
|
export declare enum IEstimateType {
|
|
199
253
|
BRIDGE = "bridge",
|