@across-protocol/sdk 3.4.15 → 3.4.16

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.
Files changed (37) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +174 -123
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  5. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +33 -1
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  7. package/dist/cjs/providers/index.d.ts +1 -0
  8. package/dist/cjs/providers/index.js +2 -0
  9. package/dist/cjs/providers/index.js.map +1 -1
  10. package/dist/cjs/providers/mockProvider.d.ts +19 -0
  11. package/dist/cjs/providers/mockProvider.js +70 -0
  12. package/dist/cjs/providers/mockProvider.js.map +1 -0
  13. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  14. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +204 -151
  15. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  16. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  17. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +42 -1
  18. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  19. package/dist/esm/providers/index.d.ts +1 -0
  20. package/dist/esm/providers/index.js +2 -0
  21. package/dist/esm/providers/index.js.map +1 -1
  22. package/dist/esm/providers/mockProvider.d.ts +23 -0
  23. package/dist/esm/providers/mockProvider.js +73 -0
  24. package/dist/esm/providers/mockProvider.js.map +1 -0
  25. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  26. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  27. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  28. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  29. package/dist/types/providers/index.d.ts +1 -0
  30. package/dist/types/providers/index.d.ts.map +1 -1
  31. package/dist/types/providers/mockProvider.d.ts +24 -0
  32. package/dist/types/providers/mockProvider.d.ts.map +1 -0
  33. package/package.json +1 -1
  34. package/src/clients/BundleDataClient/BundleDataClient.ts +98 -70
  35. package/src/clients/BundleDataClient/utils/FillUtils.ts +47 -2
  36. package/src/providers/index.ts +1 -0
  37. package/src/providers/mockProvider.ts +77 -0
