@across-protocol/sdk 4.3.59-alpha.1 → 4.3.59
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/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +8 -295
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/providers/retryProvider.js +6 -4
- package/dist/cjs/providers/retryProvider.js.map +1 -1
- package/dist/cjs/providers/utils.js +1 -1
- package/dist/cjs/providers/utils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +10 -336
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/providers/retryProvider.js +6 -4
- package/dist/esm/providers/retryProvider.js.map +1 -1
- package/dist/esm/providers/utils.js +2 -2
- package/dist/esm/providers/utils.js.map +1 -1
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
- package/dist/types/providers/retryProvider.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/clients/BundleDataClient/BundleDataClient.ts +0 -348
- package/src/providers/retryProvider.ts +6 -4
- package/src/providers/utils.ts +2 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
2
|
import _ from "lodash";
|
|
3
3
|
import {
|
|
4
|
-
ProposedRootBundle,
|
|
5
4
|
SlowFillRequestWithBlock,
|
|
6
5
|
SpokePoolClientsByChain,
|
|
7
6
|
FillType,
|
|
@@ -14,7 +13,6 @@ import {
|
|
|
14
13
|
BundleSlowFills,
|
|
15
14
|
ExpiredDepositsToRefundV3,
|
|
16
15
|
Clients,
|
|
17
|
-
CombinedRefunds,
|
|
18
16
|
FillWithBlock,
|
|
19
17
|
Deposit,
|
|
20
18
|
DepositWithBlock,
|
|
@@ -29,10 +27,8 @@ import {
|
|
|
29
27
|
assign,
|
|
30
28
|
fixedPointAdjustment,
|
|
31
29
|
isDefined,
|
|
32
|
-
toBN,
|
|
33
30
|
forEachAsync,
|
|
34
31
|
getBlockRangeForChain,
|
|
35
|
-
getImpliedBundleBlockRanges,
|
|
36
32
|
getRelayEventKey,
|
|
37
33
|
isSlowFill,
|
|
38
34
|
mapAsync,
|
|
@@ -42,7 +38,6 @@ import {
|
|
|
42
38
|
duplicateEvent,
|
|
43
39
|
invalidOutputToken,
|
|
44
40
|
Address,
|
|
45
|
-
getNetworkName,
|
|
46
41
|
toBytes32,
|
|
47
42
|
convertRelayDataParamsToBytes32,
|
|
48
43
|
convertFillParamsToBytes32,
|
|
@@ -50,10 +45,7 @@ import {
|
|
|
50
45
|
import winston from "winston";
|
|
51
46
|
import {
|
|
52
47
|
BundleDataSS,
|
|
53
|
-
getEndBlockBuffers,
|
|
54
48
|
getRefundInformationFromFill,
|
|
55
|
-
getRefundsFromBundle,
|
|
56
|
-
getWidestPossibleExpectedBlockRange,
|
|
57
49
|
isChainDisabledAtBlock,
|
|
58
50
|
prettyPrintV3SpokePoolEvents,
|
|
59
51
|
V3DepositWithBlock,
|
|
@@ -370,346 +362,6 @@ export class BundleDataClient {
|
|
|
370
362
|
return bundleData;
|
|
371
363
|
}
|
|
372
364
|
|
|
373
|
-
// @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
|
|
374
|
-
async getPendingRefundsFromValidBundles(): Promise<CombinedRefunds[]> {
|
|
375
|
-
const refunds = [];
|
|
376
|
-
if (!this.clients.hubPoolClient.isUpdated) {
|
|
377
|
-
throw new Error("BundleDataClient::getPendingRefundsFromValidBundles HubPoolClient not updated.");
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const bundle = this.clients.hubPoolClient.getLatestFullyExecutedRootBundle(
|
|
381
|
-
this.clients.hubPoolClient.latestHeightSearched
|
|
382
|
-
);
|
|
383
|
-
if (bundle !== undefined) {
|
|
384
|
-
refunds.push(await this.getPendingRefundsFromBundle(bundle));
|
|
385
|
-
} // No more valid bundles in history!
|
|
386
|
-
return refunds;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
|
|
390
|
-
// Return refunds from input bundle.
|
|
391
|
-
async getPendingRefundsFromBundle(bundle: ProposedRootBundle): Promise<CombinedRefunds> {
|
|
392
|
-
const nextBundleMainnetStartBlock = this.clients.hubPoolClient.getNextBundleStartBlockNumber(
|
|
393
|
-
this.chainIdListForBundleEvaluationBlockNumbers,
|
|
394
|
-
this.clients.hubPoolClient.latestHeightSearched,
|
|
395
|
-
this.clients.hubPoolClient.chainId
|
|
396
|
-
);
|
|
397
|
-
const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(nextBundleMainnetStartBlock);
|
|
398
|
-
|
|
399
|
-
// Reconstruct latest bundle block range.
|
|
400
|
-
const bundleEvaluationBlockRanges = getImpliedBundleBlockRanges(
|
|
401
|
-
this.clients.hubPoolClient,
|
|
402
|
-
this.clients.configStoreClient,
|
|
403
|
-
bundle
|
|
404
|
-
);
|
|
405
|
-
let combinedRefunds: CombinedRefunds;
|
|
406
|
-
// Here we don't call loadData because our fallback is to approximate refunds if we don't have arweave data, rather
|
|
407
|
-
// than use the much slower loadData to compute all refunds. We don't need to consider slow fills or deposit
|
|
408
|
-
// expiries here so we can skip some steps. We also don't need to compute LP fees as they should be small enough
|
|
409
|
-
// so as not to affect this approximate refund count.
|
|
410
|
-
const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
|
|
411
|
-
if (!isDefined(arweaveData)) {
|
|
412
|
-
combinedRefunds = await this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
|
|
413
|
-
} else {
|
|
414
|
-
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
415
|
-
combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
|
|
416
|
-
// If we don't have a spoke pool client for a chain, then we won't be able to deduct refunds correctly for this
|
|
417
|
-
// chain. For most of the pending bundle's liveness period, these past refunds are already executed so this is
|
|
418
|
-
// a reasonable assumption. This empty refund chain also matches what the alternative
|
|
419
|
-
// `getApproximateRefundsForBlockRange` would return.
|
|
420
|
-
Object.keys(combinedRefunds).forEach((chainId) => {
|
|
421
|
-
if (!this.spokePoolClientManager.getClient(Number(chainId))) {
|
|
422
|
-
delete combinedRefunds[Number(chainId)];
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// The latest proposed bundle's refund leaves might have already been partially or entirely executed.
|
|
428
|
-
// We have to deduct the executed amounts from the total refund amounts.
|
|
429
|
-
return this.deductExecutedRefunds(combinedRefunds, bundle);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// @dev This helper function should probably be moved to the InventoryClient
|
|
433
|
-
async getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): Promise<CombinedRefunds> {
|
|
434
|
-
const refundsForChain: CombinedRefunds = {};
|
|
435
|
-
const bundleEndBlockForMainnet = blockRanges[0][1];
|
|
436
|
-
for (const chainId of chainIds) {
|
|
437
|
-
const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
|
|
438
|
-
if (!isDefined(spokePoolClient)) {
|
|
439
|
-
continue;
|
|
440
|
-
}
|
|
441
|
-
const chainIndex = chainIds.indexOf(chainId);
|
|
442
|
-
// @dev This function does not account for pre-fill refunds as it is optimized for speed. The way to detect
|
|
443
|
-
// pre-fill refunds is to load all deposits that are unmatched by fills in the spoke pool client's memory
|
|
444
|
-
// and then query the FillStatus on-chain, but that might slow this function down too much. For now, we
|
|
445
|
-
// will live with this expected inaccuracy as it should be small. The pre-fill would have to precede the deposit
|
|
446
|
-
// by more than the caller's event lookback window which is expected to be unlikely.
|
|
447
|
-
const fillsToCount = spokePoolClient.getFills().filter((fill) => {
|
|
448
|
-
if (
|
|
449
|
-
fill.blockNumber < blockRanges[chainIndex][0] ||
|
|
450
|
-
fill.blockNumber > blockRanges[chainIndex][1] ||
|
|
451
|
-
isZeroValueFillOrSlowFillRequest(fill) ||
|
|
452
|
-
invalidOutputToken(fill)
|
|
453
|
-
) {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const originSpokePoolClient = this.spokePoolClientManager.getClient(fill.originChainId);
|
|
458
|
-
// If origin spoke pool client isn't defined, we can't validate it.
|
|
459
|
-
if (!isDefined(originSpokePoolClient)) {
|
|
460
|
-
return false;
|
|
461
|
-
}
|
|
462
|
-
const matchingDeposit = originSpokePoolClient.getDeposit(fill.depositId);
|
|
463
|
-
const hasMatchingDeposit =
|
|
464
|
-
matchingDeposit !== undefined && getRelayEventKey(fill) === getRelayEventKey(matchingDeposit);
|
|
465
|
-
return hasMatchingDeposit;
|
|
466
|
-
});
|
|
467
|
-
await forEachAsync(fillsToCount, async (_fill) => {
|
|
468
|
-
const originChain = getNetworkName(_fill.originChainId);
|
|
469
|
-
const originSpokePoolClient = this.spokePoolClientManager.getClient(_fill.originChainId);
|
|
470
|
-
assert(isDefined(originSpokePoolClient), `No SpokePoolClient for chain ${originChain}`);
|
|
471
|
-
const matchingDeposit = originSpokePoolClient.getDeposit(_fill.depositId);
|
|
472
|
-
assert(
|
|
473
|
-
isDefined(matchingDeposit),
|
|
474
|
-
`No ${originChain} deposit found for ${getNetworkName(_fill.destinationChainId)} fill ${_fill.depositId}`
|
|
475
|
-
);
|
|
476
|
-
|
|
477
|
-
const spokeClient = this.spokePoolClientManager.getClient(_fill.destinationChainId);
|
|
478
|
-
assert(
|
|
479
|
-
isDefined(spokeClient),
|
|
480
|
-
`SpokePoolClient for ${getNetworkName(_fill.destinationChainId)} not found for fill.`
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
let provider;
|
|
484
|
-
if (isEVMSpokePoolClient(spokeClient)) {
|
|
485
|
-
provider = spokeClient.spokePool.provider;
|
|
486
|
-
} else if (isSVMSpokePoolClient(spokeClient)) {
|
|
487
|
-
provider = spokeClient.svmEventsClient.getRpc();
|
|
488
|
-
}
|
|
489
|
-
const fill = await verifyFillRepayment(
|
|
490
|
-
_fill,
|
|
491
|
-
provider!,
|
|
492
|
-
matchingDeposit,
|
|
493
|
-
this.clients.hubPoolClient,
|
|
494
|
-
bundleEndBlockForMainnet
|
|
495
|
-
);
|
|
496
|
-
if (!isDefined(fill)) {
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
|
|
500
|
-
{
|
|
501
|
-
...fill,
|
|
502
|
-
fromLiteChain: matchingDeposit.fromLiteChain,
|
|
503
|
-
},
|
|
504
|
-
this.clients.hubPoolClient,
|
|
505
|
-
bundleEndBlockForMainnet
|
|
506
|
-
);
|
|
507
|
-
// Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
|
|
508
|
-
// these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
|
|
509
|
-
// in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
|
|
510
|
-
// worst from the relayer's perspective.
|
|
511
|
-
const { relayer, inputAmount: refundAmount } = fill;
|
|
512
|
-
refundsForChain[chainToSendRefundTo] ??= {};
|
|
513
|
-
refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()] ??= {};
|
|
514
|
-
const existingRefundAmount =
|
|
515
|
-
refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()][relayer.toBytes32()] ?? bnZero;
|
|
516
|
-
refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()][relayer.toBytes32()] =
|
|
517
|
-
existingRefundAmount.add(refundAmount);
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
return refundsForChain;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
getUpcomingDepositAmount(chainId: number, l2Token: Address, latestBlockToSearch: number): BigNumber {
|
|
524
|
-
const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
|
|
525
|
-
if (!isDefined(spokePoolClient)) {
|
|
526
|
-
return toBN(0);
|
|
527
|
-
}
|
|
528
|
-
return spokePoolClient
|
|
529
|
-
.getDeposits()
|
|
530
|
-
.filter((deposit) => deposit.blockNumber > latestBlockToSearch && deposit.inputToken.eq(l2Token))
|
|
531
|
-
.reduce((acc, deposit) => {
|
|
532
|
-
return acc.add(deposit.inputAmount);
|
|
533
|
-
}, toBN(0));
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
|
|
537
|
-
// Return refunds from the next valid bundle. This will contain any refunds that have been sent but are not included
|
|
538
|
-
// in a valid bundle with all of its leaves executed. This contains refunds from:
|
|
539
|
-
// - Bundles that passed liveness but have not had all of their pool rebalance leaves executed.
|
|
540
|
-
// - Bundles that are pending liveness
|
|
541
|
-
// - Fills sent after the pending, but not validated, bundle
|
|
542
|
-
async getNextBundleRefunds(): Promise<CombinedRefunds[]> {
|
|
543
|
-
const hubPoolClient = this.clients.hubPoolClient;
|
|
544
|
-
const nextBundleMainnetStartBlock = hubPoolClient.getNextBundleStartBlockNumber(
|
|
545
|
-
this.chainIdListForBundleEvaluationBlockNumbers,
|
|
546
|
-
hubPoolClient.latestHeightSearched,
|
|
547
|
-
hubPoolClient.chainId
|
|
548
|
-
);
|
|
549
|
-
const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(nextBundleMainnetStartBlock);
|
|
550
|
-
const combinedRefunds: CombinedRefunds[] = [];
|
|
551
|
-
|
|
552
|
-
// @dev: If spoke pool client is undefined for a chain, then the end block will be null or undefined, which
|
|
553
|
-
// should be handled gracefully and effectively cause this function to ignore refunds for the chain.
|
|
554
|
-
let widestBundleBlockRanges = await getWidestPossibleExpectedBlockRange(
|
|
555
|
-
chainIds,
|
|
556
|
-
this.spokePoolClientManager.getSpokePoolClients(),
|
|
557
|
-
getEndBlockBuffers(chainIds, this.blockRangeEndBlockBuffer),
|
|
558
|
-
this.clients,
|
|
559
|
-
this.clients.hubPoolClient.latestHeightSearched,
|
|
560
|
-
this.clients.configStoreClient.getEnabledChains(this.clients.hubPoolClient.latestHeightSearched)
|
|
561
|
-
);
|
|
562
|
-
// Return block ranges for blocks after _pendingBlockRanges and up to widestBlockRanges.
|
|
563
|
-
// If a chain is disabled or doesn't have a spoke pool client, return a range of 0
|
|
564
|
-
function getBlockRangeDelta(_pendingBlockRanges: number[][]): number[][] {
|
|
565
|
-
return widestBundleBlockRanges.map((blockRange, index) => {
|
|
566
|
-
// If pending block range doesn't have an entry for the widest range, which is possible when a new chain
|
|
567
|
-
// is added to the CHAIN_ID_INDICES list, then simply set the initial block range to the widest block range.
|
|
568
|
-
// This will produce a block range delta of 0 where the returned range for this chain is [widest[1], widest[1]].
|
|
569
|
-
const initialBlockRange = _pendingBlockRanges[index] ?? blockRange;
|
|
570
|
-
// If chain is disabled, return disabled range
|
|
571
|
-
if (initialBlockRange[0] === initialBlockRange[1]) {
|
|
572
|
-
return initialBlockRange;
|
|
573
|
-
}
|
|
574
|
-
// If pending bundle end block exceeds widest end block or if widest end block is undefined
|
|
575
|
-
// (which is possible if the spoke pool client for the chain is not defined), return an empty range since there are no
|
|
576
|
-
// "new" events to consider for this chain.
|
|
577
|
-
if (!isDefined(blockRange[1]) || initialBlockRange[1] >= blockRange[1]) {
|
|
578
|
-
return [initialBlockRange[1], initialBlockRange[1]];
|
|
579
|
-
}
|
|
580
|
-
// If initialBlockRange][0] > widestBlockRange[0], then we'll ignore any blocks
|
|
581
|
-
// between initialBlockRange[0] and widestBlockRange[0] (inclusive) for simplicity reasons. In practice
|
|
582
|
-
// this should not happen.
|
|
583
|
-
return [initialBlockRange[1] + 1, blockRange[1]];
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// If there is a pending bundle that has not been fully executed, then it should have arweave
|
|
588
|
-
// data so we can load it from there.
|
|
589
|
-
if (hubPoolClient.hasPendingProposal()) {
|
|
590
|
-
const pendingBundleBlockRanges = getImpliedBundleBlockRanges(
|
|
591
|
-
hubPoolClient,
|
|
592
|
-
this.clients.configStoreClient,
|
|
593
|
-
hubPoolClient.getLatestProposedRootBundle()
|
|
594
|
-
);
|
|
595
|
-
// Similar to getAppoximateRefundsForBlockRange, we'll skip the full bundle reconstruction if the arweave
|
|
596
|
-
// data is undefined and use the much faster approximation method which doesn't consider LP fees which is
|
|
597
|
-
// ok for this use case.
|
|
598
|
-
const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
|
|
599
|
-
if (!isDefined(arweaveData)) {
|
|
600
|
-
combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
|
|
601
|
-
} else {
|
|
602
|
-
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
603
|
-
combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Shorten the widestBundleBlockRanges now to not double count the pending bundle blocks.
|
|
607
|
-
widestBundleBlockRanges = getBlockRangeDelta(pendingBundleBlockRanges);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// Next, load all refunds sent after the last bundle proposal. This can be expensive so we'll skip the full
|
|
611
|
-
// bundle reconstruction and make some simplifying assumptions:
|
|
612
|
-
// - Only look up fills sent after the pending bundle's end blocks
|
|
613
|
-
// - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
|
|
614
|
-
const start = performance.now();
|
|
615
|
-
combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
|
|
616
|
-
this.logger.debug({
|
|
617
|
-
at: "BundleDataClient#getNextBundleRefunds",
|
|
618
|
-
message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
|
|
619
|
-
blockRanges: JSON.stringify(widestBundleBlockRanges),
|
|
620
|
-
});
|
|
621
|
-
return combinedRefunds;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// @dev This helper function should probably be moved to the InventoryClient
|
|
625
|
-
getExecutedRefunds(
|
|
626
|
-
spokePoolClient: SpokePoolClient,
|
|
627
|
-
relayerRefundRoot: string
|
|
628
|
-
): {
|
|
629
|
-
[tokenAddress: string]: {
|
|
630
|
-
[relayer: string]: BigNumber;
|
|
631
|
-
};
|
|
632
|
-
} {
|
|
633
|
-
if (!isDefined(spokePoolClient)) {
|
|
634
|
-
return {};
|
|
635
|
-
}
|
|
636
|
-
// @dev Search from right to left since there can be multiple root bundles with the same relayer refund root.
|
|
637
|
-
// The caller should take caution if they're trying to use this function to find matching refunds for older
|
|
638
|
-
// root bundles as opposed to more recent ones.
|
|
639
|
-
const bundle = _.findLast(
|
|
640
|
-
spokePoolClient.getRootBundleRelays(),
|
|
641
|
-
(bundle) => bundle.relayerRefundRoot === relayerRefundRoot
|
|
642
|
-
);
|
|
643
|
-
if (bundle === undefined) {
|
|
644
|
-
return {};
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
const executedRefundLeaves = spokePoolClient
|
|
648
|
-
.getRelayerRefundExecutions()
|
|
649
|
-
.filter((leaf) => leaf.rootBundleId === bundle.rootBundleId);
|
|
650
|
-
const executedRefunds: { [tokenAddress: string]: { [relayer: string]: BigNumber } } = {};
|
|
651
|
-
for (const refundLeaf of executedRefundLeaves) {
|
|
652
|
-
const tokenAddress = refundLeaf.l2TokenAddress.toBytes32();
|
|
653
|
-
const executedTokenRefunds = (executedRefunds[tokenAddress] ??= {});
|
|
654
|
-
|
|
655
|
-
for (let i = 0; i < refundLeaf.refundAddresses.length; i++) {
|
|
656
|
-
const relayer = refundLeaf.refundAddresses[i].toBytes32();
|
|
657
|
-
const refundAmount = refundLeaf.refundAmounts[i];
|
|
658
|
-
|
|
659
|
-
executedTokenRefunds[relayer] ??= bnZero;
|
|
660
|
-
executedTokenRefunds[relayer] = executedTokenRefunds[relayer].add(refundAmount);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return executedRefunds;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// @dev This helper function should probably be moved to the InventoryClient
|
|
667
|
-
private deductExecutedRefunds(
|
|
668
|
-
allRefunds: CombinedRefunds,
|
|
669
|
-
bundleContainingRefunds: ProposedRootBundle
|
|
670
|
-
): CombinedRefunds {
|
|
671
|
-
for (const chainIdStr of Object.keys(allRefunds)) {
|
|
672
|
-
const chainId = Number(chainIdStr);
|
|
673
|
-
const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
|
|
674
|
-
if (!isDefined(spokePoolClient)) {
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
const executedRefunds = this.getExecutedRefunds(spokePoolClient, bundleContainingRefunds.relayerRefundRoot);
|
|
678
|
-
|
|
679
|
-
for (const tokenAddress of Object.keys(allRefunds[chainId])) {
|
|
680
|
-
const refunds = allRefunds[chainId][tokenAddress];
|
|
681
|
-
if (executedRefunds[tokenAddress] === undefined || refunds === undefined) {
|
|
682
|
-
continue;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
for (const relayer of Object.keys(refunds)) {
|
|
686
|
-
const executedAmount = executedRefunds[tokenAddress][relayer];
|
|
687
|
-
if (executedAmount === undefined) {
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
// Since there should only be a single executed relayer refund leaf for each relayer-token-chain combination,
|
|
691
|
-
// we can deduct this refund and mark it as executed if the executed amount is > 0.
|
|
692
|
-
refunds[relayer] = bnZero;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
return allRefunds;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
getRefundsFor(bundleRefunds: CombinedRefunds, relayer: Address, chainId: number, token: Address): BigNumber {
|
|
700
|
-
if (!bundleRefunds[chainId] || !bundleRefunds[chainId][token.toBytes32()]) {
|
|
701
|
-
return BigNumber.from(0);
|
|
702
|
-
}
|
|
703
|
-
const allRefunds = bundleRefunds[chainId][token.toBytes32()];
|
|
704
|
-
return allRefunds && allRefunds[relayer.toBytes32()] ? allRefunds[relayer.toBytes32()] : BigNumber.from(0);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
getTotalRefund(refunds: CombinedRefunds[], relayer: Address, chainId: number, refundToken: Address): BigNumber {
|
|
708
|
-
return refunds.reduce((totalRefund, refunds) => {
|
|
709
|
-
return totalRefund.add(this.getRefundsFor(refunds, relayer, chainId, refundToken));
|
|
710
|
-
}, bnZero);
|
|
711
|
-
}
|
|
712
|
-
|
|
713
365
|
private async loadArweaveData(blockRangesForChains: number[][]): Promise<LoadDataReturnValue> {
|
|
714
366
|
const arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
|
|
715
367
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
@@ -111,7 +111,9 @@ export class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
|
|
|
111
111
|
if (!results.every(isPromiseFulfilled)) {
|
|
112
112
|
// Format the error so that it's very clear which providers failed and succeeded.
|
|
113
113
|
const errorTexts = errors.map(([provider, errorText]) => formatProviderError(provider, errorText));
|
|
114
|
-
const successfulProviderUrls = results
|
|
114
|
+
const successfulProviderUrls = results
|
|
115
|
+
.filter(isPromiseFulfilled)
|
|
116
|
+
.map((result) => getOriginFromURL(result.value[0].connection.url));
|
|
115
117
|
throw createSendErrorWithMessage(
|
|
116
118
|
`Not enough providers succeeded. Errors:\n${errorTexts.join("\n")}\n` +
|
|
117
119
|
`Successful Providers:\n${successfulProviderUrls.join("\n")}`,
|
|
@@ -130,7 +132,7 @@ export class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
|
|
|
130
132
|
const getMismatchedProviders = (values: [ethers.providers.StaticJsonRpcProvider, unknown][]) => {
|
|
131
133
|
return values
|
|
132
134
|
.filter(([, result]) => !compareRpcResults(method, result, quorumResult))
|
|
133
|
-
.map(([provider]) => provider.connection.url);
|
|
135
|
+
.map(([provider]) => getOriginFromURL(provider.connection.url));
|
|
134
136
|
};
|
|
135
137
|
|
|
136
138
|
const logQuorumMismatchOrFailureDetails = (
|
|
@@ -154,7 +156,7 @@ export class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
|
|
|
154
156
|
|
|
155
157
|
const throwQuorumError = (fallbackValues?: [ethers.providers.StaticJsonRpcProvider, unknown][]) => {
|
|
156
158
|
const errorTexts = errors.map(([provider, errorText]) => formatProviderError(provider, errorText));
|
|
157
|
-
const successfulProviderUrls = values.map(([provider]) => provider.connection.url);
|
|
159
|
+
const successfulProviderUrls = values.map(([provider]) => getOriginFromURL(provider.connection.url));
|
|
158
160
|
const mismatchedProviders = getMismatchedProviders([...values, ...(fallbackValues || [])]);
|
|
159
161
|
logQuorumMismatchOrFailureDetails(method, params, successfulProviderUrls, mismatchedProviders, errors);
|
|
160
162
|
throw new Error(
|
|
@@ -222,7 +224,7 @@ export class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
|
|
|
222
224
|
const mismatchedProviders = getMismatchedProviders([...values, ...fallbackValues]);
|
|
223
225
|
const quorumProviders = [...values, ...fallbackValues]
|
|
224
226
|
.filter(([, result]) => compareRpcResults(method, result, quorumResult))
|
|
225
|
-
.map(([provider]) => provider.connection.url);
|
|
227
|
+
.map(([provider]) => getOriginFromURL(provider.connection.url));
|
|
226
228
|
if (mismatchedProviders.length > 0 || errors.length > 0) {
|
|
227
229
|
logQuorumMismatchOrFailureDetails(method, params, quorumProviders, mismatchedProviders, errors);
|
|
228
230
|
}
|
package/src/providers/utils.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import assert from "assert";
|
|
3
3
|
import { providers } from "ethers";
|
|
4
4
|
import { isEqual } from "lodash";
|
|
5
|
-
import { isDefined } from "../utils";
|
|
5
|
+
import { getOriginFromURL, isDefined } from "../utils";
|
|
6
6
|
import { RPCProvider, RPCTransport } from "./types";
|
|
7
7
|
import * as alchemy from "./alchemy";
|
|
8
8
|
import * as infura from "./infura";
|
|
@@ -133,7 +133,7 @@ export interface RateLimitTask {
|
|
|
133
133
|
* @returns The formatted error message.
|
|
134
134
|
*/
|
|
135
135
|
export function formatProviderError(provider: providers.StaticJsonRpcProvider, rawErrorText: string) {
|
|
136
|
-
return `Provider ${provider.connection.url} failed with error: ${rawErrorText}`;
|
|
136
|
+
return `Provider ${getOriginFromURL(provider.connection.url)} failed with error: ${rawErrorText}`;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
export function createSendErrorWithMessage(message: string, sendError: Record<string, unknown>) {
|