@across-protocol/sdk 4.0.0-beta.34 → 4.0.0-beta.5
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 +189 -352
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.d.ts +2 -1
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +2 -1
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +1 -5
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +1 -47
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +4 -4
- package/dist/cjs/clients/SpokePoolClient.d.ts +0 -1
- package/dist/cjs/clients/SpokePoolClient.js +1 -10
- package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/mocks/MockSpokePoolClient.d.ts +1 -2
- package/dist/cjs/clients/mocks/MockSpokePoolClient.js +1 -11
- package/dist/cjs/clients/mocks/MockSpokePoolClient.js.map +1 -1
- package/dist/cjs/constants.d.ts +1 -1
- package/dist/cjs/constants.js +2 -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 -6
- package/dist/cjs/utils/AddressUtils.js.map +1 -1
- package/dist/cjs/utils/DepositUtils.js +1 -1
- package/dist/cjs/utils/DepositUtils.js.map +1 -1
- package/dist/cjs/utils/EventUtils.js +0 -21
- package/dist/cjs/utils/EventUtils.js.map +1 -1
- package/dist/cjs/utils/SpokeUtils.d.ts +0 -1
- package/dist/cjs/utils/SpokeUtils.js +8 -15
- package/dist/cjs/utils/SpokeUtils.js.map +1 -1
- package/dist/cjs/utils/common.d.ts +0 -1
- package/dist/cjs/utils/common.js +1 -2
- package/dist/cjs/utils/common.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +4 -5
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +274 -455
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.d.ts +2 -1
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +3 -2
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +1 -5
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +1 -54
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +4 -4
- package/dist/esm/clients/SpokePoolClient.d.ts +0 -8
- package/dist/esm/clients/SpokePoolClient.js +1 -17
- package/dist/esm/clients/SpokePoolClient.js.map +1 -1
- package/dist/esm/clients/mocks/MockSpokePoolClient.d.ts +1 -2
- package/dist/esm/clients/mocks/MockSpokePoolClient.js +1 -11
- package/dist/esm/clients/mocks/MockSpokePoolClient.js.map +1 -1
- package/dist/esm/constants.d.ts +1 -1
- package/dist/esm/constants.js +2 -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 -9
- package/dist/esm/utils/AddressUtils.js.map +1 -1
- package/dist/esm/utils/DepositUtils.js +2 -2
- package/dist/esm/utils/DepositUtils.js.map +1 -1
- package/dist/esm/utils/EventUtils.js +1 -29
- package/dist/esm/utils/EventUtils.js.map +1 -1
- package/dist/esm/utils/SpokeUtils.d.ts +0 -1
- package/dist/esm/utils/SpokeUtils.js +7 -13
- package/dist/esm/utils/SpokeUtils.js.map +1 -1
- package/dist/esm/utils/common.d.ts +0 -1
- package/dist/esm/utils/common.js +0 -1
- package/dist/esm/utils/common.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/DataworkerUtils.d.ts +2 -1
- package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +1 -5
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +4 -4
- package/dist/types/clients/SpokePoolClient.d.ts +0 -8
- package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/mocks/MockSpokePoolClient.d.ts +1 -2
- package/dist/types/clients/mocks/MockSpokePoolClient.d.ts.map +1 -1
- package/dist/types/constants.d.ts +1 -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/EventUtils.d.ts.map +1 -1
- package/dist/types/utils/SpokeUtils.d.ts +0 -1
- package/dist/types/utils/SpokeUtils.d.ts.map +1 -1
- package/dist/types/utils/common.d.ts +0 -1
- package/dist/types/utils/common.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/clients/BundleDataClient/BundleDataClient.ts +243 -427
- package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +8 -0
- package/src/clients/BundleDataClient/utils/FillUtils.ts +2 -66
- package/src/clients/SpokePoolClient.ts +3 -16
- package/src/clients/mocks/MockSpokePoolClient.ts +1 -14
- package/src/constants.ts +3 -3
- package/src/providers/index.ts +0 -1
- package/src/utils/AddressUtils.ts +0 -10
- package/src/utils/DepositUtils.ts +2 -2
- package/src/utils/EventUtils.ts +1 -29
- package/src/utils/SpokeUtils.ts +8 -21
- package/src/utils/common.ts +0 -2
- 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,7 +33,6 @@ import {
|
|
|
33
33
|
getImpliedBundleBlockRanges,
|
|
34
34
|
isSlowFill,
|
|
35
35
|
mapAsync,
|
|
36
|
-
filterAsync,
|
|
37
36
|
bnUint32Max,
|
|
38
37
|
isZeroValueDeposit,
|
|
39
38
|
findFillEvent,
|
|
@@ -50,14 +49,11 @@ import {
|
|
|
50
49
|
getRefundsFromBundle,
|
|
51
50
|
getWidestPossibleExpectedBlockRange,
|
|
52
51
|
isChainDisabled,
|
|
53
|
-
isEvmRepaymentValid,
|
|
54
52
|
PoolRebalanceRoot,
|
|
55
53
|
prettyPrintV3SpokePoolEvents,
|
|
56
54
|
V3DepositWithBlock,
|
|
57
55
|
V3FillWithBlock,
|
|
58
|
-
verifyFillRepayment,
|
|
59
56
|
} from "./utils";
|
|
60
|
-
import { PRE_FILL_MIN_CONFIG_STORE_VERSION } from "../../constants";
|
|
61
57
|
|
|
62
58
|
// max(uint256) - 1
|
|
63
59
|
export const INFINITE_FILL_DEADLINE = bnUint32Max;
|
|
@@ -90,14 +86,12 @@ function updateBundleFillsV3(
|
|
|
90
86
|
fill: V3FillWithBlock,
|
|
91
87
|
lpFeePct: BigNumber,
|
|
92
88
|
repaymentChainId: number,
|
|
93
|
-
repaymentToken: string
|
|
94
|
-
repaymentAddress: string
|
|
89
|
+
repaymentToken: string
|
|
95
90
|
): void {
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
);
|
|
91
|
+
// It is impossible to refund a deposit if the repayment chain is EVM and the relayer is a non-evm address.
|
|
92
|
+
if (chainIsEvm(fill.repaymentChainId) && !isValidEvmAddress(fill.relayer)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
101
95
|
if (!dict?.[repaymentChainId]?.[repaymentToken]) {
|
|
102
96
|
assign(dict, [repaymentChainId, repaymentToken], {
|
|
103
97
|
fills: [],
|
|
@@ -107,19 +101,19 @@ function updateBundleFillsV3(
|
|
|
107
101
|
});
|
|
108
102
|
}
|
|
109
103
|
|
|
110
|
-
const bundleFill: BundleFillV3 = { ...fill, lpFeePct
|
|
104
|
+
const bundleFill: BundleFillV3 = { ...fill, lpFeePct };
|
|
111
105
|
|
|
112
106
|
// Add all fills, slow and fast, to dictionary.
|
|
113
107
|
assign(dict, [repaymentChainId, repaymentToken, "fills"], [bundleFill]);
|
|
114
108
|
|
|
115
109
|
// All fills update the bundle LP fees.
|
|
116
110
|
const refundObj = dict[repaymentChainId][repaymentToken];
|
|
117
|
-
const realizedLpFee =
|
|
111
|
+
const realizedLpFee = fill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
|
|
118
112
|
refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
|
|
119
113
|
|
|
120
114
|
// Only fast fills get refunded.
|
|
121
|
-
if (!isSlowFill(
|
|
122
|
-
const refundAmount =
|
|
115
|
+
if (!isSlowFill(fill)) {
|
|
116
|
+
const refundAmount = fill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
|
|
123
117
|
refundObj.totalRefundAmount = refundObj.totalRefundAmount
|
|
124
118
|
? refundObj.totalRefundAmount.add(refundAmount)
|
|
125
119
|
: refundAmount;
|
|
@@ -127,10 +121,10 @@ function updateBundleFillsV3(
|
|
|
127
121
|
// Instantiate dictionary if it doesn't exist.
|
|
128
122
|
refundObj.refunds ??= {};
|
|
129
123
|
|
|
130
|
-
if (refundObj.refunds[
|
|
131
|
-
refundObj.refunds[
|
|
124
|
+
if (refundObj.refunds[fill.relayer]) {
|
|
125
|
+
refundObj.refunds[fill.relayer] = refundObj.refunds[fill.relayer].add(refundAmount);
|
|
132
126
|
} else {
|
|
133
|
-
refundObj.refunds[
|
|
127
|
+
refundObj.refunds[fill.relayer] = refundAmount;
|
|
134
128
|
}
|
|
135
129
|
}
|
|
136
130
|
}
|
|
@@ -147,9 +141,6 @@ function updateBundleExcessSlowFills(
|
|
|
147
141
|
}
|
|
148
142
|
|
|
149
143
|
function updateBundleSlowFills(dict: BundleSlowFills, deposit: V3DepositWithBlock & { lpFeePct: BigNumber }): void {
|
|
150
|
-
if (chainIsEvm(deposit.destinationChainId) && !isValidEvmAddress(deposit.recipient)) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
144
|
const { destinationChainId, outputToken } = deposit;
|
|
154
145
|
if (!dict?.[destinationChainId]?.[outputToken]) {
|
|
155
146
|
assign(dict, [destinationChainId, outputToken], []);
|
|
@@ -253,6 +244,7 @@ export class BundleDataClient {
|
|
|
253
244
|
bundleData: prettyPrintV3SpokePoolEvents(
|
|
254
245
|
bundleData.bundleDepositsV3,
|
|
255
246
|
bundleData.bundleFillsV3,
|
|
247
|
+
[], // Invalid fills are not persisted to Arweave.
|
|
256
248
|
bundleData.bundleSlowFillsV3,
|
|
257
249
|
bundleData.expiredDepositsToRefundV3,
|
|
258
250
|
bundleData.unexecutableSlowFills
|
|
@@ -300,7 +292,7 @@ export class BundleDataClient {
|
|
|
300
292
|
// so as not to affect this approximate refund count.
|
|
301
293
|
const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
|
|
302
294
|
if (arweaveData === undefined) {
|
|
303
|
-
combinedRefunds =
|
|
295
|
+
combinedRefunds = this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
|
|
304
296
|
} else {
|
|
305
297
|
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
306
298
|
combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
|
|
@@ -321,72 +313,50 @@ export class BundleDataClient {
|
|
|
321
313
|
}
|
|
322
314
|
|
|
323
315
|
// @dev This helper function should probably be moved to the InventoryClient
|
|
324
|
-
|
|
316
|
+
getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): CombinedRefunds {
|
|
325
317
|
const refundsForChain: CombinedRefunds = {};
|
|
326
318
|
for (const chainId of chainIds) {
|
|
327
319
|
if (this.spokePoolClients[chainId] === undefined) {
|
|
328
320
|
continue;
|
|
329
321
|
}
|
|
330
322
|
const chainIndex = chainIds.indexOf(chainId);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (
|
|
338
|
-
fill.blockNumber < blockRanges[chainIndex][0] ||
|
|
339
|
-
fill.blockNumber > blockRanges[chainIndex][1] ||
|
|
340
|
-
isZeroValueFillOrSlowFillRequest(fill)
|
|
341
|
-
) {
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
323
|
+
this.spokePoolClients[chainId]
|
|
324
|
+
.getFills()
|
|
325
|
+
.filter((fill) => {
|
|
326
|
+
if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
344
329
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
350
|
-
const hasMatchingDeposit =
|
|
351
|
-
matchingDeposit !== undefined &&
|
|
352
|
-
this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
|
|
353
|
-
if (hasMatchingDeposit) {
|
|
354
|
-
const validRepayment = await verifyFillRepayment(
|
|
355
|
-
fill,
|
|
356
|
-
this.spokePoolClients[fill.destinationChainId].spokePool.provider,
|
|
357
|
-
matchingDeposit,
|
|
358
|
-
// @dev: to get valid repayment chain ID's, get all chain IDs for the bundle block range and remove
|
|
359
|
-
// disabled block ranges.
|
|
360
|
-
this.clients.configStoreClient
|
|
361
|
-
.getChainIdIndicesForBlock(blockRanges[0][1])
|
|
362
|
-
.filter((_chainId, i) => !isChainDisabled(blockRanges[i]))
|
|
363
|
-
);
|
|
364
|
-
if (!isDefined(validRepayment)) {
|
|
330
|
+
// If origin spoke pool client isn't defined, we can't validate it.
|
|
331
|
+
if (this.spokePoolClients[fill.originChainId] === undefined) {
|
|
365
332
|
return false;
|
|
366
333
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
fill
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
334
|
+
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
335
|
+
const hasMatchingDeposit =
|
|
336
|
+
matchingDeposit !== undefined &&
|
|
337
|
+
this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
|
|
338
|
+
return hasMatchingDeposit;
|
|
339
|
+
})
|
|
340
|
+
.forEach((fill) => {
|
|
341
|
+
const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
|
|
342
|
+
assert(isDefined(matchingDeposit), "Deposit not found for fill.");
|
|
343
|
+
const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
|
|
344
|
+
fill,
|
|
345
|
+
this.clients.hubPoolClient,
|
|
346
|
+
blockRanges,
|
|
347
|
+
this.chainIdListForBundleEvaluationBlockNumbers,
|
|
348
|
+
matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
|
|
349
|
+
);
|
|
350
|
+
// Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
|
|
351
|
+
// these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
|
|
352
|
+
// in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
|
|
353
|
+
// worst from the relayer's perspective.
|
|
354
|
+
const { relayer, inputAmount: refundAmount } = fill;
|
|
355
|
+
refundsForChain[chainToSendRefundTo] ??= {};
|
|
356
|
+
refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
|
|
357
|
+
const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
|
|
358
|
+
refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
|
|
359
|
+
});
|
|
390
360
|
}
|
|
391
361
|
return refundsForChain;
|
|
392
362
|
}
|
|
@@ -430,7 +400,7 @@ export class BundleDataClient {
|
|
|
430
400
|
async getLatestPoolRebalanceRoot(): Promise<{ root: PoolRebalanceRoot; blockRanges: number[][] }> {
|
|
431
401
|
const { bundleData, blockRanges } = await this.getLatestProposedBundleData();
|
|
432
402
|
const hubPoolClient = this.clients.hubPoolClient;
|
|
433
|
-
const root = _buildPoolRebalanceRoot(
|
|
403
|
+
const root = await _buildPoolRebalanceRoot(
|
|
434
404
|
hubPoolClient.latestBlockSearched,
|
|
435
405
|
blockRanges[0][1],
|
|
436
406
|
bundleData.bundleDepositsV3,
|
|
@@ -513,7 +483,7 @@ export class BundleDataClient {
|
|
|
513
483
|
// ok for this use case.
|
|
514
484
|
const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
|
|
515
485
|
if (arweaveData === undefined) {
|
|
516
|
-
combinedRefunds.push(
|
|
486
|
+
combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
|
|
517
487
|
} else {
|
|
518
488
|
const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
|
|
519
489
|
combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
|
|
@@ -528,7 +498,7 @@ export class BundleDataClient {
|
|
|
528
498
|
// - Only look up fills sent after the pending bundle's end blocks
|
|
529
499
|
// - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
|
|
530
500
|
const start = performance.now();
|
|
531
|
-
combinedRefunds.push(
|
|
501
|
+
combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
|
|
532
502
|
this.logger.debug({
|
|
533
503
|
at: "BundleDataClient#getNextBundleRefunds",
|
|
534
504
|
message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
|
|
@@ -695,8 +665,6 @@ export class BundleDataClient {
|
|
|
695
665
|
const bundleDepositsV3: BundleDepositsV3 = {}; // Deposits in bundle block range.
|
|
696
666
|
const bundleFillsV3: BundleFillsV3 = {}; // Fills to refund in bundle block range.
|
|
697
667
|
const bundleInvalidFillsV3: V3FillWithBlock[] = []; // Fills that are not valid in this bundle.
|
|
698
|
-
const bundleUnrepayableFillsV3: V3FillWithBlock[] = []; // Fills that are not repayable in this bundle.
|
|
699
|
-
const bundleInvalidSlowFillRequests: SlowFillRequestWithBlock[] = []; // Slow fill requests that are not valid in this bundle.
|
|
700
668
|
const bundleSlowFillsV3: BundleSlowFills = {}; // Deposits that we need to send slow fills
|
|
701
669
|
// for in this bundle.
|
|
702
670
|
const expiredDepositsToRefundV3: ExpiredDepositsToRefundV3 = {};
|
|
@@ -783,7 +751,7 @@ export class BundleDataClient {
|
|
|
783
751
|
// Note: Since there are no partial fills in v3, there should only be one fill per relay hash.
|
|
784
752
|
// Moreover, the SpokePool blocks multiple slow fill requests, so
|
|
785
753
|
// there should also only be one slow fill request per relay hash.
|
|
786
|
-
|
|
754
|
+
deposit?: V3DepositWithBlock;
|
|
787
755
|
fill?: V3FillWithBlock;
|
|
788
756
|
slowFillRequest?: SlowFillRequestWithBlock;
|
|
789
757
|
};
|
|
@@ -794,29 +762,7 @@ export class BundleDataClient {
|
|
|
794
762
|
const bundleDepositHashes: string[] = [];
|
|
795
763
|
const olderDepositHashes: string[] = [];
|
|
796
764
|
|
|
797
|
-
|
|
798
|
-
const [relayDataHash, i] = depositHash.split("@");
|
|
799
|
-
return { relayDataHash, index: Number(i) };
|
|
800
|
-
};
|
|
801
|
-
|
|
802
|
-
// We use the following toggle to aid with the migration to pre-fills. The first bundle proposed using this
|
|
803
|
-
// pre-fill logic can double refund pre-fills that have already been filled in the last bundle, because the
|
|
804
|
-
// last bundle did not recognize a fill as a pre-fill. Therefore the developer should ensure that the version
|
|
805
|
-
// is bumped to the PRE_FILL_MIN_CONFIG_STORE_VERSION version before the first pre-fill bundle is proposed.
|
|
806
|
-
// To test the following bundle after this, the developer can set the FORCE_REFUND_PREFILLS environment variable
|
|
807
|
-
// to "true" simulate the bundle with pre-fill refunds.
|
|
808
|
-
// @todo Remove this logic once we have advanced sufficiently past the pre-fill migration.
|
|
809
|
-
const startBlockForMainnet = getBlockRangeForChain(
|
|
810
|
-
blockRangesForChains,
|
|
811
|
-
this.clients.hubPoolClient.chainId,
|
|
812
|
-
this.chainIdListForBundleEvaluationBlockNumbers
|
|
813
|
-
)[0];
|
|
814
|
-
const versionAtProposalBlock = this.clients.configStoreClient.getConfigStoreVersionForBlock(startBlockForMainnet);
|
|
815
|
-
const canRefundPrefills =
|
|
816
|
-
versionAtProposalBlock >= PRE_FILL_MIN_CONFIG_STORE_VERSION || process.env.FORCE_REFUND_PREFILLS === "true";
|
|
817
|
-
|
|
818
|
-
// Prerequisite step: Load all deposit events from the current or older bundles into the v3RelayHashes dictionary
|
|
819
|
-
// for convenient matching with fills.
|
|
765
|
+
let depositCounter = 0;
|
|
820
766
|
for (const originChainId of allChainIds) {
|
|
821
767
|
const originClient = spokePoolClients[originChainId];
|
|
822
768
|
const originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
|
|
@@ -826,59 +772,50 @@ export class BundleDataClient {
|
|
|
826
772
|
continue;
|
|
827
773
|
}
|
|
828
774
|
originClient.getDepositsForDestinationChainWithDuplicates(destinationChainId).forEach((deposit) => {
|
|
775
|
+
// Only evaluate deposits that are in this bundle or in previous bundles. This means we cannot issue fill
|
|
776
|
+
// refunds or slow fills here for deposits that are in future bundles (i.e. "pre-fills"). Instead, we'll
|
|
777
|
+
// evaluate these pre-fills once the deposit is inside the "current" bundle block range.
|
|
829
778
|
if (deposit.blockNumber > originChainBlockRange[1] || isZeroValueDeposit(deposit)) {
|
|
830
779
|
return;
|
|
831
780
|
}
|
|
781
|
+
depositCounter++;
|
|
832
782
|
const relayDataHash = this.getRelayHashFromEvent(deposit);
|
|
833
783
|
|
|
784
|
+
// Duplicate deposits are treated like normal deposits.
|
|
834
785
|
if (!v3RelayHashes[relayDataHash]) {
|
|
835
786
|
v3RelayHashes[relayDataHash] = {
|
|
836
|
-
|
|
787
|
+
deposit: deposit,
|
|
837
788
|
fill: undefined,
|
|
838
789
|
slowFillRequest: undefined,
|
|
839
790
|
};
|
|
840
|
-
} else {
|
|
841
|
-
v3RelayHashes[relayDataHash].deposits!.push(deposit);
|
|
842
791
|
}
|
|
843
792
|
|
|
844
|
-
//
|
|
845
|
-
//
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
793
|
+
// Once we've saved the deposit hash into v3RelayHashes, then we can exit early here if the inputAmount
|
|
794
|
+
// is 0 because there can be no expired amount to refund and no unexecutable slow fill amount to return
|
|
795
|
+
// if this deposit did expire. Input amount can only be zero at this point if the message is non-empty,
|
|
796
|
+
// but the message doesn't matter for expired deposits and unexecutable slow fills.
|
|
797
|
+
if (deposit.inputAmount.eq(0)) {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Evaluate all expired deposits after fetching fill statuses,
|
|
802
|
+
// since we can't know for certain whether an expired deposit was filled a long time ago.
|
|
853
803
|
if (deposit.blockNumber >= originChainBlockRange[0]) {
|
|
854
|
-
bundleDepositHashes.push(
|
|
804
|
+
bundleDepositHashes.push(relayDataHash);
|
|
855
805
|
updateBundleDepositsV3(bundleDepositsV3, deposit);
|
|
856
806
|
} else if (deposit.blockNumber < originChainBlockRange[0]) {
|
|
857
|
-
olderDepositHashes.push(
|
|
807
|
+
olderDepositHashes.push(relayDataHash);
|
|
858
808
|
}
|
|
859
809
|
});
|
|
860
810
|
}
|
|
861
811
|
}
|
|
862
812
|
this.logger.debug({
|
|
863
813
|
at: "BundleDataClient#loadData",
|
|
864
|
-
message: `Processed ${
|
|
865
|
-
performance.now() - start
|
|
866
|
-
}ms.`,
|
|
814
|
+
message: `Processed ${depositCounter} deposits in ${performance.now() - start}ms.`,
|
|
867
815
|
});
|
|
868
816
|
start = performance.now();
|
|
869
817
|
|
|
870
|
-
// Process fills
|
|
871
|
-
// - Every single fill whose type is not SlowFill in the bundle block range whose relay data matches
|
|
872
|
-
// with a deposit in the same or an older range produces a refund to the filler,
|
|
873
|
-
// unless the specified filler address cannot be repaid on the repayment chain.
|
|
874
|
-
// - Fills can match with duplicate deposits, so for every matched fill whose type is not SlowFill
|
|
875
|
-
// in the bundle block range, produce a refund to the filler for each matched deposit.
|
|
876
|
-
// - For every SlowFill in the block range that matches with multiple deposits, produce a refund to the depositor
|
|
877
|
-
// for every deposit except except the first.
|
|
878
|
-
|
|
879
|
-
// Assumptions about fills:
|
|
880
|
-
// - Duplicate fills for the same relay data hash are impossible to send.
|
|
881
|
-
// - Fills can only be sent before the deposit's fillDeadline.
|
|
818
|
+
// Process fills now that we've populated relay hash dictionary with deposits:
|
|
882
819
|
const validatedBundleV3Fills: (V3FillWithBlock & { quoteTimestamp: number })[] = [];
|
|
883
820
|
const validatedBundleSlowFills: V3DepositWithBlock[] = [];
|
|
884
821
|
const validatedBundleUnexecutableSlowFills: V3DepositWithBlock[] = [];
|
|
@@ -892,8 +829,9 @@ export class BundleDataClient {
|
|
|
892
829
|
|
|
893
830
|
const destinationClient = spokePoolClients[destinationChainId];
|
|
894
831
|
const destinationChainBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
|
|
895
|
-
const originChainBlockRange = getBlockRangeForChain(blockRangesForChains, originChainId, chainIds);
|
|
896
832
|
|
|
833
|
+
// Keep track of fast fills that replaced slow fills, which we'll use to create "unexecutable" slow fills
|
|
834
|
+
// if the slow fill request was sent in a prior bundle.
|
|
897
835
|
const fastFillsReplacingSlowFills: string[] = [];
|
|
898
836
|
await forEachAsync(
|
|
899
837
|
destinationClient
|
|
@@ -905,79 +843,47 @@ export class BundleDataClient {
|
|
|
905
843
|
(fill) => fill.blockNumber <= destinationChainBlockRange[1] && !isZeroValueFillOrSlowFillRequest(fill)
|
|
906
844
|
),
|
|
907
845
|
async (fill) => {
|
|
908
|
-
fillCounter++;
|
|
909
846
|
const relayDataHash = this.getRelayHashFromEvent(fill);
|
|
847
|
+
fillCounter++;
|
|
848
|
+
|
|
910
849
|
if (v3RelayHashes[relayDataHash]) {
|
|
911
850
|
if (!v3RelayHashes[relayDataHash].fill) {
|
|
912
851
|
assert(
|
|
913
|
-
isDefined(v3RelayHashes[relayDataHash].
|
|
852
|
+
isDefined(v3RelayHashes[relayDataHash].deposit),
|
|
914
853
|
"Deposit should exist in relay hash dictionary."
|
|
915
854
|
);
|
|
855
|
+
// At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
|
|
856
|
+
// so this fill is validated.
|
|
916
857
|
v3RelayHashes[relayDataHash].fill = fill;
|
|
917
858
|
if (fill.blockNumber >= destinationChainBlockRange[0]) {
|
|
918
|
-
|
|
919
|
-
fill,
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
allChainIds
|
|
923
|
-
);
|
|
924
|
-
if (!isDefined(fillToRefund)) {
|
|
925
|
-
bundleUnrepayableFillsV3.push(fill);
|
|
926
|
-
// We don't return here yet because we still need to mark unexecutable slow fill leaves
|
|
927
|
-
// or duplicate deposits. However, we won't issue a fast fill refund.
|
|
928
|
-
} else {
|
|
929
|
-
v3RelayHashes[relayDataHash].fill = fillToRefund;
|
|
930
|
-
validatedBundleV3Fills.push({
|
|
931
|
-
...fillToRefund,
|
|
932
|
-
quoteTimestamp: v3RelayHashes[relayDataHash].deposits![0].quoteTimestamp,
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
// Now that we know this deposit has been filled on-chain, identify any duplicate deposits
|
|
936
|
-
// sent for this fill and refund them to the filler, because this value would not be paid out
|
|
937
|
-
// otherwise. These deposits can no longer expire and get refunded as an expired deposit,
|
|
938
|
-
// and they won't trigger a pre-fill refund because the fill is in this bundle.
|
|
939
|
-
// Pre-fill refunds only happen when deposits are sent in this bundle and the
|
|
940
|
-
// fill is from a prior bundle. Paying out the filler keeps the behavior consistent for how
|
|
941
|
-
// we deal with duplicate deposits regardless if the deposit is matched with a pre-fill or
|
|
942
|
-
// a current bundle fill.
|
|
943
|
-
const duplicateDeposits = v3RelayHashes[relayDataHash].deposits!.slice(1);
|
|
944
|
-
duplicateDeposits.forEach((duplicateDeposit) => {
|
|
945
|
-
if (isSlowFill(fill)) {
|
|
946
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
|
|
947
|
-
} else {
|
|
948
|
-
validatedBundleV3Fills.push({
|
|
949
|
-
...fillToRefund,
|
|
950
|
-
quoteTimestamp: duplicateDeposit.quoteTimestamp,
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
|
|
859
|
+
validatedBundleV3Fills.push({
|
|
860
|
+
...fill,
|
|
861
|
+
quoteTimestamp: v3RelayHashes[relayDataHash].deposit!.quoteTimestamp, // ! due to assert above
|
|
862
|
+
});
|
|
956
863
|
// If fill replaced a slow fill request, then mark it as one that might have created an
|
|
957
864
|
// unexecutable slow fill. We can't know for sure until we check the slow fill request
|
|
958
865
|
// events.
|
|
866
|
+
// slow fill requests for deposits from or to lite chains are considered invalid
|
|
959
867
|
if (
|
|
960
868
|
fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
|
|
961
|
-
_canCreateSlowFillLeaf(v3RelayHashes[relayDataHash].
|
|
869
|
+
_canCreateSlowFillLeaf(v3RelayHashes[relayDataHash].deposit!)
|
|
962
870
|
) {
|
|
963
871
|
fastFillsReplacingSlowFills.push(relayDataHash);
|
|
964
872
|
}
|
|
965
873
|
}
|
|
966
|
-
} else {
|
|
967
|
-
throw new Error("Duplicate fill detected");
|
|
968
874
|
}
|
|
969
875
|
return;
|
|
970
876
|
}
|
|
971
877
|
|
|
972
878
|
// At this point, there is no relay hash dictionary entry for this fill, so we need to
|
|
973
|
-
// instantiate the entry.
|
|
879
|
+
// instantiate the entry.
|
|
974
880
|
v3RelayHashes[relayDataHash] = {
|
|
975
|
-
|
|
976
|
-
fill,
|
|
881
|
+
deposit: undefined,
|
|
882
|
+
fill: fill,
|
|
977
883
|
slowFillRequest: undefined,
|
|
978
884
|
};
|
|
979
885
|
|
|
980
|
-
// TODO: We
|
|
886
|
+
// TODO: We might be able to remove the following historical query once we deprecate the deposit()
|
|
981
887
|
// function since there won't be any old, unexpired deposits anymore assuming the spoke pool client
|
|
982
888
|
// lookbacks have been validated, which they should be before we run this function.
|
|
983
889
|
|
|
@@ -993,6 +899,18 @@ export class BundleDataClient {
|
|
|
993
899
|
bundleInvalidFillsV3.push(fill);
|
|
994
900
|
return;
|
|
995
901
|
}
|
|
902
|
+
// If the fill's repayment address is not a valid EVM address and the repayment chain is an EVM chain, the fill is invalid.
|
|
903
|
+
if (chainIsEvm(fill.repaymentChainId) && !isValidEvmAddress(fill.relayer)) {
|
|
904
|
+
const fillTransaction = await originClient.spokePool.provider.getTransaction(fill.transactionHash);
|
|
905
|
+
const originRelayer = fillTransaction.from;
|
|
906
|
+
// Repayment chain is still an EVM chain, but the msg.sender is a bytes32 address, so the fill is invalid.
|
|
907
|
+
if (!isValidEvmAddress(originRelayer)) {
|
|
908
|
+
bundleInvalidFillsV3.push(fill);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
// Otherwise, assume the relayer to be repaid is the msg.sender.
|
|
912
|
+
fill.relayer = originRelayer;
|
|
913
|
+
}
|
|
996
914
|
// If deposit is using the deterministic relay hash feature, then the following binary search-based
|
|
997
915
|
// algorithm will not work. However, it is impossible to emit an infinite fill deadline using
|
|
998
916
|
// the unsafeDepositV3 function so there is no need to catch the special case.
|
|
@@ -1001,40 +919,17 @@ export class BundleDataClient {
|
|
|
1001
919
|
bundleInvalidFillsV3.push(fill);
|
|
1002
920
|
} else {
|
|
1003
921
|
const matchedDeposit = historicalDeposit.deposit;
|
|
1004
|
-
//
|
|
1005
|
-
//
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
matchedDeposit,
|
|
1016
|
-
allChainIds
|
|
1017
|
-
);
|
|
1018
|
-
if (!isDefined(fillToRefund)) {
|
|
1019
|
-
bundleUnrepayableFillsV3.push(fill);
|
|
1020
|
-
// Don't return yet as we still need to mark down any unexecutable slow fill leaves
|
|
1021
|
-
// in case this fast fill replaced a slow fill request.
|
|
1022
|
-
} else {
|
|
1023
|
-
// @dev Since queryHistoricalDepositForFill validates the fill by checking individual
|
|
1024
|
-
// object property values against the deposit's, we
|
|
1025
|
-
// sanity check it here by comparing the full relay hashes. If there's an error here then the
|
|
1026
|
-
// historical deposit query is not working as expected.
|
|
1027
|
-
assert(this.getRelayHashFromEvent(matchedDeposit) === relayDataHash, "Relay hashes should match.");
|
|
1028
|
-
validatedBundleV3Fills.push({
|
|
1029
|
-
...fillToRefund,
|
|
1030
|
-
quoteTimestamp: matchedDeposit.quoteTimestamp,
|
|
1031
|
-
});
|
|
1032
|
-
v3RelayHashes[relayDataHash].fill = fillToRefund;
|
|
1033
|
-
|
|
1034
|
-
// No need to check for duplicate deposits here since duplicate deposits with
|
|
1035
|
-
// infinite deadlines are impossible to send via unsafeDeposit().
|
|
1036
|
-
}
|
|
1037
|
-
|
|
922
|
+
// @dev Since queryHistoricalDepositForFill validates the fill by checking individual
|
|
923
|
+
// object property values against the deposit's, we
|
|
924
|
+
// sanity check it here by comparing the full relay hashes. If there's an error here then the
|
|
925
|
+
// historical deposit query is not working as expected.
|
|
926
|
+
assert(this.getRelayHashFromEvent(matchedDeposit) === relayDataHash, "Relay hashes should match.");
|
|
927
|
+
validatedBundleV3Fills.push({
|
|
928
|
+
...fill,
|
|
929
|
+
quoteTimestamp: matchedDeposit.quoteTimestamp,
|
|
930
|
+
});
|
|
931
|
+
v3RelayHashes[relayDataHash].deposit = matchedDeposit;
|
|
932
|
+
// slow fill requests for deposits from or to lite chains are considered invalid
|
|
1038
933
|
if (
|
|
1039
934
|
fill.relayExecutionInfo.fillType === FillType.ReplacedSlowFill &&
|
|
1040
935
|
_canCreateSlowFillLeaf(matchedDeposit)
|
|
@@ -1046,14 +941,8 @@ export class BundleDataClient {
|
|
|
1046
941
|
}
|
|
1047
942
|
);
|
|
1048
943
|
|
|
1049
|
-
// Process slow fill requests
|
|
1050
|
-
//
|
|
1051
|
-
// - Slow fill leaves cannot be produced for deposits that have been filled.
|
|
1052
|
-
|
|
1053
|
-
// Assumptions about fills:
|
|
1054
|
-
// - Duplicate slow fill requests for the same relay data hash are impossible to send.
|
|
1055
|
-
// - Slow fill requests can only be sent before the deposit's fillDeadline.
|
|
1056
|
-
// - Slow fill requests for a deposit that has been filled.
|
|
944
|
+
// Process slow fill requests. One invariant we need to maintain is that we cannot create slow fill requests
|
|
945
|
+
// for deposits that would expire in this bundle.
|
|
1057
946
|
await forEachAsync(
|
|
1058
947
|
destinationClient
|
|
1059
948
|
.getSlowFillRequestsForOriginChain(originChainId)
|
|
@@ -1066,40 +955,46 @@ export class BundleDataClient {
|
|
|
1066
955
|
|
|
1067
956
|
if (v3RelayHashes[relayDataHash]) {
|
|
1068
957
|
if (!v3RelayHashes[relayDataHash].slowFillRequest) {
|
|
958
|
+
// At this point, the v3RelayHashes entry already existed meaning that there is either a matching
|
|
959
|
+
// fill or deposit.
|
|
1069
960
|
v3RelayHashes[relayDataHash].slowFillRequest = slowFillRequest;
|
|
1070
961
|
if (v3RelayHashes[relayDataHash].fill) {
|
|
1071
|
-
//
|
|
1072
|
-
//
|
|
1073
|
-
// for a fill older than this slow fill request.
|
|
962
|
+
// If there is a fill matching the relay hash, then this slow fill request can't be used
|
|
963
|
+
// to create a slow fill for a filled deposit.
|
|
1074
964
|
return;
|
|
1075
965
|
}
|
|
1076
966
|
assert(
|
|
1077
|
-
isDefined(v3RelayHashes[relayDataHash].
|
|
967
|
+
isDefined(v3RelayHashes[relayDataHash].deposit),
|
|
1078
968
|
"Deposit should exist in relay hash dictionary."
|
|
1079
969
|
);
|
|
1080
|
-
|
|
970
|
+
// The ! is safe here because we've already checked that the deposit exists in the relay hash dictionary.
|
|
971
|
+
const matchedDeposit = v3RelayHashes[relayDataHash].deposit!;
|
|
1081
972
|
|
|
973
|
+
// If there is no fill matching the relay hash, then this might be a valid slow fill request
|
|
974
|
+
// that we should produce a slow fill leaf for. Check if the slow fill request is in the
|
|
975
|
+
// destination chain block range.
|
|
1082
976
|
if (
|
|
1083
977
|
slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
|
|
1084
978
|
_canCreateSlowFillLeaf(matchedDeposit) &&
|
|
979
|
+
// Deposit must not have expired in this bundle.
|
|
1085
980
|
!_depositIsExpired(matchedDeposit)
|
|
1086
981
|
) {
|
|
982
|
+
// At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
|
|
983
|
+
// so this slow fill request relay data is correct.
|
|
1087
984
|
validatedBundleSlowFills.push(matchedDeposit);
|
|
1088
985
|
}
|
|
1089
|
-
} else {
|
|
1090
|
-
throw new Error("Duplicate slow fill request detected.");
|
|
1091
986
|
}
|
|
1092
987
|
return;
|
|
1093
988
|
}
|
|
1094
989
|
|
|
1095
990
|
// Instantiate dictionary if there is neither a deposit nor fill matching it.
|
|
1096
991
|
v3RelayHashes[relayDataHash] = {
|
|
1097
|
-
|
|
992
|
+
deposit: undefined,
|
|
1098
993
|
fill: undefined,
|
|
1099
994
|
slowFillRequest: slowFillRequest,
|
|
1100
995
|
};
|
|
1101
996
|
|
|
1102
|
-
// TODO: We
|
|
997
|
+
// TODO: We might be able to remove the following historical query once we deprecate the deposit()
|
|
1103
998
|
// function since there won't be any old, unexpired deposits anymore assuming the spoke pool client
|
|
1104
999
|
// lookbacks have been validated, which they should be before we run this function.
|
|
1105
1000
|
|
|
@@ -1111,23 +1006,16 @@ export class BundleDataClient {
|
|
|
1111
1006
|
// want to perform a binary search lookup for it because the deposit ID is "unsafe" and cannot be
|
|
1112
1007
|
// found using such a method) because infinite fill deadlines cannot be produced from the unsafeDepositV3()
|
|
1113
1008
|
// function.
|
|
1114
|
-
if (
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
}
|
|
1009
|
+
if (
|
|
1010
|
+
slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
|
|
1011
|
+
INFINITE_FILL_DEADLINE.eq(slowFillRequest.fillDeadline)
|
|
1012
|
+
) {
|
|
1119
1013
|
const historicalDeposit = await queryHistoricalDepositForFill(originClient, slowFillRequest);
|
|
1120
1014
|
if (!historicalDeposit.found) {
|
|
1121
|
-
|
|
1015
|
+
// TODO: Invalid slow fill request. Maybe worth logging.
|
|
1122
1016
|
return;
|
|
1123
1017
|
}
|
|
1124
1018
|
const matchedDeposit: V3DepositWithBlock = historicalDeposit.deposit;
|
|
1125
|
-
// If deposit is in a following bundle, then this slow fill request will have to be created
|
|
1126
|
-
// once that deposit is in the current bundle.
|
|
1127
|
-
if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
|
|
1128
|
-
bundleInvalidSlowFillRequests.push(slowFillRequest);
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
1019
|
// @dev Since queryHistoricalDepositForFill validates the slow fill request by checking individual
|
|
1132
1020
|
// object property values against the deposit's, we
|
|
1133
1021
|
// sanity check it here by comparing the full relay hashes. If there's an error here then the
|
|
@@ -1136,9 +1024,13 @@ export class BundleDataClient {
|
|
|
1136
1024
|
this.getRelayHashFromEvent(matchedDeposit) === relayDataHash,
|
|
1137
1025
|
"Deposit relay hashes should match."
|
|
1138
1026
|
);
|
|
1139
|
-
v3RelayHashes[relayDataHash].
|
|
1027
|
+
v3RelayHashes[relayDataHash].deposit = matchedDeposit;
|
|
1140
1028
|
|
|
1141
|
-
if (
|
|
1029
|
+
if (
|
|
1030
|
+
!_canCreateSlowFillLeaf(matchedDeposit) ||
|
|
1031
|
+
// Deposit must not have expired in this bundle.
|
|
1032
|
+
_depositIsExpired(matchedDeposit)
|
|
1033
|
+
) {
|
|
1142
1034
|
return;
|
|
1143
1035
|
}
|
|
1144
1036
|
validatedBundleSlowFills.push(matchedDeposit);
|
|
@@ -1146,143 +1038,122 @@ export class BundleDataClient {
|
|
|
1146
1038
|
}
|
|
1147
1039
|
);
|
|
1148
1040
|
|
|
1149
|
-
//
|
|
1150
|
-
//
|
|
1151
|
-
//
|
|
1152
|
-
// -
|
|
1153
|
-
//
|
|
1154
|
-
// -
|
|
1155
|
-
//
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
// If fill is in the current bundle then we can assume there is already a refund for it, so only
|
|
1183
|
-
// include this pre fill if the fill is in an older bundle.
|
|
1184
|
-
if (fill) {
|
|
1185
|
-
if (canRefundPrefills && fill.blockNumber < destinationChainBlockRange[0]) {
|
|
1186
|
-
const fillToRefund = await verifyFillRepayment(
|
|
1187
|
-
fill,
|
|
1188
|
-
destinationClient.spokePool.provider,
|
|
1189
|
-
v3RelayHashes[relayDataHash].deposits![0],
|
|
1190
|
-
allChainIds
|
|
1191
|
-
);
|
|
1192
|
-
if (!isDefined(fillToRefund)) {
|
|
1193
|
-
bundleUnrepayableFillsV3.push(fill);
|
|
1194
|
-
} else if (!isSlowFill(fill)) {
|
|
1195
|
-
v3RelayHashes[relayDataHash].fill = fillToRefund;
|
|
1041
|
+
// Deposits can be submitted an arbitrary amount of time after matching fills and slow fill requests.
|
|
1042
|
+
// Therefore, let's go through each deposit in this bundle again and check a few things in order:
|
|
1043
|
+
// - Has the deposit been filled ? If so, then we need to issue a relayer refund for
|
|
1044
|
+
// this "pre-fill" if the fill took place in a previous bundle.
|
|
1045
|
+
// - Or, has the deposit expired in this bundle? If so, then we need to issue an expiry refund.
|
|
1046
|
+
// - And finally, has the deposit been slow filled? If so, then we need to issue a slow fill leaf
|
|
1047
|
+
// for this "pre-slow-fill-request" if this request took place in a previous bundle.
|
|
1048
|
+
await mapAsync(
|
|
1049
|
+
bundleDepositHashes.filter((depositHash) => {
|
|
1050
|
+
const { deposit } = v3RelayHashes[depositHash];
|
|
1051
|
+
return (
|
|
1052
|
+
deposit && deposit.originChainId === originChainId && deposit.destinationChainId === destinationChainId
|
|
1053
|
+
);
|
|
1054
|
+
}),
|
|
1055
|
+
async (depositHash) => {
|
|
1056
|
+
const { deposit, fill, slowFillRequest } = v3RelayHashes[depositHash];
|
|
1057
|
+
if (!deposit) throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1058
|
+
|
|
1059
|
+
// We are willing to refund a pre-fill multiple times for each duplicate deposit.
|
|
1060
|
+
// This is because a duplicate deposit for a pre-fill cannot get
|
|
1061
|
+
// refunded to the depositor anymore because its fill status on-chain has changed to Filled. Therefore
|
|
1062
|
+
// any duplicate deposits result in a net loss of funds for the depositor and effectively pay out
|
|
1063
|
+
// the pre-filler.
|
|
1064
|
+
|
|
1065
|
+
// If fill exists in memory, then the only case in which we need to create a refund is if the
|
|
1066
|
+
// the fill occurred in a previous bundle. There are no expiry refunds for filled deposits.
|
|
1067
|
+
if (fill) {
|
|
1068
|
+
if (fill.blockNumber < destinationChainBlockRange[0] && !isSlowFill(fill)) {
|
|
1069
|
+
// If fill is in the current bundle then we can assume there is already a refund for it, so only
|
|
1070
|
+
// include this pre fill if the fill is in an older bundle. If fill is after this current bundle, then
|
|
1071
|
+
// we won't consider it, following the previous treatment of fills after the bundle block range.
|
|
1196
1072
|
validatedBundleV3Fills.push({
|
|
1197
|
-
...
|
|
1073
|
+
...fill,
|
|
1198
1074
|
quoteTimestamp: deposit.quoteTimestamp,
|
|
1199
1075
|
});
|
|
1200
|
-
} else {
|
|
1201
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1202
1076
|
}
|
|
1077
|
+
return;
|
|
1203
1078
|
}
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
1079
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1080
|
+
// If a slow fill request exists in memory, then we know the deposit has not been filled because fills
|
|
1081
|
+
// must follow slow fill requests and we would have seen the fill already if it existed. Therefore,
|
|
1082
|
+
// we can conclude that either the deposit has expired and we need to create a deposit expiry refund, or
|
|
1083
|
+
// we need to create a slow fill leaf for the deposit. The latter should only happen if the slow fill request
|
|
1084
|
+
// took place in a prior bundle otherwise we would have already created a slow fill leaf for it.
|
|
1085
|
+
if (slowFillRequest) {
|
|
1086
|
+
if (_depositIsExpired(deposit)) {
|
|
1087
|
+
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1088
|
+
} else if (
|
|
1089
|
+
slowFillRequest.blockNumber < destinationChainBlockRange[0] &&
|
|
1090
|
+
_canCreateSlowFillLeaf(deposit)
|
|
1091
|
+
) {
|
|
1092
|
+
validatedBundleSlowFills.push(deposit);
|
|
1093
|
+
}
|
|
1094
|
+
return;
|
|
1222
1095
|
}
|
|
1223
|
-
return;
|
|
1224
|
-
}
|
|
1225
1096
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
//
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
if (canRefundPrefills) {
|
|
1240
|
-
const verifiedFill = await verifyFillRepayment(
|
|
1241
|
-
prefill!,
|
|
1242
|
-
destinationClient.spokePool.provider,
|
|
1097
|
+
// So at this point in the code, there is no fill or slow fill request in memory for this deposit.
|
|
1098
|
+
// We need to check its fill status on-chain to figure out whether to issue a refund or a slow fill leaf.
|
|
1099
|
+
// We can assume at this point that all fills or slow fill requests, if found, were in previous bundles
|
|
1100
|
+
// because the spoke pool client lookback would have returned this entire bundle of events and stored
|
|
1101
|
+
// them into the relay hash dictionary.
|
|
1102
|
+
const fillStatus = await _getFillStatusForDeposit(deposit, destinationChainBlockRange[1]);
|
|
1103
|
+
|
|
1104
|
+
// If deposit was filled, then we need to issue a refund for it.
|
|
1105
|
+
if (fillStatus === FillStatus.Filled) {
|
|
1106
|
+
// We need to find the fill event to issue a refund to the right relayer and repayment chain,
|
|
1107
|
+
// or msg.sender if relayer address is invalid for the repayment chain.
|
|
1108
|
+
const prefill = (await findFillEvent(
|
|
1109
|
+
destinationClient.spokePool,
|
|
1243
1110
|
deposit,
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
} else if (!isSlowFill(verifiedFill)) {
|
|
1111
|
+
destinationClient.deploymentBlock,
|
|
1112
|
+
destinationClient.latestBlockSearched
|
|
1113
|
+
)) as unknown as FillWithBlock;
|
|
1114
|
+
if (!isSlowFill(prefill)) {
|
|
1249
1115
|
validatedBundleV3Fills.push({
|
|
1250
|
-
...
|
|
1116
|
+
...prefill,
|
|
1251
1117
|
quoteTimestamp: deposit.quoteTimestamp,
|
|
1252
1118
|
});
|
|
1253
|
-
} else {
|
|
1254
|
-
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1255
1119
|
}
|
|
1256
1120
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1121
|
+
// If deposit is not filled and its newly expired, we can create a deposit refund for it.
|
|
1122
|
+
// We don't check that fillDeadline >= bundleBlockTimestamps[destinationChainId][0] because
|
|
1123
|
+
// that would eliminate any deposits in this bundle with a very low fillDeadline like equal to 0
|
|
1124
|
+
// for example. Those should be included in this bundle of refunded deposits.
|
|
1125
|
+
else if (_depositIsExpired(deposit)) {
|
|
1126
|
+
updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
|
|
1127
|
+
}
|
|
1128
|
+
// If slow fill requested, then issue a slow fill leaf for the deposit.
|
|
1129
|
+
else if (fillStatus === FillStatus.RequestedSlowFill) {
|
|
1130
|
+
// Input and Output tokens must be equivalent on the deposit for this to be slow filled.
|
|
1131
|
+
// Slow fill requests for deposits from or to lite chains are considered invalid
|
|
1132
|
+
if (_canCreateSlowFillLeaf(deposit)) {
|
|
1133
|
+
// If deposit newly expired, then we can't create a slow fill leaf for it but we can
|
|
1134
|
+
// create a deposit refund for it.
|
|
1135
|
+
validatedBundleSlowFills.push(deposit);
|
|
1136
|
+
}
|
|
1266
1137
|
}
|
|
1267
1138
|
}
|
|
1268
|
-
|
|
1139
|
+
);
|
|
1269
1140
|
|
|
1270
1141
|
// For all fills that came after a slow fill request, we can now check if the slow fill request
|
|
1271
1142
|
// was a valid one and whether it was created in a previous bundle. If so, then it created a slow fill
|
|
1272
1143
|
// leaf that is now unexecutable.
|
|
1273
1144
|
fastFillsReplacingSlowFills.forEach((relayDataHash) => {
|
|
1274
|
-
const {
|
|
1145
|
+
const { deposit, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
|
|
1275
1146
|
assert(
|
|
1276
1147
|
fill?.relayExecutionInfo.fillType === FillType.ReplacedSlowFill,
|
|
1277
1148
|
"Fill type should be ReplacedSlowFill."
|
|
1278
1149
|
);
|
|
1279
1150
|
// Needed for TSC - are implicitely checking that deposit exists by making it to this point.
|
|
1280
|
-
if (!
|
|
1151
|
+
if (!deposit) {
|
|
1281
1152
|
throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1282
1153
|
}
|
|
1283
1154
|
// We should never push fast fills involving lite chains here because slow fill requests for them are invalid:
|
|
1284
1155
|
assert(
|
|
1285
|
-
_canCreateSlowFillLeaf(
|
|
1156
|
+
_canCreateSlowFillLeaf(deposit),
|
|
1286
1157
|
"fastFillsReplacingSlowFills should contain only deposits that can be slow filled"
|
|
1287
1158
|
);
|
|
1288
1159
|
const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
|
|
@@ -1292,7 +1163,7 @@ export class BundleDataClient {
|
|
|
1292
1163
|
!slowFillRequest ||
|
|
1293
1164
|
slowFillRequest.blockNumber < destinationBlockRange[0]
|
|
1294
1165
|
) {
|
|
1295
|
-
validatedBundleUnexecutableSlowFills.push(
|
|
1166
|
+
validatedBundleUnexecutableSlowFills.push(deposit);
|
|
1296
1167
|
}
|
|
1297
1168
|
});
|
|
1298
1169
|
}
|
|
@@ -1306,19 +1177,15 @@ export class BundleDataClient {
|
|
|
1306
1177
|
// For all deposits older than this bundle, we need to check if they expired in this bundle and if they did,
|
|
1307
1178
|
// whether there was a slow fill created for it in a previous bundle that is now unexecutable and replaced
|
|
1308
1179
|
// by a new expired deposit refund.
|
|
1309
|
-
await forEachAsync(olderDepositHashes, async (
|
|
1310
|
-
const {
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
throw new Error("Deposit should exist in relay hash dictionary.");
|
|
1314
|
-
}
|
|
1315
|
-
const deposit = deposits[index];
|
|
1316
|
-
const { destinationChainId } = deposit;
|
|
1180
|
+
await forEachAsync(olderDepositHashes, async (relayDataHash) => {
|
|
1181
|
+
const { deposit, slowFillRequest, fill } = v3RelayHashes[relayDataHash];
|
|
1182
|
+
assert(isDefined(deposit), "Deposit should exist in relay hash dictionary.");
|
|
1183
|
+
const { destinationChainId } = deposit!;
|
|
1317
1184
|
const destinationBlockRange = getBlockRangeForChain(blockRangesForChains, destinationChainId, chainIds);
|
|
1318
1185
|
|
|
1319
1186
|
// Only look for deposits that were mined before this bundle and that are newly expired.
|
|
1320
1187
|
// If the fill deadline is lower than the bundle start block on the destination chain, then
|
|
1321
|
-
// we should assume it was refunded in a previous bundle.
|
|
1188
|
+
// we should assume it was marked "newly expired" and refunded in a previous bundle.
|
|
1322
1189
|
if (
|
|
1323
1190
|
// If there is a valid fill that we saw matching this deposit, then it does not need a refund.
|
|
1324
1191
|
!fill &&
|
|
@@ -1362,7 +1229,7 @@ export class BundleDataClient {
|
|
|
1362
1229
|
validatedBundleV3Fills.length > 0
|
|
1363
1230
|
? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(
|
|
1364
1231
|
validatedBundleV3Fills.map((fill) => {
|
|
1365
|
-
const matchedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].
|
|
1232
|
+
const matchedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].deposit;
|
|
1366
1233
|
assert(isDefined(matchedDeposit), "Deposit should exist in relay hash dictionary.");
|
|
1367
1234
|
const { chainToSendRefundTo: paymentChainId } = getRefundInformationFromFill(
|
|
1368
1235
|
fill,
|
|
@@ -1406,7 +1273,7 @@ export class BundleDataClient {
|
|
|
1406
1273
|
});
|
|
1407
1274
|
v3FillLpFees.forEach(({ realizedLpFeePct }, idx) => {
|
|
1408
1275
|
const fill = validatedBundleV3Fills[idx];
|
|
1409
|
-
const associatedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].
|
|
1276
|
+
const associatedDeposit = v3RelayHashes[this.getRelayHashFromEvent(fill)].deposit;
|
|
1410
1277
|
assert(isDefined(associatedDeposit), "Deposit should exist in relay hash dictionary.");
|
|
1411
1278
|
const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
|
|
1412
1279
|
fill,
|
|
@@ -1415,19 +1282,10 @@ export class BundleDataClient {
|
|
|
1415
1282
|
chainIds,
|
|
1416
1283
|
associatedDeposit!.fromLiteChain
|
|
1417
1284
|
);
|
|
1418
|
-
updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken
|
|
1285
|
+
updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken);
|
|
1419
1286
|
});
|
|
1420
1287
|
v3SlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
|
|
1421
1288
|
const deposit = validatedBundleSlowFills[idx];
|
|
1422
|
-
// We should not create slow fill leaves for duplicate deposit hashes and we should only create a slow
|
|
1423
|
-
// fill leaf for the first deposit (the quote timestamp of the deposit determines the LP fee, so its
|
|
1424
|
-
// important we pick out the correct deposit). Deposits are pushed into validatedBundleSlowFills in ascending
|
|
1425
|
-
// order so the following slice will only match the first deposit.
|
|
1426
|
-
const relayDataHash = this.getRelayHashFromEvent(deposit);
|
|
1427
|
-
if (validatedBundleSlowFills.slice(0, idx).some((d) => this.getRelayHashFromEvent(d) === relayDataHash)) {
|
|
1428
|
-
return;
|
|
1429
|
-
}
|
|
1430
|
-
assert(!_depositIsExpired(deposit), "Cannot create slow fill leaf for expired deposit.");
|
|
1431
1289
|
updateBundleSlowFills(bundleSlowFillsV3, { ...deposit, lpFeePct });
|
|
1432
1290
|
});
|
|
1433
1291
|
v3UnexecutableSlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
|
|
@@ -1438,6 +1296,7 @@ export class BundleDataClient {
|
|
|
1438
1296
|
const v3SpokeEventsReadable = prettyPrintV3SpokePoolEvents(
|
|
1439
1297
|
bundleDepositsV3,
|
|
1440
1298
|
bundleFillsV3,
|
|
1299
|
+
bundleInvalidFillsV3,
|
|
1441
1300
|
bundleSlowFillsV3,
|
|
1442
1301
|
expiredDepositsToRefundV3,
|
|
1443
1302
|
unexecutableSlowFills
|
|
@@ -1446,30 +1305,12 @@ export class BundleDataClient {
|
|
|
1446
1305
|
if (bundleInvalidFillsV3.length > 0) {
|
|
1447
1306
|
this.logger.debug({
|
|
1448
1307
|
at: "BundleDataClient#loadData",
|
|
1449
|
-
message: "Finished loading V3 spoke pool data and found some invalid fills in range",
|
|
1308
|
+
message: "Finished loading V3 spoke pool data and found some invalid V3 fills in range",
|
|
1450
1309
|
blockRangesForChains,
|
|
1451
1310
|
bundleInvalidFillsV3,
|
|
1452
1311
|
});
|
|
1453
1312
|
}
|
|
1454
1313
|
|
|
1455
|
-
if (bundleUnrepayableFillsV3.length > 0) {
|
|
1456
|
-
this.logger.debug({
|
|
1457
|
-
at: "BundleDataClient#loadData",
|
|
1458
|
-
message: "Finished loading V3 spoke pool data and found some unrepayable fills in range",
|
|
1459
|
-
blockRangesForChains,
|
|
1460
|
-
bundleUnrepayableFillsV3,
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
if (bundleInvalidSlowFillRequests.length > 0) {
|
|
1465
|
-
this.logger.debug({
|
|
1466
|
-
at: "BundleDataClient#loadData",
|
|
1467
|
-
message: "Finished loading V3 spoke pool data and found some invalid slow fill requests in range",
|
|
1468
|
-
blockRangesForChains,
|
|
1469
|
-
bundleInvalidSlowFillRequests,
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
1314
|
this.logger.debug({
|
|
1474
1315
|
at: "BundleDataClient#loadDataFromScratch",
|
|
1475
1316
|
message: `Computed bundle data in ${Math.round(performance.now() - start) / 1000}s.`,
|
|
@@ -1489,7 +1330,7 @@ export class BundleDataClient {
|
|
|
1489
1330
|
// keccak256 hash of the relay data, which can be used as input into the on-chain `fillStatuses()` function in the
|
|
1490
1331
|
// spoke pool contract. However, this internal function is used to uniquely identify a bridging event
|
|
1491
1332
|
// for speed since its easier to build a string from the event data than to hash it.
|
|
1492
|
-
|
|
1333
|
+
private getRelayHashFromEvent(event: V3DepositWithBlock | V3FillWithBlock | SlowFillRequestWithBlock): string {
|
|
1493
1334
|
return `${event.depositor}-${event.recipient}-${event.exclusiveRelayer}-${event.inputToken}-${event.outputToken}-${
|
|
1494
1335
|
event.inputAmount
|
|
1495
1336
|
}-${event.outputAmount}-${event.originChainId}-${event.depositId.toString()}-${event.fillDeadline}-${
|
|
@@ -1497,18 +1338,6 @@ export class BundleDataClient {
|
|
|
1497
1338
|
}-${event.message}-${event.destinationChainId}`;
|
|
1498
1339
|
}
|
|
1499
1340
|
|
|
1500
|
-
protected async findMatchingFillEvent(
|
|
1501
|
-
deposit: DepositWithBlock,
|
|
1502
|
-
spokePoolClient: SpokePoolClient
|
|
1503
|
-
): Promise<FillWithBlock | undefined> {
|
|
1504
|
-
return await findFillEvent(
|
|
1505
|
-
spokePoolClient.spokePool,
|
|
1506
|
-
deposit,
|
|
1507
|
-
spokePoolClient.deploymentBlock,
|
|
1508
|
-
spokePoolClient.latestBlockSearched
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
1341
|
async getBundleBlockTimestamps(
|
|
1513
1342
|
chainIds: number[],
|
|
1514
1343
|
blockRangesForChains: number[][],
|
|
@@ -1534,26 +1363,13 @@ export class BundleDataClient {
|
|
|
1534
1363
|
// will usually be called in production with block ranges that were validated by
|
|
1535
1364
|
// DataworkerUtils.blockRangesAreInvalidForSpokeClients.
|
|
1536
1365
|
const startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestBlockSearched);
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
// in exactly one bundle, therefore we must make sure that the bundle block timestamp for one bundle's
|
|
1540
|
-
// end block is exactly equal to the bundle block timestamp for the next bundle's start block. This way
|
|
1541
|
-
// there are no gaps in block timestamps between bundles.
|
|
1542
|
-
const endBlockForChain = Math.min(_endBlockForChain + 1, spokePoolClient.latestBlockSearched);
|
|
1543
|
-
const [startTime, _endTime] = [
|
|
1366
|
+
const endBlockForChain = Math.min(_endBlockForChain, spokePoolClient.latestBlockSearched);
|
|
1367
|
+
const [startTime, endTime] = [
|
|
1544
1368
|
await spokePoolClient.getTimestampForBlock(startBlockForChain),
|
|
1545
1369
|
await spokePoolClient.getTimestampForBlock(endBlockForChain),
|
|
1546
1370
|
];
|
|
1547
|
-
// @dev similar to reasoning above to ensure no gaps between bundle block range timestamps and also
|
|
1548
|
-
// no overlap, subtract 1 from the end time.
|
|
1549
|
-
const endBlockDelta = endBlockForChain > startBlockForChain ? 1 : 0;
|
|
1550
|
-
const endTime = Math.max(0, _endTime - endBlockDelta);
|
|
1551
|
-
|
|
1552
1371
|
// Sanity checks:
|
|
1553
|
-
assert(
|
|
1554
|
-
endTime >= startTime,
|
|
1555
|
-
`End time for block ${endBlockForChain} should be greater than start time for block ${startBlockForChain}: ${endTime} >= ${startTime}.`
|
|
1556
|
-
);
|
|
1372
|
+
assert(endTime >= startTime, "End time should be greater than start time.");
|
|
1557
1373
|
assert(
|
|
1558
1374
|
startBlockForChain === 0 || startTime > 0,
|
|
1559
1375
|
"Start timestamp must be greater than 0 if the start block is greater than 0."
|