@@ -30,6 +30,7 @@ import {
30
30
  getImpliedBundleBlockRanges,
31
31
  isSlowFill,
32
32
  mapAsync,
33
+ filterAsync,
33
34
  bnUint32Max,
34
35
  isZeroValueDeposit,
35
36
  chainIsEvm,
@@ -48,6 +49,7 @@ import {
48
49
  prettyPrintV3SpokePoolEvents,
49
50
  V3DepositWithBlock,
50
51
  V3FillWithBlock,
52
+ verifyFillRepayment,
51
53
  } from "./utils";
52
54
 
53
55
  // max(uint256) - 1
@@ -81,10 +83,11 @@ function updateBundleFillsV3(
81
83
  fill: V3FillWithBlock,
82
84
  lpFeePct: BigNumber,
83
85
  repaymentChainId: number,
84
- repaymentToken: string
86
+ repaymentToken: string,
87
+ repaymentAddress: string
85
88
  ): void {
86
89
  // It is impossible to refund a deposit if the repayment chain is EVM and the relayer is a non-evm address.
87
- if (chainIsEvm(fill.repaymentChainId) && !isValidEvmAddress(fill.relayer)) {
90
+ if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(repaymentAddress)) {
88
91
  return;
89
92
  }
90
93
  if (!dict?.[repaymentChainId]?.[repaymentToken]) {
@@ -96,19 +99,19 @@ function updateBundleFillsV3(
96
99
  });
97
100
  }
98
101
 
99
- const bundleFill: BundleFillV3 = { ...fill, lpFeePct };
102
+ const bundleFill: BundleFillV3 = { ...fill, lpFeePct, relayer: repaymentAddress };
100
103
 
101
104
  // Add all fills, slow and fast, to dictionary.
102
105
  assign(dict, [repaymentChainId, repaymentToken, "fills"], [bundleFill]);
103
106
 
104
107
  // All fills update the bundle LP fees.
105
108
  const refundObj = dict[repaymentChainId][repaymentToken];
106
- const realizedLpFee = fill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
109
+ const realizedLpFee = bundleFill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
107
110
  refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
108
111
 
109
112
  // Only fast fills get refunded.
110
- if (!isSlowFill(fill)) {
111
- const refundAmount = fill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
113
+ if (!isSlowFill(bundleFill)) {
114
+ const refundAmount = bundleFill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
112
115
  refundObj.totalRefundAmount = refundObj.totalRefundAmount
113
116
  ? refundObj.totalRefundAmount.add(refundAmount)
114
117
  : refundAmount;
@@ -116,10 +119,10 @@ function updateBundleFillsV3(
116
119
  // Instantiate dictionary if it doesn't exist.
117
120
  refundObj.refunds ??= {};
118
121
 
119
- if (refundObj.refunds[fill.relayer]) {
120
- refundObj.refunds[fill.relayer] = refundObj.refunds[fill.relayer].add(refundAmount);
122
+ if (refundObj.refunds[bundleFill.relayer]) {
123
+ refundObj.refunds[bundleFill.relayer] = refundObj.refunds[bundleFill.relayer].add(refundAmount);
121
124
  } else {
122
- refundObj.refunds[fill.relayer] = refundAmount;
125
+ refundObj.refunds[bundleFill.relayer] = refundAmount;
123
126
  }
124
127
  }
125
128
  }
@@ -287,7 +290,7 @@ export class BundleDataClient {
287
290
  // so as not to affect this approximate refund count.
288
291
  const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
289
292
  if (arweaveData === undefined) {
290
- combinedRefunds = this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
293
+ combinedRefunds = await this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
291
294
  } else {
292
295
  const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
293
296
  combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
@@ -308,50 +311,63 @@ export class BundleDataClient {
308
311
  }
309
312
 
310
313
  // @dev This helper function should probably be moved to the InventoryClient
311
- getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): CombinedRefunds {
314
+ async getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): Promise<CombinedRefunds> {
312
315
  const refundsForChain: CombinedRefunds = {};
313
316
  for (const chainId of chainIds) {
314
317
  if (this.spokePoolClients[chainId] === undefined) {
315
318
  continue;
316
319
  }
317
320
  const chainIndex = chainIds.indexOf(chainId);
318
- this.spokePoolClients[chainId]
319
- .getFills()
320
- .filter((fill) => {
321
- if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
322
- return false;
323
- }
321
+ const fillsToCount = await filterAsync(this.spokePoolClients[chainId].getFills(), async (fill) => {
322
+ if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
323
+ return false;
324
+ }
324
325
 
325
- // If origin spoke pool client isn't defined, we can't validate it.
326
- if (this.spokePoolClients[fill.originChainId] === undefined) {
327
- return false;
328
- }
329
- const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
330
- const hasMatchingDeposit =
331
- matchingDeposit !== undefined &&
332
- this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
333
- return hasMatchingDeposit;
334
- })
335
- .forEach((fill) => {
336
- const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
337
- assert(isDefined(matchingDeposit), "Deposit not found for fill.");
338
- const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
326
+ // If origin spoke pool client isn't defined, we can't validate it.
327
+ if (this.spokePoolClients[fill.originChainId] === undefined) {
328
+ return false;
329
+ }
330
+ const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
331
+ const hasMatchingDeposit =
332
+ matchingDeposit !== undefined &&
333
+ this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
334
+ if (hasMatchingDeposit) {
335
+ const validRepayment = await verifyFillRepayment(
339
336
  fill,
340
- this.clients.hubPoolClient,
341
- blockRanges,
342
- this.chainIdListForBundleEvaluationBlockNumbers,
343
- matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
337
+ this.spokePoolClients[fill.destinationChainId].spokePool.provider,
338
+ matchingDeposit,
339
+ // @dev: to get valid repayment chain ID's, get all chain IDs for the bundle block range and remove
340
+ // disabled block ranges.
341
+ this.clients.configStoreClient
342
+ .getChainIdIndicesForBlock(blockRanges[0][1])
343
+ .filter((_chainId, i) => !isChainDisabled(blockRanges[i]))
344
344
  );
345
- // Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
346
- // these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
347
- // in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
348
- // worst from the relayer's perspective.
349
- const { relayer, inputAmount: refundAmount } = fill;
350
- refundsForChain[chainToSendRefundTo] ??= {};
351
- refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
352
- const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
353
- refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
354
- });
345
+ if (!isDefined(validRepayment)) {
346
+ return false;
347
+ }
348
+ }
349
+ return hasMatchingDeposit;
350
+ });
351
+ fillsToCount.forEach((fill) => {
352
+ const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
353
+ assert(isDefined(matchingDeposit), "Deposit not found for fill.");
354
+ const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
355
+ fill,
356
+ this.clients.hubPoolClient,
357
+ blockRanges,
358
+ this.chainIdListForBundleEvaluationBlockNumbers,
359
+ matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
360
+ );
361
+ // Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
362
+ // these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
363
+ // in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
364
+ // worst from the relayer's perspective.
365
+ const { relayer, inputAmount: refundAmount } = fill;
366
+ refundsForChain[chainToSendRefundTo] ??= {};
367
+ refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
368
+ const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
369
+ refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
370
+ });
355
371
  }
356
372
  return refundsForChain;
357
373
  }
@@ -478,7 +494,7 @@ export class BundleDataClient {
478
494
  // ok for this use case.
479
495
  const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
480
496
  if (arweaveData === undefined) {
481
- combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
497
+ combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
482
498
  } else {
483
499
  const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
484
500
  combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
@@ -493,7 +509,7 @@ export class BundleDataClient {
493
509
  // - Only look up fills sent after the pending bundle's end blocks
494
510
  // - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
495
511
  const start = performance.now();
496
- combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
512
+ combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
497
513
  this.logger.debug({
498
514
  at: "BundleDataClient#getNextBundleRefunds",
499
515
  message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
@@ -868,16 +884,28 @@ export class BundleDataClient {
868
884
  // tokens to the filler. We can't remove non-empty message deposit here in case there is a slow fill
869
885
  // request for the deposit, we'd want to see the fill took place.
870
886
  .filter((fill) => fill.blockNumber <= destinationChainBlockRange[1] && !isZeroValueDeposit(fill)),
871
- async (fill) => {
872
- const relayDataHash = this.getRelayHashFromEvent(fill);
887
+ async (_fill) => {
873
888
  fillCounter++;
874
-
889
+ const relayDataHash = this.getRelayHashFromEvent(_fill);
875
890
  if (v3RelayHashes[relayDataHash]) {
876
891
  if (!v3RelayHashes[relayDataHash].fill) {
877
892
  assert(
878
893
  isDefined(v3RelayHashes[relayDataHash].deposit),
879
894
  "Deposit should exist in relay hash dictionary."
880
895
  );
896
+ // `fill` will only possibly differ from `_fill` in the `relayer` field, which does not affect the
897
+ // relay hash, so it is safe to modify.
898
+ const fill = await verifyFillRepayment(
899
+ _fill,
900
+ destinationClient.spokePool.provider,
901
+ v3RelayHashes[relayDataHash].deposit!,
902
+ allChainIds
903
+ );
904
+ if (!isDefined(fill)) {
905
+ bundleInvalidFillsV3.push(_fill);
906
+ return;
907
+ }
908
+
881
909
  // At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
882
910
  // so this fill is validated.
883
911
  v3RelayHashes[relayDataHash].fill = fill;
@@ -903,10 +931,10 @@ export class BundleDataClient {
903
931
  }
904
932
 
905
933
  // At this point, there is no relay hash dictionary entry for this fill, so we need to
906
- // instantiate the entry.
934
+ // instantiate the entry. We won't modify the fill.relayer until we match it with a deposit.
907
935
  v3RelayHashes[relayDataHash] = {
908
936
  deposit: undefined,
909
- fill: fill,
937
+ fill: _fill,
910
938
  slowFillRequest: undefined,
911
939
  };
912
940
 
@@ -918,34 +946,34 @@ export class BundleDataClient {
918
946
  // older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
919
947
  // We can skip this step if the fill's fill deadline is not infinite, because we can assume that the
920
948
  // spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
921
- if (fill.blockNumber >= destinationChainBlockRange[0]) {
949
+ if (_fill.blockNumber >= destinationChainBlockRange[0]) {
922
950
  // Fill has a non-infinite expiry, and we can assume our spoke pool clients have old enough deposits
923
951
  // to conclude that this fill is invalid if we haven't found a matching deposit in memory, so
924
952
  // skip the historical query.
925
- if (!INFINITE_FILL_DEADLINE.eq(fill.fillDeadline)) {
926
- bundleInvalidFillsV3.push(fill);
953
+ if (!INFINITE_FILL_DEADLINE.eq(_fill.fillDeadline)) {
954
+ bundleInvalidFillsV3.push(_fill);
927
955
  return;
928
956
  }
929
- // If the fill's repayment address is not a valid EVM address and the repayment chain is an EVM chain, the fill is invalid.
930
- if (chainIsEvm(fill.repaymentChainId) && !isValidEvmAddress(fill.relayer)) {
931
- const fillTransaction = await originClient.spokePool.provider.getTransaction(fill.transactionHash);
932
- const originRelayer = fillTransaction.from;
933
- // Repayment chain is still an EVM chain, but the msg.sender is a bytes32 address, so the fill is invalid.
934
- if (!isValidEvmAddress(originRelayer)) {
935
- bundleInvalidFillsV3.push(fill);
936
- return;
937
- }
938
- // Otherwise, assume the relayer to be repaid is the msg.sender.
939
- fill.relayer = originRelayer;
940
- }
941
957
  // If deposit is using the deterministic relay hash feature, then the following binary search-based
942
958
  // algorithm will not work. However, it is impossible to emit an infinite fill deadline using
943
959
  // the unsafeDepositV3 function so there is no need to catch the special case.
944
- const historicalDeposit = await queryHistoricalDepositForFill(originClient, fill);
960
+ const historicalDeposit = await queryHistoricalDepositForFill(originClient, _fill);
945
961
  if (!historicalDeposit.found) {
946
- bundleInvalidFillsV3.push(fill);
962
+ bundleInvalidFillsV3.push(_fill);
947
963
  } else {
948
964
  const matchedDeposit = historicalDeposit.deposit;
965
+ const fill = await verifyFillRepayment(
966
+ _fill,
967
+ destinationClient.spokePool.provider,
968
+ matchedDeposit,
969
+ allChainIds
970
+ );
971
+ if (!isDefined(fill)) {
972
+ bundleInvalidFillsV3.push(_fill);
973
+ return;
974
+ }
975
+ v3RelayHashes[relayDataHash].fill = fill;
976
+
949
977
  // @dev Since queryHistoricalDepositForFill validates the fill by checking individual
950
978
  // object property values against the deposit's, we
951
979
  // sanity check it here by comparing the full relay hashes. If there's an error here then the
@@ -1286,7 +1314,7 @@ export class BundleDataClient {
1286
1314
  chainIds,
1287
1315
  associatedDeposit!.fromLiteChain
1288
1316
  );
1289
- updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken);
1317
+ updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken, fill.relayer);
1290
1318
  });
1291
1319
  v3SlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
1292
1320
  const deposit = validatedBundleSlowFills[idx];
@@ -1,5 +1,7 @@
1
- import { Fill } from "../../../interfaces";
2
- import { getBlockRangeForChain, isSlowFill } from "../../../utils";
1
+ import _ from "lodash";
2
+ import { providers } from "ethers";
3
+ import { DepositWithBlock, Fill, FillWithBlock } from "../../../interfaces";
4
+ import { getBlockRangeForChain, isSlowFill, chainIsEvm, isValidEvmAddress, isDefined } from "../../../utils";
3
5
  import { HubPoolClient } from "../../HubPoolClient";
4
6
 
5
7
  export function getRefundInformationFromFill(
@@ -44,3 +46,46 @@ export function getRefundInformationFromFill(
44
46
  repaymentToken,
45
47
  };
46
48
  }
49
+
50
+ // Verify that a fill sent to an EVM chain has a 20 byte address. If the fill does not, then attempt
51
+ // to repay the `msg.sender` of the relay transaction. Otherwise, return undefined.
52
+ export async function verifyFillRepayment(
53
+ fill: FillWithBlock,
54
+ destinationChainProvider: providers.Provider,
55
+ matchedDeposit: DepositWithBlock,
56
+ possibleRepaymentChainIds: number[]
57
+ ): Promise<FillWithBlock | undefined> {
58
+ // Slow fills don't result in repayments so they're always valid.
59
+ if (isSlowFill(fill)) {
60
+ return fill;
61
+ }
62
+ // Lite chain deposits force repayment on origin chain.
63
+ const repaymentChainId = matchedDeposit.fromLiteChain ? fill.originChainId : fill.repaymentChainId;
64
+ // Return undefined if the requested repayment chain ID is not recognized by the hub pool.
65
+ if (!possibleRepaymentChainIds.includes(repaymentChainId)) {
66
+ return undefined;
67
+ }
68
+ const updatedFill = _.cloneDeep(fill);
69
+
70
+ // If the fill requests repayment on a chain where the repayment address is not valid, attempt to find a valid
71
+ // repayment address, otherwise return undefined.
72
+
73
+ // Case 1: repayment chain is an EVM chain but repayment address is not a valid EVM address.
74
+ if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(updatedFill.relayer)) {
75
+ // TODO: Handle case where fill was sent on non-EVM chain, in which case the following call would fail
76
+ // or return something unexpected. We'd want to return undefined here.
77
+ const fillTransaction = await destinationChainProvider.getTransaction(updatedFill.transactionHash);
78
+ const destinationRelayer = fillTransaction?.from;
79
+ // Repayment chain is still an EVM chain, but the msg.sender is a bytes32 address, so the fill is invalid.
80
+ if (!isDefined(destinationRelayer) || !isValidEvmAddress(destinationRelayer)) {
81
+ return undefined;
82
+ }
83
+ // Otherwise, assume the relayer to be repaid is the msg.sender. We don't need to modify the repayment chain since
84
+ // the getTransaction() call would only succeed if the fill was sent on an EVM chain and therefore the msg.sender
85
+ // is a valid EVM address and the repayment chain is an EVM chain.
86
+ updatedFill.relayer = destinationRelayer;
87
+ }
88
+
89
+ // Case 2: TODO repayment chain is an SVM chain and repayment address is not a valid SVM address.
90
+ return updatedFill;
91
+ }
@@ -5,3 +5,4 @@ export * from "./speedProvider";
5
5
  export * from "./constants";
6
6
  export * from "./types";
7
7
  export * from "./utils";
8
+ export * as mocks from "./mockProvider";
@@ -0,0 +1,77 @@
1
+ import { BigNumber, providers } from "ethers";
2
+ import { Block, BlockTag, FeeData, TransactionResponse } from "@ethersproject/abstract-provider";
3
+ import { bnZero } from "../utils/BigNumberUtils";
4
+
5
+ /**
6
+ * @notice Class used to test GasPriceOracle which makes ethers provider calls to the following implemented
7
+ * methods.
8
+ */
9
+ export class MockedProvider extends providers.StaticJsonRpcProvider {
10
+ private transactions: { [hash: string]: TransactionResponse } = {};
11
+
12
+ constructor(
13
+ readonly stdLastBaseFeePerGas: BigNumber,
14
+ readonly stdMaxPriorityFeePerGas: BigNumber,
15
+ readonly defaultChainId = 1
16
+ ) {
17
+ super(undefined, defaultChainId);
18
+ }
19
+
20
+ getBlock(_blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>): Promise<Block> {
21
+ const mockBlock: Block = {
22
+ transactions: [],
23
+ hash: "0x",
24
+ parentHash: "0x",
25
+ number: 0,
26
+ nonce: "0",
27
+ difficulty: 0,
28
+ _difficulty: bnZero,
29
+ timestamp: 0,
30
+ gasLimit: bnZero,
31
+ gasUsed: bnZero,
32
+ baseFeePerGas: this.stdLastBaseFeePerGas,
33
+ miner: "0x",
34
+ extraData: "0x",
35
+ };
36
+ return Promise.resolve(mockBlock);
37
+ }
38
+
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ send(method: string, _params: Array<any>): Promise<any> {
41
+ switch (method) {
42
+ case "eth_maxPriorityFeePerGas":
43
+ return Promise.resolve(this.stdMaxPriorityFeePerGas);
44
+ default:
45
+ throw new Error(`MockedProvider#Unimplemented method: ${method}`);
46
+ }
47
+ }
48
+
49
+ getFeeData(): Promise<FeeData> {
50
+ return Promise.resolve({
51
+ lastBaseFeePerGas: this.stdLastBaseFeePerGas,
52
+ maxPriorityFeePerGas: this.stdMaxPriorityFeePerGas,
53
+ // Following fields unused in GasPrice oracle
54
+ maxFeePerGas: null,
55
+ gasPrice: null,
56
+ });
57
+ }
58
+
59
+ getTransaction(hash: string): Promise<TransactionResponse> {
60
+ return Promise.resolve(this.transactions[hash]);
61
+ }
62
+
63
+ getGasPrice(): Promise<BigNumber> {
64
+ return Promise.resolve(this.stdLastBaseFeePerGas.add(this.stdMaxPriorityFeePerGas));
65
+ }
66
+
67
+ getNetwork(): Promise<{ chainId: number; name: string }> {
68
+ return Promise.resolve({
69
+ name: "mocknetwork",
70
+ chainId: this.defaultChainId,
71
+ });
72
+ }
73
+
74
+ _setTransaction(hash: string, transaction: TransactionResponse) {
75
+ this.transactions[hash] = transaction;
76
+ }
77
+ }