@across-protocol/sdk 4.0.0-beta.19 → 4.0.0-beta.2
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 +4 -5
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +176 -308
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +1 -3
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +1 -33
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient.d.ts +0 -1
- package/dist/cjs/clients/SpokePoolClient.js +4 -13
- package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
- package/dist/cjs/constants.d.ts +0 -1
- package/dist/cjs/constants.js +1 -2
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/providers/index.d.ts +0 -1
- package/dist/cjs/providers/index.js +0 -2
- package/dist/cjs/providers/index.js.map +1 -1
- package/dist/cjs/utils/AddressUtils.d.ts +0 -1
- package/dist/cjs/utils/AddressUtils.js +1 -14
- package/dist/cjs/utils/AddressUtils.js.map +1 -1
- package/dist/cjs/utils/CachingUtils.js +1 -1
- package/dist/cjs/utils/CachingUtils.js.map +1 -1
- package/dist/cjs/utils/DepositUtils.d.ts +1 -2
- package/dist/cjs/utils/DepositUtils.js +3 -12
- package/dist/cjs/utils/DepositUtils.js.map +1 -1
- package/dist/cjs/utils/NetworkUtils.d.ts +0 -1
- package/dist/cjs/utils/NetworkUtils.js +1 -6
- package/dist/cjs/utils/NetworkUtils.js.map +1 -1
- package/dist/cjs/utils/SpokeUtils.js +3 -3
- package/dist/cjs/utils/SpokeUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +4 -5
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +214 -370
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +1 -3
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +1 -42
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient.d.ts +0 -8
- package/dist/esm/clients/SpokePoolClient.js +4 -20
- package/dist/esm/clients/SpokePoolClient.js.map +1 -1
- package/dist/esm/constants.d.ts +0 -1
- package/dist/esm/constants.js +1 -2
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/providers/index.d.ts +0 -1
- package/dist/esm/providers/index.js +0 -2
- package/dist/esm/providers/index.js.map +1 -1
- package/dist/esm/utils/AddressUtils.d.ts +0 -1
- package/dist/esm/utils/AddressUtils.js +0 -16
- package/dist/esm/utils/AddressUtils.js.map +1 -1
- package/dist/esm/utils/CachingUtils.js +1 -1
- package/dist/esm/utils/CachingUtils.js.map +1 -1
- package/dist/esm/utils/DepositUtils.d.ts +1 -2
- package/dist/esm/utils/DepositUtils.js +3 -12
- package/dist/esm/utils/DepositUtils.js.map +1 -1
- package/dist/esm/utils/NetworkUtils.d.ts +0 -6
- package/dist/esm/utils/NetworkUtils.js +0 -10
- package/dist/esm/utils/NetworkUtils.js.map +1 -1
- package/dist/esm/utils/SpokeUtils.js +4 -4
- package/dist/esm/utils/SpokeUtils.js.map +1 -1
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +4 -5
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +1 -3
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient.d.ts +0 -8
- package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/constants.d.ts +0 -1
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/providers/index.d.ts +0 -1
- package/dist/types/providers/index.d.ts.map +1 -1
- package/dist/types/utils/AddressUtils.d.ts +0 -1
- package/dist/types/utils/AddressUtils.d.ts.map +1 -1
- package/dist/types/utils/DepositUtils.d.ts +1 -2
- package/dist/types/utils/DepositUtils.d.ts.map +1 -1
- package/dist/types/utils/NetworkUtils.d.ts +0 -6
- package/dist/types/utils/NetworkUtils.d.ts.map +1 -1
- package/dist/types/utils/SpokeUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/clients/BundleDataClient/BundleDataClient.ts +215 -375
- package/src/clients/BundleDataClient/utils/FillUtils.ts +2 -47
- package/src/clients/SpokePoolClient.ts +6 -19
- package/src/constants.ts +1 -3
- package/src/providers/index.ts +0 -1
- package/src/utils/AddressUtils.ts +0 -16
- package/src/utils/CachingUtils.ts +1 -1
- package/src/utils/DepositUtils.ts +3 -12
- package/src/utils/NetworkUtils.ts +0 -11
- package/src/utils/SpokeUtils.ts +5 -6
- package/dist/cjs/providers/mockProvider.d.ts +0 -19
- package/dist/cjs/providers/mockProvider.js +0 -70
- package/dist/cjs/providers/mockProvider.js.map +0 -1
- package/dist/esm/providers/mockProvider.d.ts +0 -23
- package/dist/esm/providers/mockProvider.js +0 -73
- package/dist/esm/providers/mockProvider.js.map +0 -1
- package/dist/types/providers/mockProvider.d.ts +0 -24
- package/dist/types/providers/mockProvider.d.ts.map +0 -1
- package/src/providers/mockProvider.ts +0 -77
|
@@ -33,13 +33,10 @@ import {
|
|
|
33
33
|
getImpliedBundleBlockRanges,
|
|
34
34
|
isSlowFill,
|
|
35
35
|
mapAsync,
|
|
36
|
-
filterAsync,
|
|
37
36
|
bnUint32Max,
|
|
38
37
|
isZeroValueDeposit,
|
|
39
38
|
findFillEvent,
|
|
40
39
|
isZeroValueFillOrSlowFillRequest,
|
|
41
|
-
chainIsEvm,
|
|
42
|
-
isValidEvmAddress,
|
|
43
40
|
} from "../../utils";
|
|
44
41
|
import winston from "winston";
|
|
45
42
|
import {
|
|
@@ -54,9 +51,7 @@ import {
|
|
|
54
51
|
prettyPrintV3SpokePoolEvents,
|
|
55
52
|
V3DepositWithBlock,
|
|
56
53
|
V3FillWithBlock,
|
|
57
|
-
verifyFillRepayment,
|
|
58
54
|
} from "./utils";
|
|
59
|
-
import { PRE_FILL_MIN_CONFIG_STORE_VERSION } from "../../constants";
|
|
60
55
|
|
|
61
56
|
// max(uint256) - 1
|
|
62
57
|
export const INFINITE_FILL_DEADLINE = bnUint32Max;
|
|
@@ -65,10 +60,6 @@ type DataCache = Record<string, Promise<LoadDataReturnValue>>;
|
|
|
65
60
|
|
|
66
61
|
// V3 dictionary helper functions
|
|
67
62
|
function updateExpiredDepositsV3(dict: ExpiredDepositsToRefundV3, deposit: V3DepositWithBlock): void {
|
|
68
|
-
// A deposit refund for a deposit is invalid if the depositor has a bytes32 address input for an EVM chain. It is valid otherwise.
|
|
69
|
-
if (chainIsEvm(deposit.originChainId) && !isValidEvmAddress(deposit.depositor)) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
63
|
const { originChainId, inputToken } = deposit;
|
|
73
64
|
if (!dict?.[originChainId]?.[inputToken]) {
|
|
74
65
|
assign(dict, [originChainId, inputToken], []);
|
|
@@ -89,13 +80,8 @@ function updateBundleFillsV3(
|
|
|
89
80
|
fill: V3FillWithBlock,
|
|
90
81
|
lpFeePct: BigNumber,
|
|
91
82
|
repaymentChainId: number,
|
|
92
|
-
repaymentToken: string
|
|
93
|
-
repaymentAddress: string
|
|
83
|
+
repaymentToken: string
|
|
94
84
|
): void {
|
|
95
|
-
// It is impossible to refund a deposit if the repayment chain is EVM and the relayer is a non-evm address.
|
|
96
|
-
if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(repaymentAddress)) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
85
|
if (!dict?.[repaymentChainId]?.[repaymentToken]) {
|
|
100
86
|
assign(dict, [repaymentChainId, repaymentToken], {
|
|
101
87
|
fills: [],
|
|
@@ -105,19 +91,19 @@ function updateBundleFillsV3(
|
|
|
105
91
|
});
|
|
106
92
|
}
|
|
107
93
|
|
|
108
|
-
const bundleFill: BundleFillV3 = { ...fill, lpFeePct
|
|
94
|
+
const bundleFill: BundleFillV3 = { ...fill, lpFeePct };
|
|
109
95
|
|
|
110
96
|
// Add all fills, slow and fast, to dictionary.
|
|
111
97
|
assign(dict, [repaymentChainId, repaymentToken, "fills"], [bundleFill]);
|
|
112
98
|
|
|
113
99
|
// All fills update the bundle LP fees.
|
|
114
100
|
const refundObj = dict[repaymentChainId][repaymentToken];
|
|
115
|
-
const realizedLpFee =
|
|
101
|
+
const realizedLpFee = fill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
|
|
116
102
|
refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
|
|
117
103
|
|
|
118
104
|
// Only fast fills get refunded.
|
|
119
|
-
if (!isSlowFill(
|
|
120
|
-
const refundAmount =
|
|
105
|
+
if (!isSlowFill(fill)) {
|
|
106
|
+
const refundAmount = fill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
|
|
121
107
|
refundObj.totalRefundAmount = refundObj.totalRefundAmount
|
|
122
108
|
? refundObj.totalRefundAmount.add(refundAmount)
|
|
123
109
|
: refundAmount;
|
|
@@ -125,10 +111,10 @@ function updateBundleFillsV3(
|
|
|
125
111
|
// Instantiate dictionary if it doesn't exist.
|
|
126
112
|
refundObj.refunds ??= {};
|
|
127
113
|
|
|
128
|
-
if (refundObj.refunds[
|
|
129
|
-
refundObj.refunds[
|
|
114
|
+
if (refundObj.refunds[fill.relayer]) {
|
|
115
|
+
refundObj.refunds[fill.relayer] = refundObj.refunds[fill.relayer].add(refundAmount);
|
|
130
116
|
} else {
|
|
131
|
-
refundObj.refunds[
|
|
117
|
+
refundObj.refunds[fill.relayer] = refundAmount;
|
|
132
118
|
}
|
|
133
119
|
}
|
|
134
120
|
}
|
|
@@ -296,7 +282,7 @@ export class BundleDataClient {
|
|
|
296
282
|
// so as not to affect this approximate refund count.
|
|
297
283
|
const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
|
|
298
284
|
if (arweaveData === undefined) {
|
|
299
|
-
combinedRefunds =
|
|
285
|
+
combinedRefunds = this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
|
|
300
286
|
} else {
|
|
301
287
|
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
302
288
|
combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
|
|
@@ -317,72 +303,50 @@ export class BundleDataClient {
|
|
|
317
303
|
}
|
|
318
304
|
|
|
319
305
|
// @dev This helper function should probably be moved to the InventoryClient
|
|
320
|
-
|
|
306
|
+
getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): CombinedRefunds {
|
|
321
307
|
const refundsForChain: CombinedRefunds = {};
|
|
322
308
|
for (const chainId of chainIds) {
|
|
323
309
|
if (this.spokePoolClients[chainId] === undefined) {
|
|
324
310
|
continue;
|
|
325
311
|
}
|
|
326
312
|
const chainIndex = chainIds.indexOf(chainId);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
if (
|
|
334
|
-
fill.blockNumber < blockRanges[chainIndex][0] ||
|
|
335
|
-
fill.blockNumber > blockRanges[chainIndex][1] ||
|
|
336
|
-
isZeroValueFillOrSlowFillRequest(fill)
|
|
337
|
-
) {
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
313
|
+
this.spokePoolClients[chainId]
|
|
314
|
+
.getFills()
|
|
315
|
+
.filter((fill) => {
|
|
316
|
+
if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
340
319
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
346
|
-
const hasMatchingDeposit =
|
|
347
|
-
matchingDeposit !== undefined &&
|
|
348
|
-
this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
|
|
349
|
-
if (hasMatchingDeposit) {
|
|
350
|
-
const validRepayment = await verifyFillRepayment(
|
|
351
|
-
fill,
|
|
352
|
-
this.spokePoolClients[fill.destinationChainId].spokePool.provider,
|
|
353
|
-
matchingDeposit,
|
|
354
|
-
// @dev: to get valid repayment chain ID's, get all chain IDs for the bundle block range and remove
|
|
355
|
-
// disabled block ranges.
|
|
356
|
-
this.clients.configStoreClient
|
|
357
|
-
.getChainIdIndicesForBlock(blockRanges[0][1])
|
|
358
|
-
.filter((_chainId, i) => !isChainDisabled(blockRanges[i]))
|
|
359
|
-
);
|
|
360
|
-
if (!isDefined(validRepayment)) {
|
|
320
|
+
// If origin spoke pool client isn't defined, we can't validate it.
|
|
321
|
+
if (this.spokePoolClients[fill.originChainId] === undefined) {
|
|
361
322
|
return false;
|
|
362
323
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
fill
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
324
|
+
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
325
|
+
const hasMatchingDeposit =
|
|
326
|
+
matchingDeposit !== undefined &&
|
|
327
|
+
this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
|
|
328
|
+
return hasMatchingDeposit;
|
|
329
|
+
})
|
|
330
|
+
.forEach((fill) => {
|
|
331
|
+
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
332
|
+
assert(isDefined(matchingDeposit), "Deposit not found for fill.");
|
|
333
|
+
const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
|
|
334
|
+
fill,
|
|
335
|
+
this.clients.hubPoolClient,
|
|
336
|
+
blockRanges,
|
|
337
|
+
this.chainIdListForBundleEvaluationBlockNumbers,
|
|
338
|
+
matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
|
|
339
|
+
);
|
|
340
|
+
// Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
|
|
341
|
+
// these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
|
|
342
|
+
// in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
|
|
343
|
+
// worst from the relayer's perspective.
|
|
344
|
+
const { relayer, inputAmount: refundAmount } = fill;
|
|
345
|
+
refundsForChain[chainToSendRefundTo] ??= {};
|
|
346
|
+
refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
|
|
347
|
+
const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
|
|
348
|
+
refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
|
|
349
|
+
});
|
|
386
350
|
}
|
|
387
351
|
return refundsForChain;
|
|
388
352
|
}
|
|
@@ -509,7 +473,7 @@ export class BundleDataClient {
|
|
|
509
473
|
// ok for this use case.
|
|
510
474
|
const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
|
|
511
475
|
if (arweaveData === undefined) {
|
|
512
|
-
combinedRefunds.push(
|
|
476
|
+
combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
|
|
513
477
|
} else {
|
|
514
478
|
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
515
479
|
combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
|
|
@@ -524,7 +488,7 @@ export class BundleDataClient {
|
|
|
524
488
|
// - Only look up fills sent after the pending bundle's end blocks
|
|
525
489
|
// - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
|
|
526
490
|
const start = performance.now();
|
|
527
|
-
combinedRefunds.push(
|
|
491
|
+
combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
|
|
528
492
|
this.logger.debug({
|
|
529
493
|
at: "BundleDataClient#getNextBundleRefunds",
|
|
530
494
|
message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
|
|
@@ -722,10 +686,6 @@ export class BundleDataClient {
|
|
|
722
686
|
);
|
|
723
687
|
};
|
|
724
688
|
|
|
725
|
-
const _depositIsExpired = (deposit: DepositWithBlock): boolean => {
|
|
726
|
-
return deposit.fillDeadline < bundleBlockTimestamps[deposit.destinationChainId][1];
|
|
727
|
-
};
|
|
728
|
-
|
|
729
689
|
const _getFillStatusForDeposit = (deposit: Deposit, queryBlock: number): Promise<FillStatus> => {
|
|
730
690
|
return spokePoolClients[deposit.destinationChainId].relayFillStatus(
|
|
731
691
|
deposit,
|
|
@@ -777,7 +737,7 @@ export class BundleDataClient {
|
|
|
777
737
|
// Note: Since there are no partial fills in v3, there should only be one fill per relay hash.
|
|
778
738
|
// Moreover, the SpokePool blocks multiple slow fill requests, so
|
|
779
739
|
// there should also only be one slow fill request per relay hash.
|
|
780
|
-
|
|
740
|
+
deposit?: V3DepositWithBlock;
|
|
781
741
|
fill?: V3FillWithBlock;
|
|
782
742
|
slowFillRequest?: SlowFillRequestWithBlock;
|
|
783
743
|
};
|
|
@@ -788,27 +748,6 @@ export class BundleDataClient {
|
|
|
788
748
|
const bundleDepositHashes: string[] = [];
|
|
789
749
|
const olderDepositHashes: string[] = [];
|
|
790
750
|
|
|
791
|
-
const decodeBundleDepositHash = (depositHash: string): { relayDataHash: string; index: number } => {
|
|
792
|
-
const [relayDataHash, i] = depositHash.split("@");
|
|
793
|
-
return { relayDataHash, index: Number(i) };
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
// We use the following toggle to aid with the migration to pre-fills. The first bundle proposed using this
|
|
797
|
-
// pre-fill logic can double refund pre-fills that have already been filled in the last bundle, because the
|
|
798
|
-
// last bundle did not recognize a fill as a pre-fill. Therefore the developer should ensure that the version
|
|
799
|
-
// is bumped to the PRE_FILL_MIN_CONFIG_STORE_VERSION version before the first pre-fill bundle is proposed.
|
|
800
|
-
// To test the following bundle after this, the developer can set the FORCE_REFUND_PREFILLS environment variable
|
|
801
|
-
// to "true" simulate the bundle with pre-fill refunds.
|
|
802
|
-
// @todo Remove this logic once we have advanced sufficiently past the pre-fill migration.
|
|
803
|
-
const startBlockForMainnet = getBlockRangeForChain(
|
|
804
|
-
blockRangesForChains,
|
|
805
|
-
this.clients.hubPoolClient.chainId,
|
|
806
|
-
this.chainIdListForBundleEvaluationBlockNumbers
|
|
807
|
-
)[0];
|
|
808
|
-
const versionAtProposalBlock = this.clients.configStoreClient.getConfigStoreVersionForBlock(startBlockForMainnet);
|
|
809
|
-
const canRefundPrefills =
|
|
810
|
-
versionAtProposalBlock >= PRE_FILL_MIN_CONFIG_STORE_VERSION || process.env.FORCE_REFUND_PREFILLS === "true";
|
|
811
|
-
|
|
812
751
|
let depositCounter = 0;
|
|
813
752
|
for (const originChainId of allChainIds) {
|
|
814
753
|
const originClient = spokePoolClients[originChainId];
|
|
@@ -822,20 +761,17 @@ export class BundleDataClient {
|
|
|
822
761
|
// Only evaluate deposits that are in this bundle or in previous bundles. This means we cannot issue fill
|
|
823
762
|
// refunds or slow fills here for deposits that are in future bundles (i.e. "pre-fills"). Instead, we'll
|
|
824
763
|
// evaluate these pre-fills once the deposit is inside the "current" bundle block range.
|
|
825
|
-
if (deposit.blockNumber > originChainBlockRange[1]
|
|
764
|
+
if (isZeroValueDeposit(deposit) || deposit.blockNumber > originChainBlockRange[1]) {
|
|
826
765
|
return;
|
|
827
766
|
}
|
|
828
767
|
depositCounter++;
|
|
829
768
|
const relayDataHash = this.getRelayHashFromEvent(deposit);
|
|
830
|
-
|
|
831
769
|
if (!v3RelayHashes[relayDataHash]) {
|
|
832
770
|
v3RelayHashes[relayDataHash] = {
|
|
833
|
-
|
|
771
|
+
deposit: deposit,
|
|
834
772
|
fill: undefined,
|
|
835
773
|
slowFillRequest: undefined,
|
|
836
774
|
};
|
|
837
|
-
} else {
|
|
838
|
-
v3RelayHashes[relayDataHash].deposits!.push(deposit);
|
|
839
775
|
}
|
|
840
776
|
|
|
841
777
|
// Once we've saved the deposit hash into v3RelayHashes, then we can exit early here if the inputAmount
|
|
@@ -846,20 +782,11 @@ export class BundleDataClient {
|
|
|
846
782
|
return;
|
|
847
783
|
}
|
|
848
784
|
|
|
849
|
-
// Evaluate all expired deposits after fetching fill statuses,
|
|
850
|
-
// since we can't know for certain whether an expired deposit was filled a long time ago.
|
|
851
|
-
const newBundleDepositHash = `${relayDataHash}@${v3RelayHashes[relayDataHash].deposits!.length - 1}`;
|
|
852
|
-
const decodedBundleDepositHash = decodeBundleDepositHash(newBundleDepositHash);
|
|
853
|
-
assert(
|
|
854
|
-
decodedBundleDepositHash.relayDataHash === relayDataHash &&
|
|
855
|
-
decodedBundleDepositHash.index === v3RelayHashes[relayDataHash].deposits!.length - 1,
|
|
856
|
-
"Not using correct bundle deposit hash key"
|
|
857
|
-
);
|
|
858
785
|
if (deposit.blockNumber >= originChainBlockRange[0]) {
|
|
859
|
-
bundleDepositHashes.push(
|
|
786
|
+
bundleDepositHashes.push(relayDataHash);
|
|
860
787
|
updateBundleDepositsV3(bundleDepositsV3, deposit);
|
|
861
788
|
} else if (deposit.blockNumber < originChainBlockRange[0]) {
|
|
862
|
-
olderDepositHashes.push(
|
|
789
|
+
olderDepositHashes.push(relayDataHash);
|
|
863
790
|
}
|
|
864
791
|
});
|
|
865
792
|
}
|
|
@@ -898,69 +825,44 @@ export class BundleDataClient {
|
|
|
898
825
|
(fill) => fill.blockNumber <= destinationChainBlockRange[1] && !isZeroValueFillOrSlowFillRequest(fill)
|
|
899
826
|
),
|
|
900
827
|
async (fill) => {
|
|
901
|
-
fillCounter++;
|
|
902
828
|
const relayDataHash = this.getRelayHashFromEvent(fill);
|
|
829
|
+
fillCounter++;
|
|
830
|
+
|
|
903
831
|
if (v3RelayHashes[relayDataHash]) {
|
|
904
832
|
if (!v3RelayHashes[relayDataHash].fill) {
|
|
905
833
|
assert(
|
|
906
|
-
isDefined(v3RelayHashes[relayDataHash].
|
|
834
|
+
isDefined(v3RelayHashes[relayDataHash].deposit),
|
|
907
835
|
"Deposit should exist in relay hash dictionary."
|
|
908
836
|
);
|
|
909
837
|
// At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
|
|
910
|
-
// so this fill
|
|
838
|
+
// so this fill is validated.
|
|
911
839
|
v3RelayHashes[relayDataHash].fill = fill;
|
|
912
840
|
if (fill.blockNumber >= destinationChainBlockRange[0]) {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
destinationClient.spokePool.provider,
|
|
918
|
-
v3RelayHashes[relayDataHash].deposits![0],
|
|
919
|
-
allChainIds
|
|
920
|
-
);
|
|
921
|
-
if (!isDefined(fillToRefund)) {
|
|
922
|
-
bundleInvalidFillsV3.push(fill);
|
|
923
|
-
// We don't return here yet because we still need to mark unexecutable slow fill leaves
|
|
924
|
-
// or duplicate deposits. However, we won't issue a fast fill refund.
|
|
925
|
-
} else {
|
|
926
|
-
v3RelayHashes[relayDataHash].fill = fillToRefund;
|
|
927
|
-
validatedBundleV3Fills.push({
|
|
928
|
-
...fillToRefund,
|
|
929
|
-
quoteTimestamp: v3RelayHashes[relayDataHash].deposits![0].quoteTimestamp, // ! due to assert above
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
|
|
841
|
+
validatedBundleV3Fills.push({
|
|
842
|
+
...fill,
|
|
843
|
+
quoteTimestamp: v3RelayHashes[relayDataHash].deposit!.quoteTimestamp, // ! due to assert above
|
|
844
|
+
});
|
|
933
845
|
// If fill replaced a slow fill request, then mark it as one that might have created an
|
|
934
846
|
// unexecutable slow fill. We can't know for sure until we check the slow fill request
|
|
935
847
|
// events.
|
|
936
848
|
// slow fill requests for deposits from or to lite chains are considered invalid
|
|
937
849
|
if (
|
|
938
850
|
fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
|
|
939
|
-
|
|
851
|
+
!v3RelayHashes[relayDataHash].deposit!.fromLiteChain &&
|
|
852
|
+
!v3RelayHashes[relayDataHash].deposit!.toLiteChain
|
|
940
853
|
) {
|
|
941
854
|
fastFillsReplacingSlowFills.push(relayDataHash);
|
|
942
855
|
}
|
|
943
|
-
// Now that know this deposit has been filled on-chain, identify any duplicate deposits sent for this fill and refund
|
|
944
|
-
// them, because they would not be refunded otherwise. These deposits can no longer expire and get
|
|
945
|
-
// refunded as an expired deposit, and they won't trigger a pre-fill refund because the fill is
|
|
946
|
-
// in this bundle. Pre-fill refunds only happen when deposits are sent in this bundle and the
|
|
947
|
-
// fill is from a prior bundle.
|
|
948
|
-
const duplicateDeposits = v3RelayHashes[relayDataHash].deposits!.slice(1);
|
|
949
|
-
duplicateDeposits.forEach((duplicateDeposit) => {
|
|
950
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
|
|
951
|
-
});
|
|
952
856
|
}
|
|
953
|
-
} else {
|
|
954
|
-
throw new Error("Duplicate fill detected.");
|
|
955
857
|
}
|
|
956
858
|
return;
|
|
957
859
|
}
|
|
958
860
|
|
|
959
861
|
// At this point, there is no relay hash dictionary entry for this fill, so we need to
|
|
960
|
-
// instantiate the entry.
|
|
862
|
+
// instantiate the entry.
|
|
961
863
|
v3RelayHashes[relayDataHash] = {
|
|
962
|
-
|
|
963
|
-
fill,
|
|
864
|
+
deposit: undefined,
|
|
865
|
+
fill: fill,
|
|
964
866
|
slowFillRequest: undefined,
|
|
965
867
|
};
|
|
966
868
|
|
|
@@ -988,42 +890,24 @@ export class BundleDataClient {
|
|
|
988
890
|
bundleInvalidFillsV3.push(fill);
|
|
989
891
|
} else {
|
|
990
892
|
const matchedDeposit = historicalDeposit.deposit;
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
// Don't return yet as we still need to mark down any unexecutable slow fill leaves
|
|
1002
|
-
// in case this fast fill replaced a slow fill request.
|
|
1003
|
-
} else {
|
|
1004
|
-
// @dev Since queryHistoricalDepositForFill validates the fill by checking individual
|
|
1005
|
-
// object property values against the deposit's, we
|
|
1006
|
-
// sanity check it here by comparing the full relay hashes. If there's an error here then the
|
|
1007
|
-
// historical deposit query is not working as expected.
|
|
1008
|
-
assert(this.getRelayHashFromEvent(matchedDeposit) === relayDataHash, "Relay hashes should match.");
|
|
1009
|
-
validatedBundleV3Fills.push({
|
|
1010
|
-
...fillToRefund,
|
|
1011
|
-
quoteTimestamp: matchedDeposit.quoteTimestamp,
|
|
1012
|
-
});
|
|
1013
|
-
v3RelayHashes[relayDataHash].fill = fillToRefund;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
893
|
+
// @dev Since queryHistoricalDepositForFill validates the fill by checking individual
|
|
894
|
+
// object property values against the deposit's, we
|
|
895
|
+
// sanity check it here by comparing the full relay hashes. If there's an error here then the
|
|
896
|
+
// historical deposit query is not working as expected.
|
|
897
|
+
assert(this.getRelayHashFromEvent(matchedDeposit) === relayDataHash, "Relay hashes should match.");
|
|
898
|
+
validatedBundleV3Fills.push({
|
|
899
|
+
...fill,
|
|
900
|
+
quoteTimestamp: matchedDeposit.quoteTimestamp,
|
|
901
|
+
});
|
|
902
|
+
v3RelayHashes[relayDataHash].deposit = matchedDeposit;
|
|
1016
903
|
// slow fill requests for deposits from or to lite chains are considered invalid
|
|
1017
904
|
if (
|
|
1018
905
|
fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
|
|
1019
|
-
|
|
906
|
+
!matchedDeposit.fromLiteChain &&
|
|
907
|
+
!matchedDeposit.toLiteChain
|
|
1020
908
|
) {
|
|
1021
909
|
fastFillsReplacingSlowFills.push(relayDataHash);
|
|
1022
910
|
}
|
|
1023
|
-
|
|
1024
|
-
// No need to check for duplicate deposits here since we would have seen them in memory if they
|
|
1025
|
-
// had a non-infinite fill deadline, and duplicate deposits with infinite deadlines are impossible
|
|
1026
|
-
// to send.
|
|
1027
911
|
}
|
|
1028
912
|
}
|
|
1029
913
|
}
|
|
@@ -1048,40 +932,38 @@ export class BundleDataClient {
|
|
|
1048
932
|
v3RelayHashes[relayDataHash].slowFillRequest = slowFillRequest;
|
|
1049
933
|
if (v3RelayHashes[relayDataHash].fill) {
|
|
1050
934
|
// If there is a fill matching the relay hash, then this slow fill request can't be used
|
|
1051
|
-
// to create a slow fill for a filled deposit.
|
|
1052
|
-
// slow fill requests must precede fills, so if there is a matching fill for this request's
|
|
1053
|
-
// relay data, then this slow fill will be unexecutable.
|
|
935
|
+
// to create a slow fill for a filled deposit.
|
|
1054
936
|
return;
|
|
1055
937
|
}
|
|
1056
938
|
assert(
|
|
1057
|
-
isDefined(v3RelayHashes[relayDataHash].
|
|
939
|
+
isDefined(v3RelayHashes[relayDataHash].deposit),
|
|
1058
940
|
"Deposit should exist in relay hash dictionary."
|
|
1059
941
|
);
|
|
1060
942
|
// The ! is safe here because we've already checked that the deposit exists in the relay hash dictionary.
|
|
1061
|
-
const matchedDeposit = v3RelayHashes[relayDataHash].
|
|
943
|
+
const matchedDeposit = v3RelayHashes[relayDataHash].deposit!;
|
|
944
|
+
if (!_canCreateSlowFillLeaf(matchedDeposit)) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
1062
947
|
|
|
1063
948
|
// If there is no fill matching the relay hash, then this might be a valid slow fill request
|
|
1064
949
|
// that we should produce a slow fill leaf for. Check if the slow fill request is in the
|
|
1065
950
|
// destination chain block range.
|
|
1066
951
|
if (
|
|
1067
952
|
slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
|
|
1068
|
-
_canCreateSlowFillLeaf(matchedDeposit) &&
|
|
1069
953
|
// Deposit must not have expired in this bundle.
|
|
1070
|
-
|
|
954
|
+
slowFillRequest.fillDeadline >= bundleBlockTimestamps[destinationChainId][1]
|
|
1071
955
|
) {
|
|
1072
956
|
// At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
|
|
1073
957
|
// so this slow fill request relay data is correct.
|
|
1074
958
|
validatedBundleSlowFills.push(matchedDeposit);
|
|
1075
959
|
}
|
|
1076
|
-
} else {
|
|
1077
|
-
throw new Error("Duplicate slow fill request detected.");
|
|
1078
960
|
}
|
|
1079
961
|
return;
|
|
1080
962
|
}
|
|
1081
963
|
|
|
1082
964
|
// Instantiate dictionary if there is neither a deposit nor fill matching it.
|
|
1083
965
|
v3RelayHashes[relayDataHash] = {
|
|
1084
|
-
|
|
966
|
+
deposit: undefined,
|
|
1085
967
|
fill: undefined,
|
|
1086
968
|
slowFillRequest: slowFillRequest,
|
|
1087
969
|
};
|
|
@@ -1116,12 +998,12 @@ export class BundleDataClient {
|
|
|
1116
998
|
this.getRelayHashFromEvent(matchedDeposit) === relayDataHash,
|
|
1117
999
|
"Deposit relay hashes should match."
|
|
1118
1000
|
);
|
|
1119
|
-
v3RelayHashes[relayDataHash].
|
|
1001
|
+
v3RelayHashes[relayDataHash].deposit = matchedDeposit;
|
|
1120
1002
|
|
|
1121
1003
|
if (
|
|
1122
1004
|
!_canCreateSlowFillLeaf(matchedDeposit) ||
|
|
1123
1005
|
// Deposit must not have expired in this bundle.
|
|
1124
|
-
|
|
1006
|
+
slowFillRequest.fillDeadline < bundleBlockTimestamps[destinationChainId][1]
|
|
1125
1007
|
) {
|
|
1126
1008
|
return;
|
|
1127
1009
|
}
|
|
@@ -1137,163 +1019,141 @@ export class BundleDataClient {
|
|
|
1137
1019
|
// - Or, has the deposit expired in this bundle? If so, then we need to issue an expiry refund.
|
|
1138
1020
|
// - And finally, has the deposit been slow filled? If so, then we need to issue a slow fill leaf
|
|
1139
1021
|
// for this "pre-slow-fill-request" if this request took place in a previous bundle.
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
// in rapid succession in most cases, unless they are unlucky enough to send duplicate deposits
|
|
1169
|
-
// in different bundle block ranges.
|
|
1170
|
-
const duplicateDepositsInBundle = deposits!.slice(index + 1);
|
|
1171
|
-
|
|
1172
|
-
// We are willing to refund a pre-fill multiple times for each duplicate deposit.
|
|
1173
|
-
// This is because a duplicate deposit for a pre-fill cannot get
|
|
1174
|
-
// refunded to the depositor anymore because its fill status on-chain has changed to Filled. Therefore
|
|
1175
|
-
// any duplicate deposits result in a net loss of funds for the depositor and effectively pay out
|
|
1176
|
-
// the pre-filler.
|
|
1177
|
-
|
|
1178
|
-
// If fill exists in memory, then the only case in which we need to create a refund is if the
|
|
1179
|
-
// the fill occurred in a previous bundle. There are no expiry refunds for filled deposits.
|
|
1180
|
-
if (fill) {
|
|
1181
|
-
if (!isDuplicateDepositInBundle && fill.blockNumber < destinationChainBlockRange[0]) {
|
|
1182
|
-
duplicateDepositsInBundle.forEach((duplicateDeposit) => {
|
|
1183
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
|
|
1184
|
-
});
|
|
1185
|
-
if (canRefundPrefills) {
|
|
1022
|
+
const originBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
|
|
1023
|
+
|
|
1024
|
+
await mapAsync(
|
|
1025
|
+
bundleDepositHashes.filter((depositHash) => {
|
|
1026
|
+
const { deposit } = v3RelayHashes[depositHash];
|
|
1027
|
+
return (
|
|
1028
|
+
deposit &&
|
|
1029
|
+
deposit.originChainId === originChainId &&
|
|
1030
|
+
deposit.destinationChainId === destinationChainId &&
|
|
1031
|
+
deposit.blockNumber >= originBlockRange[0] &&
|
|
1032
|
+
deposit.blockNumber <= originBlockRange[1] &&
|
|
1033
|
+
!isZeroValueDeposit(deposit)
|
|
1034
|
+
);
|
|
1035
|
+
}),
|
|
1036
|
+
async (depositHash) => {
|
|
1037
|
+
const { deposit, fill, slowFillRequest } = v3RelayHashes[depositHash];
|
|
1038
|
+
if (!deposit) throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1039
|
+
|
|
1040
|
+
// We are willing to refund a pre-fill multiple times for each duplicate deposit.
|
|
1041
|
+
// This is because a duplicate deposit for a pre-fill cannot get
|
|
1042
|
+
// refunded to the depositor anymore because its fill status on-chain has changed to Filled. Therefore
|
|
1043
|
+
// any duplicate deposits result in a net loss of funds for the depositor and effectively pay out
|
|
1044
|
+
// the pre-filler.
|
|
1045
|
+
|
|
1046
|
+
// If fill exists in memory, then the only case in which we need to create a refund is if the
|
|
1047
|
+
// the fill occurred in a previous bundle. There are no expiry refunds for filled deposits.
|
|
1048
|
+
if (fill) {
|
|
1049
|
+
if (!isSlowFill(fill) && fill.blockNumber < destinationChainBlockRange[0]) {
|
|
1186
1050
|
// If fill is in the current bundle then we can assume there is already a refund for it, so only
|
|
1187
1051
|
// include this pre fill if the fill is in an older bundle. If fill is after this current bundle, then
|
|
1188
1052
|
// we won't consider it, following the previous treatment of fills after the bundle block range.
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
});
|
|
1194
|
-
}
|
|
1053
|
+
validatedBundleV3Fills.push({
|
|
1054
|
+
...fill,
|
|
1055
|
+
quoteTimestamp: deposit.quoteTimestamp,
|
|
1056
|
+
});
|
|
1195
1057
|
}
|
|
1058
|
+
return;
|
|
1196
1059
|
}
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
1060
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1061
|
+
// If a slow fill request exists in memory, then we know the deposit has not been filled because fills
|
|
1062
|
+
// must follow slow fill requests and we would have seen the fill already if it existed. Therefore,
|
|
1063
|
+
// we can conclude that either the deposit has expired and we need to create a deposit expiry refund, or
|
|
1064
|
+
// we need to create a slow fill leaf for the deposit. The latter should only happen if the slow fill request
|
|
1065
|
+
// took place in a prior bundle otherwise we would have already created a slow fill leaf for it.
|
|
1066
|
+
if (slowFillRequest) {
|
|
1067
|
+
if (deposit.fillDeadline < bundleBlockTimestamps[destinationChainId][1]) {
|
|
1068
|
+
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1069
|
+
} else if (
|
|
1070
|
+
_canCreateSlowFillLeaf(deposit) &&
|
|
1071
|
+
slowFillRequest.blockNumber < destinationChainBlockRange[0]
|
|
1072
|
+
) {
|
|
1073
|
+
validatedBundleSlowFills.push(deposit);
|
|
1074
|
+
}
|
|
1075
|
+
return;
|
|
1215
1076
|
}
|
|
1216
|
-
return;
|
|
1217
|
-
}
|
|
1218
1077
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
assert(isDefined(prefill), `findFillEvent# Cannot find prefill: ${relayDataHash}`);
|
|
1233
|
-
assert(this.getRelayHashFromEvent(prefill!) === relayDataHash, "Relay hashes should match.");
|
|
1234
|
-
if (!isDuplicateDepositInBundle) {
|
|
1235
|
-
duplicateDepositsInBundle.forEach((duplicateDeposit) => {
|
|
1236
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
|
|
1237
|
-
});
|
|
1238
|
-
const verifiedFill = await verifyFillRepayment(
|
|
1239
|
-
prefill!,
|
|
1240
|
-
destinationClient.spokePool.provider,
|
|
1078
|
+
// So at this point in the code, there is no fill or slow fill request in memory for this deposit.
|
|
1079
|
+
// We need to check its fill status on-chain to figure out whether to issue a refund or a slow fill leaf.
|
|
1080
|
+
// We can assume at this point that all fills or slow fill requests, if found, were in previous bundles
|
|
1081
|
+
// because the spoke pool client lookback would have returned this entire bundle of events and stored
|
|
1082
|
+
// them into the relay hash dictionary.
|
|
1083
|
+
const fillStatus = await _getFillStatusForDeposit(deposit, destinationChainBlockRange[1]);
|
|
1084
|
+
|
|
1085
|
+
// If deposit was filled, then we need to issue a refund for it.
|
|
1086
|
+
if (fillStatus === FillStatus.Filled) {
|
|
1087
|
+
// We need to find the fill event to issue a refund to the right relayer and repayment chain,
|
|
1088
|
+
// or msg.sender if relayer address is invalid for the repayment chain.
|
|
1089
|
+
const prefill = (await findFillEvent(
|
|
1090
|
+
destinationClient.spokePool,
|
|
1241
1091
|
deposit,
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1092
|
+
destinationClient.deploymentBlock,
|
|
1093
|
+
destinationClient.latestBlockSearched
|
|
1094
|
+
)) as unknown as FillWithBlock;
|
|
1095
|
+
if (!isSlowFill(prefill)) {
|
|
1245
1096
|
validatedBundleV3Fills.push({
|
|
1246
|
-
...
|
|
1097
|
+
...prefill,
|
|
1247
1098
|
quoteTimestamp: deposit.quoteTimestamp,
|
|
1248
1099
|
});
|
|
1249
1100
|
}
|
|
1250
1101
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1102
|
+
// If deposit is not filled and its newly expired, we can create a deposit refund for it.
|
|
1103
|
+
// We don't check that fillDeadline >= bundleBlockTimestamps[destinationChainId][0] because
|
|
1104
|
+
// that would eliminate any deposits in this bundle with a very low fillDeadline like equal to 0
|
|
1105
|
+
// for example. Those should be included in this bundle of refunded deposits.
|
|
1106
|
+
else if (deposit.fillDeadline < bundleBlockTimestamps[destinationChainId][1]) {
|
|
1107
|
+
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1108
|
+
}
|
|
1109
|
+
// If slow fill requested, then issue a slow fill leaf for the deposit.
|
|
1110
|
+
else if (fillStatus === FillStatus.RequestedSlowFill) {
|
|
1111
|
+
// Input and Output tokens must be equivalent on the deposit for this to be slow filled.
|
|
1112
|
+
// Slow fill requests for deposits from or to lite chains are considered invalid
|
|
1113
|
+
if (_canCreateSlowFillLeaf(deposit)) {
|
|
1114
|
+
// If deposit newly expired, then we can't create a slow fill leaf for it but we can
|
|
1115
|
+
// create a deposit refund for it.
|
|
1116
|
+
validatedBundleSlowFills.push(deposit);
|
|
1117
|
+
}
|
|
1267
1118
|
}
|
|
1268
1119
|
}
|
|
1269
|
-
|
|
1120
|
+
);
|
|
1270
1121
|
|
|
1271
1122
|
// For all fills that came after a slow fill request, we can now check if the slow fill request
|
|
1272
1123
|
// was a valid one and whether it was created in a previous bundle. If so, then it created a slow fill
|
|
1273
1124
|
// leaf that is now unexecutable.
|
|
1274
1125
|
fastFillsReplacingSlowFills.forEach((relayDataHash) => {
|
|
1275
|
-
const {
|
|
1126
|
+
const { deposit, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
|
|
1276
1127
|
assert(
|
|
1277
1128
|
fill?.relayExecutionInfo.fillType === FillType.ReplacedSlowFill,
|
|
1278
1129
|
"Fill type should be ReplacedSlowFill."
|
|
1279
1130
|
);
|
|
1280
1131
|
// Needed for TSC - are implicitely checking that deposit exists by making it to this point.
|
|
1281
|
-
if (!
|
|
1132
|
+
if (!deposit) {
|
|
1282
1133
|
throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1283
1134
|
}
|
|
1284
1135
|
// We should never push fast fills involving lite chains here because slow fill requests for them are invalid:
|
|
1285
1136
|
assert(
|
|
1286
|
-
|
|
1287
|
-
"fastFillsReplacingSlowFills should contain
|
|
1137
|
+
!deposit.fromLiteChain && !deposit.toLiteChain,
|
|
1138
|
+
"fastFillsReplacingSlowFills should not contain lite chain deposits"
|
|
1288
1139
|
);
|
|
1289
1140
|
const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
|
|
1290
1141
|
if (
|
|
1142
|
+
// If the slow fill request that was replaced by this fill was in an older bundle, then we don't
|
|
1143
|
+
// need to check if the slow fill request was valid since we can assume all bundles in the past
|
|
1144
|
+
// were validated. However, we might as well double check.
|
|
1145
|
+
this.clients.hubPoolClient.areTokensEquivalent(
|
|
1146
|
+
deposit.inputToken,
|
|
1147
|
+
deposit.originChainId,
|
|
1148
|
+
deposit.outputToken,
|
|
1149
|
+
deposit.destinationChainId,
|
|
1150
|
+
deposit.quoteBlockNumber
|
|
1151
|
+
) &&
|
|
1291
1152
|
// If there is a slow fill request in this bundle that matches the relay hash, then there was no slow fill
|
|
1292
1153
|
// created that would be considered excess.
|
|
1293
|
-
!slowFillRequest ||
|
|
1294
|
-
slowFillRequest.blockNumber < destinationBlockRange[0]
|
|
1154
|
+
(!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0])
|
|
1295
1155
|
) {
|
|
1296
|
-
validatedBundleUnexecutableSlowFills.push(
|
|
1156
|
+
validatedBundleUnexecutableSlowFills.push(deposit);
|
|
1297
1157
|
}
|
|
1298
1158
|
});
|
|
1299
1159
|
}
|
|
@@ -1307,14 +1167,10 @@ export class BundleDataClient {
|
|
|
1307
1167
|
// For all deposits older than this bundle, we need to check if they expired in this bundle and if they did,
|
|
1308
1168
|
// whether there was a slow fill created for it in a previous bundle that is now unexecutable and replaced
|
|
1309
1169
|
// by a new expired deposit refund.
|
|
1310
|
-
await forEachAsync(olderDepositHashes, async (
|
|
1311
|
-
const {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1315
|
-
}
|
|
1316
|
-
const deposit = deposits[index];
|
|
1317
|
-
const { destinationChainId } = deposit;
|
|
1170
|
+
await forEachAsync(olderDepositHashes, async (relayDataHash) => {
|
|
1171
|
+
const { deposit, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
|
|
1172
|
+
assert(isDefined(deposit), "Deposit should exist in relay hash dictionary.");
|
|
1173
|
+
const { destinationChainId } = deposit!;
|
|
1318
1174
|
const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
|
|
1319
1175
|
|
|
1320
1176
|
// Only look for deposits that were mined before this bundle and that are newly expired.
|
|
@@ -1324,7 +1180,7 @@ export class BundleDataClient {
|
|
|
1324
1180
|
// If there is a valid fill that we saw matching this deposit, then it does not need a refund.
|
|
1325
1181
|
!fill &&
|
|
1326
1182
|
isDefined(deposit) && // Needed for TSC - we check this above.
|
|
1327
|
-
|
|
1183
|
+
deposit.fillDeadline < bundleBlockTimestamps[destinationChainId][1] &&
|
|
1328
1184
|
deposit.fillDeadline >= bundleBlockTimestamps[destinationChainId][0] &&
|
|
1329
1185
|
spokePoolClients[destinationChainId] !== undefined
|
|
1330
1186
|
) {
|
|
@@ -1340,7 +1196,8 @@ export class BundleDataClient {
|
|
|
1340
1196
|
// If fill status is RequestedSlowFill, then we might need to mark down an unexecutable
|
|
1341
1197
|
// slow fill that we're going to replace with an expired deposit refund.
|
|
1342
1198
|
// If deposit cannot be slow filled, then exit early.
|
|
1343
|
-
|
|
1199
|
+
// slow fill requests for deposits from or to lite chains are considered invalid
|
|
1200
|
+
if (fillStatus !== FillStatus.RequestedSlowFill || deposit.fromLiteChain || deposit.toLiteChain) {
|
|
1344
1201
|
return;
|
|
1345
1202
|
}
|
|
1346
1203
|
// Now, check if there was a slow fill created for this deposit in a previous bundle which would now be
|
|
@@ -1349,9 +1206,21 @@ export class BundleDataClient {
|
|
|
1349
1206
|
|
|
1350
1207
|
// If there is a slow fill request in this bundle, then the expired deposit refund will supercede
|
|
1351
1208
|
// the slow fill request. If there is no slow fill request seen or its older than this bundle, then we can
|
|
1352
|
-
// assume a slow fill leaf was created for it because
|
|
1353
|
-
//
|
|
1354
|
-
if (
|
|
1209
|
+
// assume a slow fill leaf was created for it because its tokens are equivalent. The slow fill request was
|
|
1210
|
+
// also sent before the fill deadline expired since we checked that above.
|
|
1211
|
+
if (
|
|
1212
|
+
// Since this deposit was requested for a slow fill in an older bundle at this point, we don't
|
|
1213
|
+
// technically need to check if the slow fill request was valid since we can assume all bundles in the past
|
|
1214
|
+
// were validated. However, we might as well double check.
|
|
1215
|
+
this.clients.hubPoolClient.areTokensEquivalent(
|
|
1216
|
+
deposit.inputToken,
|
|
1217
|
+
deposit.originChainId,
|
|
1218
|
+
deposit.outputToken,
|
|
1219
|
+
deposit.destinationChainId,
|
|
1220
|
+
deposit.quoteBlockNumber
|
|
1221
|
+
) &&
|
|
1222
|
+
(!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0])
|
|
1223
|
+
) {
|
|
1355
1224
|
validatedBundleUnexecutableSlowFills.push(deposit);
|
|
1356
1225
|
}
|
|
1357
1226
|
}
|
|
@@ -1363,7 +1232,7 @@ export class BundleDataClient {
|
|
|
1363
1232
|
validatedBundleV3Fills.length > 0
|
|
1364
1233
|
? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(
|
|
1365
1234
|
validatedBundleV3Fills.map((fill) => {
|
|
1366
|
-
const matchedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].
|
|
1235
|
+
const matchedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].deposit;
|
|
1367
1236
|
assert(isDefined(matchedDeposit), "Deposit should exist in relay hash dictionary.");
|
|
1368
1237
|
const { chainToSendRefundTo: paymentChainId } = getRefundInformationFromFill(
|
|
1369
1238
|
fill,
|
|
@@ -1407,7 +1276,7 @@ export class BundleDataClient {
|
|
|
1407
1276
|
});
|
|
1408
1277
|
v3FillLpFees.forEach(({ realizedLpFeePct }, idx) => {
|
|
1409
1278
|
const fill = validatedBundleV3Fills[idx];
|
|
1410
|
-
const associatedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].
|
|
1279
|
+
const associatedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].deposit;
|
|
1411
1280
|
assert(isDefined(associatedDeposit), "Deposit should exist in relay hash dictionary.");
|
|
1412
1281
|
const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
|
|
1413
1282
|
fill,
|
|
@@ -1416,7 +1285,7 @@ export class BundleDataClient {
|
|
|
1416
1285
|
chainIds,
|
|
1417
1286
|
associatedDeposit!.fromLiteChain
|
|
1418
1287
|
);
|
|
1419
|
-
updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken
|
|
1288
|
+
updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken);
|
|
1420
1289
|
});
|
|
1421
1290
|
v3SlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
|
|
1422
1291
|
const deposit = validatedBundleSlowFills[idx];
|
|
@@ -1464,24 +1333,8 @@ export class BundleDataClient {
|
|
|
1464
1333
|
// keccak256 hash of the relay data, which can be used as input into the on-chain `fillStatuses()` function in the
|
|
1465
1334
|
// spoke pool contract. However, this internal function is used to uniquely identify a bridging event
|
|
1466
1335
|
// for speed since its easier to build a string from the event data than to hash it.
|
|
1467
|
-
|
|
1468
|
-
return `${event.depositor}-${event.recipient}-${event.exclusiveRelayer}-${event.inputToken}-${event.outputToken}-${
|
|
1469
|
-
event.inputAmount
|
|
1470
|
-
}-${event.outputAmount}-${event.originChainId}-${event.depositId.toString()}-${event.fillDeadline}-${
|
|
1471
|
-
event.exclusivityDeadline
|
|
1472
|
-
}-${event.message}-${event.destinationChainId}`;
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
protected async findMatchingFillEvent(
|
|
1476
|
-
deposit: DepositWithBlock,
|
|
1477
|
-
spokePoolClient: SpokePoolClient
|
|
1478
|
-
): Promise<FillWithBlock | undefined> {
|
|
1479
|
-
return await findFillEvent(
|
|
1480
|
-
spokePoolClient.spokePool,
|
|
1481
|
-
deposit,
|
|
1482
|
-
spokePoolClient.deploymentBlock,
|
|
1483
|
-
spokePoolClient.latestBlockSearched
|
|
1484
|
-
);
|
|
1336
|
+
private getRelayHashFromEvent(event: V3DepositWithBlock | V3FillWithBlock | SlowFillRequestWithBlock): string {
|
|
1337
|
+
return `${event.depositor}-${event.recipient}-${event.exclusiveRelayer}-${event.inputToken}-${event.outputToken}-${event.inputAmount}-${event.outputAmount}-${event.originChainId}-${event.depositId}-${event.fillDeadline}-${event.exclusivityDeadline}-${event.message}-${event.destinationChainId}`;
|
|
1485
1338
|
}
|
|
1486
1339
|
|
|
1487
1340
|
async getBundleBlockTimestamps(
|
|
@@ -1509,26 +1362,13 @@ export class BundleDataClient {
|
|
|
1509
1362
|
// will usually be called in production with block ranges that were validated by
|
|
1510
1363
|
// DataworkerUtils.blockRangesAreInvalidForSpokeClients.
|
|
1511
1364
|
const startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestBlockSearched);
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
// in exactly one bundle, therefore we must make sure that the bundle block timestamp for one bundle's
|
|
1515
|
-
// end block is exactly equal to the bundle block timestamp for the next bundle's start block. This way
|
|
1516
|
-
// there are no gaps in block timestamps between bundles.
|
|
1517
|
-
const endBlockForChain = Math.min(_endBlockForChain + 1, spokePoolClient.latestBlockSearched);
|
|
1518
|
-
const [startTime, _endTime] = [
|
|
1365
|
+
const endBlockForChain = Math.min(_endBlockForChain, spokePoolClient.latestBlockSearched);
|
|
1366
|
+
const [startTime, endTime] = [
|
|
1519
1367
|
await spokePoolClient.getTimestampForBlock(startBlockForChain),
|
|
1520
1368
|
await spokePoolClient.getTimestampForBlock(endBlockForChain),
|
|
1521
1369
|
];
|
|
1522
|
-
// @dev similar to reasoning above to ensure no gaps between bundle block range timestamps and also
|
|
1523
|
-
// no overlap, subtract 1 from the end time.
|
|
1524
|
-
const endBlockDelta = endBlockForChain > startBlockForChain ? 1 : 0;
|
|
1525
|
-
const endTime = Math.max(0, _endTime - endBlockDelta);
|
|
1526
|
-
|
|
1527
1370
|
// Sanity checks:
|
|
1528
|
-
assert(
|
|
1529
|
-
endTime >= startTime,
|
|
1530
|
-
`End time for block ${endBlockForChain} should be greater than start time for block ${startBlockForChain}: ${endTime} >= ${startTime}.`
|
|
1531
|
-
);
|
|
1371
|
+
assert(endTime >= startTime, "End time should be greater than start time.");
|
|
1532
1372
|
assert(
|
|
1533
1373
|
startBlockForChain === 0 || startTime > 0,
|
|
1534
1374
|
"Start timestamp must be greater than 0 if the start block is greater than 0."
|