hermes-swap 0.6.9 → 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.
- package/dist/cjs/aggregator.cjs +253 -52
- package/dist/cjs/aggregator.d.ts +4 -0
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.d.ts +3 -2
- package/dist/cjs/provider.cjs +10 -0
- package/dist/cjs/provider.d.ts +1 -0
- package/dist/cjs/types.d.ts +8 -0
- package/dist/esm/aggregator.d.ts +4 -0
- package/dist/esm/aggregator.mjs +644 -488
- package/dist/esm/index.d.ts +3 -2
- 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 +8 -0
- package/package.json +1 -1
package/dist/cjs/aggregator.cjs
CHANGED
|
@@ -90,6 +90,20 @@ var _Aggregator = class {
|
|
|
90
90
|
return "unknown";
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
emitTrace(txReq, chain, level, stage, message) {
|
|
94
|
+
var _a;
|
|
95
|
+
(_a = txReq == null ? void 0 : txReq.trace) == null ? void 0 : _a.call(txReq, {
|
|
96
|
+
ts: Date.now(),
|
|
97
|
+
chain,
|
|
98
|
+
level,
|
|
99
|
+
stage,
|
|
100
|
+
message
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
trace(chain, txReq, level, stage, message) {
|
|
104
|
+
_Aggregator.traceLog(chain, level, message);
|
|
105
|
+
this.emitTrace(txReq, chain, level, stage, message);
|
|
106
|
+
}
|
|
93
107
|
getAggregator(chain) {
|
|
94
108
|
if (!this.aggregatorMap.has(chain)) {
|
|
95
109
|
throw new Error(`Aggregator not found for chain: ${chain}`);
|
|
@@ -118,6 +132,15 @@ var _Aggregator = class {
|
|
|
118
132
|
}
|
|
119
133
|
throw new Error(`No builder config for chain: ${chain}`);
|
|
120
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
|
+
}
|
|
121
144
|
getSequencerRpcs(config) {
|
|
122
145
|
const merged = {
|
|
123
146
|
..._Aggregator.DEFAULT_SEQUENCER_RPC_BY_CHAIN
|
|
@@ -161,6 +184,16 @@ var _Aggregator = class {
|
|
|
161
184
|
]
|
|
162
185
|
};
|
|
163
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
|
+
}
|
|
164
197
|
async sendBundle(chain, rawTxs, targetBlock, signer) {
|
|
165
198
|
const builderCfg = this.getBuilderConfig(chain);
|
|
166
199
|
const body = this.buildBundleRequestBody(builderCfg, rawTxs, targetBlock);
|
|
@@ -176,6 +209,14 @@ var _Aggregator = class {
|
|
|
176
209
|
const ts = Date.now();
|
|
177
210
|
try {
|
|
178
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
|
+
}
|
|
179
220
|
sent++;
|
|
180
221
|
const detail = `[OK] ${name}`;
|
|
181
222
|
details.push(detail);
|
|
@@ -311,10 +352,13 @@ var _Aggregator = class {
|
|
|
311
352
|
}
|
|
312
353
|
async swapAndBridge(params, txReq = {}) {
|
|
313
354
|
var _a, _b;
|
|
355
|
+
const traceReq = txReq;
|
|
314
356
|
const useBundle = this.shouldUseBundle(params.chain, txReq);
|
|
315
|
-
|
|
357
|
+
this.trace(
|
|
316
358
|
params.chain,
|
|
359
|
+
traceReq,
|
|
317
360
|
"log",
|
|
361
|
+
"hermes-swapAndBridge-开始",
|
|
318
362
|
`swapAndBridge开始, user=${params.user}, amountInWeis=[${params.amountInWeis.join(",")}], bridgeType=${params.bridgeType}, destChain=${params.destChain}, useBundle=${useBundle}`
|
|
319
363
|
);
|
|
320
364
|
const startTs = Date.now();
|
|
@@ -357,14 +401,26 @@ var _Aggregator = class {
|
|
|
357
401
|
const { gasLimit: _ignore, ...estimationOverrides } = txReq;
|
|
358
402
|
const args = [params.user, params.amountInWeis, swapParamsList, params.minAmountOutLists, bridgeArgs, params.totalMinAmountOut];
|
|
359
403
|
try {
|
|
404
|
+
this.trace(params.chain, traceReq, "log", "hermes-swapAndBridge-estimateGas-开始", "swapAndBridge estimateGas 开始");
|
|
360
405
|
estimateGas = await aggregator.multiSwapAndBridge.estimateGas(...args, estimationOverrides);
|
|
406
|
+
this.trace(params.chain, traceReq, "log", "hermes-swapAndBridge-estimateGas-完成", `swapAndBridge estimateGas 完成, estimateGas=${estimateGas}`);
|
|
361
407
|
} catch (error) {
|
|
362
|
-
|
|
408
|
+
this.trace(params.chain, traceReq, "error", "hermes-swapAndBridge-estimateGas-失败", `swapAndBridge estimateGas失败, rpcUrl=${this.getRpcUrl(params.chain)}, error=${error}`);
|
|
363
409
|
throw error;
|
|
364
410
|
}
|
|
365
411
|
txReq = this.resolveGasLimit(txReq, estimateGas);
|
|
412
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolveNonce-开始", "swapAndBridge resolveNonce 开始");
|
|
366
413
|
txReq = await this.resolveNonce(wallet.provider, wallet.address, txReq);
|
|
414
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolveNonce-完成", `swapAndBridge resolveNonce 完成, nonce=${txReq.nonce}`);
|
|
415
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolvePricing-开始", "swapAndBridge resolvePricing 开始");
|
|
367
416
|
txReq = await this.resolvePricing(wallet.provider, txReq);
|
|
417
|
+
this.trace(
|
|
418
|
+
params.chain,
|
|
419
|
+
traceReq,
|
|
420
|
+
"log",
|
|
421
|
+
"hermes-resolvePricing-完成",
|
|
422
|
+
`swapAndBridge resolvePricing 完成, gasPrice=${txReq.gasPrice ?? "n/a"}, maxFeePerGas=${txReq.maxFeePerGas ?? "n/a"}, maxPriorityFeePerGas=${txReq.maxPriorityFeePerGas ?? "n/a"}`
|
|
423
|
+
);
|
|
368
424
|
const iface = new import_ethers.ethers.Interface(import_aggregator.default);
|
|
369
425
|
let receipt;
|
|
370
426
|
if (useBundle) {
|
|
@@ -373,7 +429,7 @@ var _Aggregator = class {
|
|
|
373
429
|
receipt: flashbotsReceipt,
|
|
374
430
|
txHash: bundleTxHash,
|
|
375
431
|
targetBlocks
|
|
376
|
-
} = await this.submitBundleTx(params.chain, wallet, txReq, aggregatorAddress, calldata, txReq.value ?? 0n, bundleBlockCount);
|
|
432
|
+
} = await this.submitBundleTx(params.chain, wallet, txReq, aggregatorAddress, calldata, txReq.value ?? 0n, bundleBlockCount, traceReq);
|
|
377
433
|
txHash = bundleTxHash;
|
|
378
434
|
if (!flashbotsReceipt) {
|
|
379
435
|
throw new import_types.BundleNotIncludedError(`Bundle 未在目标区块上链, txHash=${bundleTxHash}, targetBlocks=[${targetBlocks.join(",")}]`, bundleTxHash);
|
|
@@ -383,7 +439,7 @@ var _Aggregator = class {
|
|
|
383
439
|
}
|
|
384
440
|
receipt = flashbotsReceipt;
|
|
385
441
|
} else {
|
|
386
|
-
receipt = await this.sendContractTx(params.chain, aggregator, "multiSwapAndBridge", args, txReq);
|
|
442
|
+
receipt = await this.sendContractTx(params.chain, aggregator, "multiSwapAndBridge", args, txReq, traceReq);
|
|
387
443
|
txHash = receipt.hash;
|
|
388
444
|
}
|
|
389
445
|
let receiptUser = null;
|
|
@@ -411,7 +467,13 @@ var _Aggregator = class {
|
|
|
411
467
|
const fromTokenAddress = ((_a = pathStart == null ? void 0 : pathStart[0]) == null ? void 0 : _a.fromCoinAddress) ?? "";
|
|
412
468
|
const toTokenAddress = ((_b = pathEnd == null ? void 0 : pathEnd[pathEnd.length - 1]) == null ? void 0 : _b.toCoinAddress) ?? "";
|
|
413
469
|
const totalAmountInFromEvent = amountInList.reduce((sum, amount) => sum + amount, 0n);
|
|
414
|
-
|
|
470
|
+
this.trace(
|
|
471
|
+
params.chain,
|
|
472
|
+
traceReq,
|
|
473
|
+
"log",
|
|
474
|
+
"hermes-swapAndBridge-完成",
|
|
475
|
+
`swapAndBridge完成, txHash=${receipt.hash}, amountOut=${amountOut}, useBundle=${useBundle}, 总耗时=${Date.now() - startTs}ms`
|
|
476
|
+
);
|
|
415
477
|
return {
|
|
416
478
|
hash: receipt.hash,
|
|
417
479
|
from: receipt.from,
|
|
@@ -420,14 +482,27 @@ var _Aggregator = class {
|
|
|
420
482
|
receipt
|
|
421
483
|
};
|
|
422
484
|
} catch (error) {
|
|
423
|
-
|
|
485
|
+
this.trace(
|
|
486
|
+
params.chain,
|
|
487
|
+
traceReq,
|
|
488
|
+
"error",
|
|
489
|
+
"hermes-swapAndBridge-异常",
|
|
490
|
+
`swapAndBridge异常, rpcUrl=${this.getRpcUrl(params.chain)}, txHash=${txHash ?? "N/A"}, 总耗时=${Date.now() - startTs}ms, error=${error}`
|
|
491
|
+
);
|
|
424
492
|
throw error;
|
|
425
493
|
}
|
|
426
494
|
}
|
|
427
495
|
async multiSwap(params, txReq = {}) {
|
|
428
496
|
var _a;
|
|
497
|
+
const traceReq = txReq;
|
|
429
498
|
const useBundle = this.shouldUseBundle(params.chain, txReq);
|
|
430
|
-
|
|
499
|
+
this.trace(
|
|
500
|
+
params.chain,
|
|
501
|
+
traceReq,
|
|
502
|
+
"log",
|
|
503
|
+
"hermes-multiSwap-开始",
|
|
504
|
+
`multiSwap开始, user=${params.user}, pathsCount=${params.paths.length}, amountInWeis=[${params.amountInWeis.join(",")}], useBundle=${useBundle}`
|
|
505
|
+
);
|
|
431
506
|
const startTs = Date.now();
|
|
432
507
|
let txHash;
|
|
433
508
|
try {
|
|
@@ -469,14 +544,26 @@ var _Aggregator = class {
|
|
|
469
544
|
let estimateGas;
|
|
470
545
|
const { gasLimit: _ignore, ...estimationOverrides } = txReq;
|
|
471
546
|
try {
|
|
547
|
+
this.trace(params.chain, traceReq, "log", "hermes-multiSwap-estimateGas-开始", "multiSwap estimateGas 开始");
|
|
472
548
|
estimateGas = await aggregator.multiSwap.estimateGas(params.user, params.amountInWeis, swapParamsList, params.minAmountOutLists, params.totalMinAmountOut, estimationOverrides);
|
|
549
|
+
this.trace(params.chain, traceReq, "log", "hermes-multiSwap-estimateGas-完成", `multiSwap estimateGas 完成, estimateGas=${estimateGas}`);
|
|
473
550
|
} catch (error) {
|
|
474
|
-
|
|
551
|
+
this.trace(params.chain, traceReq, "error", "hermes-multiSwap-estimateGas-失败", `multiSwap estimateGas失败, rpcUrl=${this.getRpcUrl(params.chain)}, error=${error}`);
|
|
475
552
|
throw error;
|
|
476
553
|
}
|
|
477
554
|
txReq = this.resolveGasLimit(txReq, estimateGas);
|
|
555
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolveNonce-开始", "multiSwap resolveNonce 开始");
|
|
478
556
|
txReq = await this.resolveNonce(wallet.provider, wallet.address, txReq);
|
|
557
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolveNonce-完成", `multiSwap resolveNonce 完成, nonce=${txReq.nonce}`);
|
|
558
|
+
this.trace(params.chain, traceReq, "log", "hermes-resolvePricing-开始", "multiSwap resolvePricing 开始");
|
|
479
559
|
txReq = await this.resolvePricing(wallet.provider, txReq);
|
|
560
|
+
this.trace(
|
|
561
|
+
params.chain,
|
|
562
|
+
traceReq,
|
|
563
|
+
"log",
|
|
564
|
+
"hermes-resolvePricing-完成",
|
|
565
|
+
`multiSwap resolvePricing 完成, gasPrice=${txReq.gasPrice ?? "n/a"}, maxFeePerGas=${txReq.maxFeePerGas ?? "n/a"}, maxPriorityFeePerGas=${txReq.maxPriorityFeePerGas ?? "n/a"}`
|
|
566
|
+
);
|
|
480
567
|
const iface = new import_ethers.ethers.Interface(import_aggregator.default);
|
|
481
568
|
let receipt;
|
|
482
569
|
if (useBundle) {
|
|
@@ -485,7 +572,7 @@ var _Aggregator = class {
|
|
|
485
572
|
receipt: flashbotsReceipt,
|
|
486
573
|
txHash: bundleTxHash,
|
|
487
574
|
targetBlocks
|
|
488
|
-
} = await this.submitBundleTx(params.chain, wallet, txReq, aggregatorAddress, calldata, txReq.value ?? 0n, bundleBlockCount);
|
|
575
|
+
} = await this.submitBundleTx(params.chain, wallet, txReq, aggregatorAddress, calldata, txReq.value ?? 0n, bundleBlockCount, traceReq);
|
|
489
576
|
txHash = bundleTxHash;
|
|
490
577
|
if (!flashbotsReceipt) {
|
|
491
578
|
throw new import_types.BundleNotIncludedError(`Bundle 未在目标区块上链, txHash=${bundleTxHash}, targetBlocks=[${targetBlocks.join(",")}]`, bundleTxHash);
|
|
@@ -495,7 +582,14 @@ var _Aggregator = class {
|
|
|
495
582
|
}
|
|
496
583
|
receipt = flashbotsReceipt;
|
|
497
584
|
} else {
|
|
498
|
-
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
|
+
);
|
|
499
593
|
txHash = receipt.hash;
|
|
500
594
|
}
|
|
501
595
|
let amountOutList = null;
|
|
@@ -513,7 +607,13 @@ var _Aggregator = class {
|
|
|
513
607
|
}
|
|
514
608
|
if (!amountOutList)
|
|
515
609
|
throw new Error(`MultiSwapped event not found: ${receipt.hash}`);
|
|
516
|
-
|
|
610
|
+
this.trace(
|
|
611
|
+
params.chain,
|
|
612
|
+
traceReq,
|
|
613
|
+
"log",
|
|
614
|
+
"hermes-multiSwap-完成",
|
|
615
|
+
`multiSwap完成, txHash=${receipt.hash}, amountOutList=[${amountOutList.join(",")}], useBundle=${useBundle}, 总耗时=${Date.now() - startTs}ms`
|
|
616
|
+
);
|
|
517
617
|
return {
|
|
518
618
|
hash: receipt.hash,
|
|
519
619
|
from: receipt.from,
|
|
@@ -531,7 +631,13 @@ var _Aggregator = class {
|
|
|
531
631
|
receipt
|
|
532
632
|
};
|
|
533
633
|
} catch (error) {
|
|
534
|
-
|
|
634
|
+
this.trace(
|
|
635
|
+
params.chain,
|
|
636
|
+
traceReq,
|
|
637
|
+
"error",
|
|
638
|
+
"hermes-multiSwap-异常",
|
|
639
|
+
`multiSwap异常, rpcUrl=${this.getRpcUrl(params.chain)}, txHash=${txHash ?? "N/A"}, 总耗时=${Date.now() - startTs}ms, error=${error}`
|
|
640
|
+
);
|
|
535
641
|
throw error;
|
|
536
642
|
}
|
|
537
643
|
}
|
|
@@ -899,9 +1005,12 @@ var _Aggregator = class {
|
|
|
899
1005
|
const block = await provider.getBlock(blockNumber, true);
|
|
900
1006
|
if (!block)
|
|
901
1007
|
return false;
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
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
|
+
});
|
|
905
1014
|
} catch {
|
|
906
1015
|
return false;
|
|
907
1016
|
}
|
|
@@ -947,10 +1056,23 @@ var _Aggregator = class {
|
|
|
947
1056
|
cleanup();
|
|
948
1057
|
resolve(receipt);
|
|
949
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
|
+
};
|
|
950
1072
|
const scheduleInspect = (fromBlock, toBlock) => {
|
|
951
1073
|
if (fromBlock > toBlock) {
|
|
952
1074
|
if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
|
|
953
|
-
|
|
1075
|
+
finishWithFallbackCheck();
|
|
954
1076
|
}
|
|
955
1077
|
return;
|
|
956
1078
|
}
|
|
@@ -980,7 +1102,7 @@ var _Aggregator = class {
|
|
|
980
1102
|
return;
|
|
981
1103
|
}
|
|
982
1104
|
if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
|
|
983
|
-
|
|
1105
|
+
finishWithFallbackCheck();
|
|
984
1106
|
}
|
|
985
1107
|
};
|
|
986
1108
|
const onBlock = (blockNumber) => {
|
|
@@ -993,7 +1115,7 @@ var _Aggregator = class {
|
|
|
993
1115
|
}
|
|
994
1116
|
if (fromBlock > toBlock) {
|
|
995
1117
|
if (checkedBlocks.size === targetBlockSet.size && lastObservedBlock >= maxTargetBlock) {
|
|
996
|
-
|
|
1118
|
+
finishWithFallbackCheck();
|
|
997
1119
|
}
|
|
998
1120
|
return;
|
|
999
1121
|
}
|
|
@@ -1011,7 +1133,8 @@ var _Aggregator = class {
|
|
|
1011
1133
|
const toBlock = Math.min(latestBlock, maxTargetBlock);
|
|
1012
1134
|
scheduleInspect(sortedTargetBlocks[0], toBlock);
|
|
1013
1135
|
await inspectionChain;
|
|
1014
|
-
|
|
1136
|
+
if (!settled)
|
|
1137
|
+
await finishWithFallbackCheck();
|
|
1015
1138
|
}, _Aggregator.BUNDLE_INCLUSION_TIMEOUT_MS);
|
|
1016
1139
|
provider.on("block", onBlock);
|
|
1017
1140
|
provider.getBlockNumber().then(
|
|
@@ -1030,22 +1153,22 @@ var _Aggregator = class {
|
|
|
1030
1153
|
);
|
|
1031
1154
|
});
|
|
1032
1155
|
}
|
|
1033
|
-
async sendSignedTxToChannels(chain, signedTx, txHash, channels) {
|
|
1156
|
+
async sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq) {
|
|
1034
1157
|
const results = await Promise.all(
|
|
1035
1158
|
channels.map(async ({ label, send }) => {
|
|
1036
1159
|
var _a, _b, _c, _d, _e;
|
|
1037
1160
|
const sendTs = Date.now();
|
|
1038
1161
|
try {
|
|
1039
1162
|
await send();
|
|
1040
|
-
|
|
1163
|
+
this.trace(chain, traceReq, "log", "hermes-broadcast-channel-成功", `广播${label} OK, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1041
1164
|
return { label, ok: true };
|
|
1042
1165
|
} catch (err) {
|
|
1043
1166
|
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);
|
|
1044
1167
|
if (_Aggregator.isBenignBroadcastError(msg)) {
|
|
1045
|
-
|
|
1168
|
+
this.trace(chain, traceReq, "log", "hermes-broadcast-channel-已存在", `广播${label} already-known, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1046
1169
|
return { label, ok: true };
|
|
1047
1170
|
}
|
|
1048
|
-
|
|
1171
|
+
this.trace(chain, traceReq, "warn", "hermes-broadcast-channel-失败", `广播${label} 失败: ${msg}, txHash=${txHash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1049
1172
|
return { label, ok: false, msg };
|
|
1050
1173
|
}
|
|
1051
1174
|
})
|
|
@@ -1056,7 +1179,7 @@ var _Aggregator = class {
|
|
|
1056
1179
|
const detail = results.map((result) => `${result.label}: ${result.msg ?? "unknown error"}`).join("; ");
|
|
1057
1180
|
throw new Error(`All broadcast channels failed for ${txHash}: ${detail}`);
|
|
1058
1181
|
}
|
|
1059
|
-
raceForReceipt(chain, txHash, providers, ownedProviders = [], timeoutMs = _Aggregator.TX_CONFIRM_TIMEOUT_MS) {
|
|
1182
|
+
raceForReceipt(chain, txHash, providers, ownedProviders = [], timeoutMs = _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq) {
|
|
1060
1183
|
return new Promise((resolve, reject) => {
|
|
1061
1184
|
let settled = false;
|
|
1062
1185
|
const blockHandlers = [];
|
|
@@ -1077,7 +1200,7 @@ var _Aggregator = class {
|
|
|
1077
1200
|
settled = true;
|
|
1078
1201
|
clearTimeout(timer);
|
|
1079
1202
|
cleanup();
|
|
1080
|
-
|
|
1203
|
+
this.trace(chain, traceReq, "log", "hermes-raceForReceipt-命中receipt", `${label} 先查到receipt, txHash=${txHash}, block=${receipt.blockNumber}`);
|
|
1081
1204
|
resolve(receipt);
|
|
1082
1205
|
};
|
|
1083
1206
|
const checkReceipt = (provider, label) => {
|
|
@@ -1103,6 +1226,7 @@ var _Aggregator = class {
|
|
|
1103
1226
|
return;
|
|
1104
1227
|
settled = true;
|
|
1105
1228
|
cleanup();
|
|
1229
|
+
this.trace(chain, traceReq, "warn", "hermes-raceForReceipt-超时", `Transaction not confirmed within ${timeoutMs}ms: ${txHash}`);
|
|
1106
1230
|
reject(new Error(`Transaction not confirmed within ${timeoutMs}ms: ${txHash}`));
|
|
1107
1231
|
}, timeoutMs);
|
|
1108
1232
|
});
|
|
@@ -1123,26 +1247,35 @@ var _Aggregator = class {
|
|
|
1123
1247
|
}
|
|
1124
1248
|
};
|
|
1125
1249
|
}
|
|
1126
|
-
async sendContractTx(chain, contract, method, args, txReq) {
|
|
1250
|
+
async sendContractTx(chain, contract, method, args, txReq, traceReq) {
|
|
1127
1251
|
const extraUrls = this.broadcastRpcsMap.get(chain);
|
|
1128
1252
|
const hasSequencer = _Aggregator.SEQUENCER_CHAINS.has(chain) && this.sequencerRpcsMap.has(chain);
|
|
1129
1253
|
if (!extraUrls || extraUrls.length === 0) {
|
|
1130
1254
|
if (!hasSequencer) {
|
|
1131
|
-
|
|
1255
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-发出前", `渠道=单RPC直发, method=${method}, nonce=${txReq.nonce}, gasLimit=${txReq.gasLimit}`);
|
|
1132
1256
|
const sendTs = Date.now();
|
|
1257
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-RPC发送前", `单RPC准备发送, method=${method}`);
|
|
1133
1258
|
const txResponse = await contract[method](...args, txReq);
|
|
1134
|
-
|
|
1259
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-RPC已发送", `单RPC已发送, txHash=${txResponse.hash}, 耗时=${Date.now() - sendTs}ms`);
|
|
1260
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-等待确认", `单RPC开始等待上链确认, txHash=${txResponse.hash}`);
|
|
1135
1261
|
const receipt3 = await txResponse.wait();
|
|
1136
1262
|
const singleProvider = this.providerClient.getProvider(chain);
|
|
1137
1263
|
const blockTs3 = await this.getBlockTimestampStr(singleProvider, receipt3.blockNumber);
|
|
1138
|
-
|
|
1264
|
+
this.trace(
|
|
1265
|
+
chain,
|
|
1266
|
+
traceReq,
|
|
1267
|
+
"log",
|
|
1268
|
+
"hermes-sendContractTx-确认完成",
|
|
1269
|
+
`单RPC上链确认, txHash=${receipt3.hash}, blockNumber=${receipt3.blockNumber}, 出块时间=${blockTs3}, gasUsed=${receipt3.gasUsed}, status=${receipt3.status}`
|
|
1270
|
+
);
|
|
1139
1271
|
if (receipt3.status === 0) {
|
|
1140
1272
|
throw new import_types.TransactionRevertedError(receipt3.hash, receipt3.gasUsed);
|
|
1141
1273
|
}
|
|
1142
1274
|
return receipt3;
|
|
1143
1275
|
}
|
|
1144
|
-
|
|
1276
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-发出前", `渠道=单RPC+排序器直发, method=${method}, nonce=${txReq.nonce}, gasLimit=${txReq.gasLimit}`);
|
|
1145
1277
|
const wallet2 = this.providerClient.getWallet(chain);
|
|
1278
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-构建交易", `开始 populateTransaction, method=${method}`);
|
|
1146
1279
|
const populated2 = await contract[method].populateTransaction(...args, txReq);
|
|
1147
1280
|
delete populated2.from;
|
|
1148
1281
|
const network2 = await wallet2.provider.getNetwork();
|
|
@@ -1150,18 +1283,21 @@ var _Aggregator = class {
|
|
|
1150
1283
|
const signedTx2 = await wallet2.signTransaction(populated2);
|
|
1151
1284
|
const txHash2 = import_ethers.ethers.keccak256(signedTx2);
|
|
1152
1285
|
const mainProvider2 = wallet2.provider;
|
|
1153
|
-
|
|
1286
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-RPC发送前", `单RPC+排序器并行广播, txHash=${txHash2}`);
|
|
1154
1287
|
const broadcastTs2 = Date.now();
|
|
1155
1288
|
const providers = [{ provider: mainProvider2, label: "RPC[0/主]" }];
|
|
1156
1289
|
const sequencerChannel2 = this.buildSequencerChannel(chain, signedTx2);
|
|
1157
1290
|
const channels2 = [...providers.map(({ provider, label }) => ({ label, send: () => provider.broadcastTransaction(signedTx2) })), ...sequencerChannel2 ? [sequencerChannel2] : []];
|
|
1158
|
-
const receiptPromise2 = this.raceForReceipt(chain, txHash2, providers);
|
|
1159
|
-
await this.sendSignedTxToChannels(chain, signedTx2, txHash2, channels2);
|
|
1291
|
+
const receiptPromise2 = this.raceForReceipt(chain, txHash2, providers, [], _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq);
|
|
1292
|
+
await this.sendSignedTxToChannels(chain, signedTx2, txHash2, channels2, traceReq);
|
|
1293
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-等待确认", `并行广播后开始等待确认, txHash=${txHash2}`);
|
|
1160
1294
|
const receipt2 = await receiptPromise2;
|
|
1161
1295
|
const blockTs2 = await this.getBlockTimestampStr(mainProvider2, receipt2.blockNumber);
|
|
1162
|
-
|
|
1296
|
+
this.trace(
|
|
1163
1297
|
chain,
|
|
1298
|
+
traceReq,
|
|
1164
1299
|
"log",
|
|
1300
|
+
"hermes-sendContractTx-确认完成",
|
|
1165
1301
|
`单RPC+排序器上链确认, txHash=${receipt2.hash}, blockNumber=${receipt2.blockNumber}, 出块时间=${blockTs2}, gasUsed=${receipt2.gasUsed}, status=${receipt2.status}, 总耗时=${Date.now() - broadcastTs2}ms`
|
|
1166
1302
|
);
|
|
1167
1303
|
if (receipt2.status === 0) {
|
|
@@ -1184,21 +1320,27 @@ var _Aggregator = class {
|
|
|
1184
1320
|
}));
|
|
1185
1321
|
const allProviders = [{ provider: mainProvider, label: "RPC[0/主]" }, ...extraProviders];
|
|
1186
1322
|
const ownedProviders = extraProviders.map((e) => e.provider);
|
|
1187
|
-
|
|
1323
|
+
this.trace(
|
|
1188
1324
|
chain,
|
|
1325
|
+
traceReq,
|
|
1189
1326
|
"log",
|
|
1327
|
+
"hermes-sendContractTx-发出前",
|
|
1190
1328
|
`渠道=多RPC广播, method=${method}, nonce=${txReq.nonce}, gasLimit=${txReq.gasLimit}, 当前区块=${currentBlock}, 期望上链区块=${currentBlock + 1}, txHash=${txHash}, RPC数量=${allProviders.length}(主1+副${extraUrls.length})${hasSequencer ? ", +排序器直发" : ""}`
|
|
1191
1329
|
);
|
|
1192
1330
|
const broadcastTs = Date.now();
|
|
1193
1331
|
const sequencerChannel = this.buildSequencerChannel(chain, signedTx);
|
|
1194
1332
|
const channels = [...allProviders.map(({ provider, label }) => ({ label, send: () => provider.broadcastTransaction(signedTx) })), ...sequencerChannel ? [sequencerChannel] : []];
|
|
1195
|
-
const receiptPromise = this.raceForReceipt(chain, txHash, allProviders, ownedProviders);
|
|
1196
|
-
|
|
1333
|
+
const receiptPromise = this.raceForReceipt(chain, txHash, allProviders, ownedProviders, _Aggregator.TX_CONFIRM_TIMEOUT_MS, traceReq);
|
|
1334
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-RPC发送前", `多RPC广播准备发送, txHash=${txHash}`);
|
|
1335
|
+
await this.sendSignedTxToChannels(chain, signedTx, txHash, channels, traceReq);
|
|
1336
|
+
this.trace(chain, traceReq, "log", "hermes-sendContractTx-等待确认", `多RPC广播后开始等待确认, txHash=${txHash}`);
|
|
1197
1337
|
const receipt = await receiptPromise;
|
|
1198
1338
|
const blockTs = await this.getBlockTimestampStr(mainProvider, receipt.blockNumber);
|
|
1199
|
-
|
|
1339
|
+
this.trace(
|
|
1200
1340
|
chain,
|
|
1341
|
+
traceReq,
|
|
1201
1342
|
"log",
|
|
1343
|
+
"hermes-sendContractTx-确认完成",
|
|
1202
1344
|
`多RPC广播上链确认, txHash=${receipt.hash}, blockNumber=${receipt.blockNumber}, 出块时间=${blockTs}, gasUsed=${receipt.gasUsed}, status=${receipt.status}, 总耗时=${Date.now() - broadcastTs}ms`
|
|
1203
1345
|
);
|
|
1204
1346
|
if (receipt.status === 0) {
|
|
@@ -1206,9 +1348,9 @@ var _Aggregator = class {
|
|
|
1206
1348
|
}
|
|
1207
1349
|
return receipt;
|
|
1208
1350
|
}
|
|
1209
|
-
async submitBundleTx(chain, wallet, txReq, to, data, value, bundleBlockCount) {
|
|
1351
|
+
async submitBundleTx(chain, wallet, txReq, to, data, value, bundleBlockCount, traceReq) {
|
|
1210
1352
|
if (bundleBlockCount == null) {
|
|
1211
|
-
bundleBlockCount = this.
|
|
1353
|
+
bundleBlockCount = this.getDefaultBundleBlockCount(chain);
|
|
1212
1354
|
}
|
|
1213
1355
|
const builderCfg = this.getBuilderConfig(chain);
|
|
1214
1356
|
if (builderCfg.authType === "flashbots" && !this.flashbotSigner) {
|
|
@@ -1240,9 +1382,11 @@ var _Aggregator = class {
|
|
|
1240
1382
|
const targetBlocks = Array.from({ length: normalizedBundleBlockCount }, (_, i) => currentBlock + 1 + i);
|
|
1241
1383
|
const builderNames = Object.keys(builderCfg.urls);
|
|
1242
1384
|
const builderEntries = Object.entries(builderCfg.urls);
|
|
1243
|
-
|
|
1385
|
+
this.trace(
|
|
1244
1386
|
chain,
|
|
1387
|
+
traceReq,
|
|
1245
1388
|
"log",
|
|
1389
|
+
"hermes-submitBundleTx-发出前",
|
|
1246
1390
|
`渠道=Builder Bundle, authType=${builderCfg.authType}, method=${builderCfg.method ?? "eth_sendBundle"}, nonce=${txReq.nonce}, gasLimit=${txReq.gasLimit}, chainId=${network.chainId}, 当前区块=${currentBlock}, 目标区块=[${targetBlocks.join(",")}], builders=[${builderNames.join(",")}](${builderNames.length}个), txHash=${txHash}`
|
|
1247
1391
|
);
|
|
1248
1392
|
const sendBundleTs = Date.now();
|
|
@@ -1261,12 +1405,36 @@ var _Aggregator = class {
|
|
|
1261
1405
|
const ts = Date.now();
|
|
1262
1406
|
try {
|
|
1263
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
|
+
}
|
|
1264
1420
|
totalSent++;
|
|
1265
|
-
|
|
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
|
+
);
|
|
1266
1428
|
} catch (error) {
|
|
1267
1429
|
totalFailed++;
|
|
1268
1430
|
const msg = (error == null ? void 0 : error.response) ? JSON.stringify(error.response.data) : (error == null ? void 0 : error.message) ?? String(error);
|
|
1269
|
-
|
|
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
|
+
);
|
|
1270
1438
|
}
|
|
1271
1439
|
})()
|
|
1272
1440
|
];
|
|
@@ -1280,35 +1448,56 @@ var _Aggregator = class {
|
|
|
1280
1448
|
const ts = Date.now();
|
|
1281
1449
|
try {
|
|
1282
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
|
+
}
|
|
1283
1463
|
totalSent++;
|
|
1284
|
-
|
|
1464
|
+
this.trace(chain, traceReq, "log", "hermes-submitBundleTx-builder-成功", `Builder[${name}] 发送成功, targetBlock=${block}, 耗时=${Date.now() - ts}ms, resp=${JSON.stringify(response.data)}`);
|
|
1285
1465
|
} catch (error) {
|
|
1286
1466
|
totalFailed++;
|
|
1287
1467
|
const msg = (error == null ? void 0 : error.response) ? JSON.stringify(error.response.data) : (error == null ? void 0 : error.message) ?? String(error);
|
|
1288
|
-
|
|
1468
|
+
this.trace(chain, traceReq, "error", "hermes-submitBundleTx-builder-失败", `Builder[${name}] 发送失败, targetBlock=${block}, 耗时=${Date.now() - ts}ms, error=${msg}`);
|
|
1289
1469
|
}
|
|
1290
1470
|
});
|
|
1291
1471
|
});
|
|
1292
1472
|
const abortController = new AbortController();
|
|
1293
1473
|
const inclusionPromise = this.waitForBundleInclusion(provider, txHash, targetBlocks, abortController.signal);
|
|
1294
1474
|
const waitTs = Date.now();
|
|
1475
|
+
this.trace(chain, traceReq, "log", "hermes-submitBundleTx-RPC发送前", `Bundle 请求开始发送, txHash=${txHash}, targetBlocks=[${targetBlocks.join(",")}]`);
|
|
1295
1476
|
const [receipt] = await Promise.all([
|
|
1296
1477
|
inclusionPromise,
|
|
1297
1478
|
Promise.all(fireAndForget).then(() => {
|
|
1298
|
-
|
|
1479
|
+
this.trace(
|
|
1480
|
+
chain,
|
|
1481
|
+
traceReq,
|
|
1482
|
+
"log",
|
|
1483
|
+
"hermes-submitBundleTx-RPC已发送",
|
|
1484
|
+
`Bundle发送完成, 成功=${totalSent}, 失败=${totalFailed}, 总请求=${fireAndForget.length}, 耗时=${Date.now() - sendBundleTs}ms, txHash=${txHash}`
|
|
1485
|
+
);
|
|
1299
1486
|
if (totalSent === 0)
|
|
1300
1487
|
abortController.abort();
|
|
1301
1488
|
})
|
|
1302
1489
|
]);
|
|
1303
1490
|
if (receipt) {
|
|
1304
1491
|
const blockTs = await this.getBlockTimestampStr(provider, receipt.blockNumber);
|
|
1305
|
-
|
|
1492
|
+
this.trace(
|
|
1306
1493
|
chain,
|
|
1494
|
+
traceReq,
|
|
1307
1495
|
"log",
|
|
1496
|
+
"hermes-submitBundleTx-确认完成",
|
|
1308
1497
|
`Bundle上链确认, txHash=${receipt.hash}, blockNumber=${receipt.blockNumber}, 出块时间=${blockTs}, gasUsed=${receipt.gasUsed}, 等待耗时=${Date.now() - waitTs}ms`
|
|
1309
1498
|
);
|
|
1310
1499
|
} else {
|
|
1311
|
-
|
|
1500
|
+
this.trace(chain, traceReq, "warn", "hermes-submitBundleTx-等待结束", `Bundle未在目标区块上链, txHash=${txHash}, 目标区块=[${targetBlocks.join(",")}], 等待耗时=${Date.now() - waitTs}ms`);
|
|
1312
1501
|
}
|
|
1313
1502
|
return { receipt, txHash, targetBlocks };
|
|
1314
1503
|
}
|
|
@@ -1409,8 +1598,8 @@ var _Aggregator = class {
|
|
|
1409
1598
|
return chain === import_types.ChainNameEnum.ETH && !!this.flashbotSigner;
|
|
1410
1599
|
}
|
|
1411
1600
|
stripCustomFields(txReq, chain) {
|
|
1412
|
-
const defaultBlockCount =
|
|
1413
|
-
const { useBundle, bundleBlockCount = defaultBlockCount, ...pureTxReq } = txReq;
|
|
1601
|
+
const defaultBlockCount = this.getDefaultBundleBlockCount(chain);
|
|
1602
|
+
const { useBundle, bundleBlockCount = defaultBlockCount, trace, ...pureTxReq } = txReq;
|
|
1414
1603
|
return { pureTxReq, bundleBlockCount: this.normalizeBundleBlockCount(bundleBlockCount) };
|
|
1415
1604
|
}
|
|
1416
1605
|
normalizeBundleBlockCount(bundleBlockCount) {
|
|
@@ -1444,11 +1633,23 @@ var Aggregator = _Aggregator;
|
|
|
1444
1633
|
Aggregator.DEFAULT_ETH_BUILDERS = {
|
|
1445
1634
|
"beaverbuild.org": "https://rpc.beaverbuild.org",
|
|
1446
1635
|
Titan: "https://rpc.titanbuilder.xyz",
|
|
1636
|
+
"Titan-EU": "https://eu.rpc.titanbuilder.xyz",
|
|
1447
1637
|
flashbots: "https://relay.flashbots.net",
|
|
1448
1638
|
// bloXroute: 'https://mev.api.blxrbdn.com', // 旧 api.blxrbdn.com 也行,需配置 Authorization 头
|
|
1449
|
-
|
|
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",
|
|
1450
1644
|
// 新增,实测直接可用
|
|
1451
|
-
|
|
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
|
|
1452
1653
|
// nfactorial: 'https://rpc.nfactorial.xyz', // 新增,支持 bundle rebate
|
|
1453
1654
|
};
|
|
1454
1655
|
Aggregator.DEFAULT_SEQUENCER_RPC_BY_CHAIN = {
|
package/dist/cjs/aggregator.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ declare class Aggregator {
|
|
|
16
16
|
private static traceLog;
|
|
17
17
|
private static formatBlockTimestamp;
|
|
18
18
|
private getBlockTimestampStr;
|
|
19
|
+
private emitTrace;
|
|
20
|
+
private trace;
|
|
19
21
|
private static readonly DEFAULT_ETH_BUILDERS;
|
|
20
22
|
private static readonly DEFAULT_SEQUENCER_RPC_BY_CHAIN;
|
|
21
23
|
private static readonly SEQUENCER_CHAINS;
|
|
@@ -24,9 +26,11 @@ declare class Aggregator {
|
|
|
24
26
|
getAggregatorAddress(chain: ChainNameEnum): string;
|
|
25
27
|
signRequestBody(body: unknown, signer: ethers.Wallet): Promise<string>;
|
|
26
28
|
private getBuilderConfig;
|
|
29
|
+
private getDefaultBundleBlockCount;
|
|
27
30
|
private getSequencerRpcs;
|
|
28
31
|
private buildBundleRequestBody;
|
|
29
32
|
private buildFlashbotsMevBundleRequestBody;
|
|
33
|
+
private static getJsonRpcErrorMessage;
|
|
30
34
|
sendBundle(chain: ChainNameEnum, rawTxs: string[], targetBlock: number, signer?: ethers.Wallet): Promise<{
|
|
31
35
|
sent: number;
|
|
32
36
|
failed: number;
|