@across-protocol/sdk 4.1.45 → 4.1.46-beta.0

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 (92) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +2 -0
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +41 -23
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +1 -10
  5. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +7 -7
  7. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +36 -47
  8. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  9. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  10. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
  11. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  12. package/dist/cjs/clients/HubPoolClient.d.ts +2 -6
  13. package/dist/cjs/clients/HubPoolClient.js +15 -37
  14. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  15. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
  16. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +5 -19
  17. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  18. package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +1 -3
  19. package/dist/cjs/clients/mocks/MockHubPoolClient.js +1 -19
  20. package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
  21. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -1
  22. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js +0 -5
  23. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  24. package/dist/cjs/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
  25. package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
  26. package/dist/cjs/utils/DepositUtils.d.ts +0 -1
  27. package/dist/cjs/utils/DepositUtils.js +1 -5
  28. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  29. package/dist/cjs/utils/TokenUtils.js +2 -0
  30. package/dist/cjs/utils/TokenUtils.js.map +1 -1
  31. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +2 -0
  32. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +45 -24
  33. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  34. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +1 -16
  35. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  36. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +7 -28
  37. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +50 -83
  38. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  39. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  40. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
  41. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  42. package/dist/esm/clients/HubPoolClient.d.ts +16 -13
  43. package/dist/esm/clients/HubPoolClient.js +34 -49
  44. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  45. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
  46. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +14 -28
  47. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  48. package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +1 -3
  49. package/dist/esm/clients/mocks/MockHubPoolClient.js +1 -19
  50. package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
  51. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -6
  52. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js +0 -10
  53. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  54. package/dist/esm/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
  55. package/dist/esm/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
  56. package/dist/esm/utils/DepositUtils.d.ts +0 -1
  57. package/dist/esm/utils/DepositUtils.js +1 -5
  58. package/dist/esm/utils/DepositUtils.js.map +1 -1
  59. package/dist/esm/utils/TokenUtils.js +2 -0
  60. package/dist/esm/utils/TokenUtils.js.map +1 -1
  61. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +2 -0
  62. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  63. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
  64. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +7 -28
  65. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  66. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  67. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
  68. package/dist/types/clients/HubPoolClient.d.ts +16 -13
  69. package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
  70. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
  71. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
  72. package/dist/types/clients/mocks/MockHubPoolClient.d.ts +1 -3
  73. package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
  74. package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -6
  75. package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts.map +1 -1
  76. package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
  77. package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts.map +1 -1
  78. package/dist/types/utils/DepositUtils.d.ts +0 -1
  79. package/dist/types/utils/DepositUtils.d.ts.map +1 -1
  80. package/dist/types/utils/TokenUtils.d.ts.map +1 -1
  81. package/package.json +1 -1
  82. package/src/clients/BundleDataClient/BundleDataClient.ts +58 -38
  83. package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +1 -36
  84. package/src/clients/BundleDataClient/utils/FillUtils.ts +71 -133
  85. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +2 -3
  86. package/src/clients/HubPoolClient.ts +38 -64
  87. package/src/clients/SpokePoolClient/SpokePoolClient.ts +16 -54
  88. package/src/clients/mocks/MockHubPoolClient.ts +2 -18
  89. package/src/relayFeeCalculator/chain-queries/baseQuery.ts +0 -10
  90. package/src/relayFeeCalculator/relayFeeCalculator.ts +0 -1
  91. package/src/utils/DepositUtils.ts +1 -6
  92. package/src/utils/TokenUtils.ts +2 -0
@@ -146,13 +146,6 @@ export function _buildPoolRebalanceRoot(
146
146
  const repaymentChainId = Number(_repaymentChainId);
147
147
  Object.entries(fillsForChain).forEach(
148
148
  ([l2TokenAddress, { realizedLpFees: totalRealizedLpFee, totalRefundAmount }]) => {
149
- // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
150
- // there are no relevant L1 running balances.
151
- if (
152
- !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(l2TokenAddress, repaymentChainId, mainnetBundleEndBlock)
153
- ) {
154
- return;
155
- }
156
149
  const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
157
150
  l2TokenAddress,
158
151
  repaymentChainId,
@@ -222,24 +215,7 @@ export function _buildPoolRebalanceRoot(
222
215
  Object.entries(bundleV3Deposits).forEach(([, depositsForChain]) => {
223
216
  Object.entries(depositsForChain).forEach(([, deposits]) => {
224
217
  deposits.forEach((deposit) => {
225
- // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
226
- // there are no relevant L1 running balances.
227
- if (
228
- !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
229
- deposit.inputToken,
230
- deposit.originChainId,
231
- mainnetBundleEndBlock
232
- )
233
- ) {
234
- return;
235
- }
236
- updateRunningBalanceForDeposit(
237
- runningBalances,
238
- clients.hubPoolClient,
239
- deposit,
240
- deposit.inputAmount.mul(-1),
241
- mainnetBundleEndBlock
242
- );
218
+ updateRunningBalanceForDeposit(runningBalances, clients.hubPoolClient, deposit, deposit.inputAmount.mul(-1));
243
219
  });
244
220
  });
245
221
  });
@@ -253,17 +229,6 @@ export function _buildPoolRebalanceRoot(
253
229
  const originChainId = Number(_originChainId);
254
230
  Object.entries(depositsForChain).forEach(([inputToken, deposits]) => {
255
231
  deposits.forEach((deposit) => {
256
- // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
257
- // there are no relevant L1 running balances.
258
- if (
259
- !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
260
- deposit.inputToken,
261
- deposit.originChainId,
262
- mainnetBundleEndBlock
263
- )
264
- ) {
265
- return;
266
- }
267
232
  const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
268
233
  inputToken,
269
234
  originChainId,
@@ -1,120 +1,124 @@
1
1
  import _ from "lodash";
2
- import assert from "assert";
3
2
  import { providers } from "ethers";
4
- import { DepositWithBlock, Fill, FillWithBlock } from "../../../interfaces";
5
- import { isSlowFill, isValidEvmAddress, isDefined, chainIsEvm } from "../../../utils";
3
+ import { Deposit, DepositWithBlock, Fill, FillWithBlock } from "../../../interfaces";
4
+ import { getBlockRangeForChain, isSlowFill, isValidEvmAddress, isDefined, chainIsEvm } from "../../../utils";
6
5
  import { HubPoolClient } from "../../HubPoolClient";
7
6
 
8
- /**
9
- * @notice FillRepaymentInformation is a fill with additional properties required to determine where it can
10
- * be repaid.
11
- */
12
- type FillRepaymentInformation = Fill & { fromLiteChain: boolean };
13
-
14
- /**
15
- * @notice Return repayment chain and repayment token for a fill, but does not verify if the returned
16
- * repayment information is valid for the desired repayment address.
17
- * @dev The passed in fill should be verified first via verifyFillRepayment().
18
- * @param fill The fill to get the repayment information for.
19
- * @return The chain to send the refund to and the token to use for the refund.
20
- */
21
7
  export function getRefundInformationFromFill(
22
- relayData: FillRepaymentInformation,
8
+ fill: Fill,
23
9
  hubPoolClient: HubPoolClient,
24
- bundleEndBlockForMainnet: number
10
+ blockRangesForChains: number[][],
11
+ chainIdListForBundleEvaluationBlockNumbers: number[],
12
+ fromLiteChain: boolean
25
13
  ): {
26
14
  chainToSendRefundTo: number;
27
15
  repaymentToken: string;
28
16
  } {
29
- const chainToSendRefundTo = _getRepaymentChainId(relayData, hubPoolClient, bundleEndBlockForMainnet);
30
- if (chainToSendRefundTo === relayData.originChainId) {
31
- return {
32
- chainToSendRefundTo,
33
- repaymentToken: relayData.inputToken,
34
- };
17
+ // Handle slow relay where repaymentChainId = 0. Slow relays always pay recipient on destination chain.
18
+ // So, save the slow fill under the destination chain, and save the fast fill under its repayment chain.
19
+ let chainToSendRefundTo = isSlowFill(fill) ? fill.destinationChainId : fill.repaymentChainId;
20
+ // If the fill is for a deposit originating from the lite chain, the repayment chain is the origin chain
21
+ // regardless of whether it is a slow or fast fill (we ignore slow fills but this is for posterity).
22
+ // @note fill.repaymentChainId should already be set to originChainId but reset it to be safe.
23
+ if (fromLiteChain) {
24
+ chainToSendRefundTo = fill.originChainId;
35
25
  }
36
26
 
37
- // Now figure out the equivalent L2 token for the repayment token. If the inputToken doesn't have a
38
- // PoolRebalanceRoute, then the repayment chain would have been the originChainId after the getRepaymentChainId()
39
- // call and we would have returned already, so the following call should always succeed.
27
+ // Save fill data and associate with repayment chain and L2 token refund should be denominated in.
28
+ const endBlockForMainnet = getBlockRangeForChain(
29
+ blockRangesForChains,
30
+ hubPoolClient.chainId,
31
+ chainIdListForBundleEvaluationBlockNumbers
32
+ )[1];
33
+
40
34
  const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
41
- relayData.inputToken,
42
- relayData.originChainId,
43
- bundleEndBlockForMainnet
35
+ fill.inputToken,
36
+ fill.originChainId,
37
+ endBlockForMainnet
44
38
  );
45
39
 
46
40
  const repaymentToken = hubPoolClient.getL2TokenForL1TokenAtBlock(
47
41
  l1TokenCounterpart,
48
42
  chainToSendRefundTo,
49
- bundleEndBlockForMainnet
43
+ endBlockForMainnet
50
44
  );
51
45
  return {
52
46
  chainToSendRefundTo,
53
47
  repaymentToken,
54
48
  };
55
49
  }
56
- /**
57
- * @notice Verifies that the fill can be repaid. If the repayment address is not
58
- * valid for the requested repayment chain, then this function will attempt to change the fill's repayment chain
59
- * to the destination chain and its repayment address to the msg.sender and if this is possible,
60
- * return the fill. Otherwise, return undefined.
61
- * @param _fill Fill with a requested repayment chain and address
62
- * @return Fill with the applied repayment chain (depends on the validity of the requested repayment address)
63
- * and applied repayment address, or undefined if the applied repayment address is not valid for the
64
- * applied repayment chain.
65
- */
50
+
51
+ export function getRepaymentChainId(fill: Fill, matchedDeposit: Deposit): number {
52
+ // Lite chain deposits force repayment on origin chain.
53
+ return matchedDeposit.fromLiteChain ? matchedDeposit.originChainId : fill.repaymentChainId;
54
+ }
55
+
56
+ export function forceDestinationRepayment(
57
+ repaymentChainId: number,
58
+ matchedDeposit: Deposit & { quoteBlockNumber: number },
59
+ hubPoolClient: HubPoolClient
60
+ ): boolean {
61
+ if (!matchedDeposit.fromLiteChain) {
62
+ try {
63
+ const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
64
+ matchedDeposit.inputToken,
65
+ matchedDeposit.originChainId,
66
+ matchedDeposit.quoteBlockNumber
67
+ );
68
+ hubPoolClient.getL2TokenForL1TokenAtBlock(l1TokenCounterpart, repaymentChainId, matchedDeposit.quoteBlockNumber);
69
+ // Repayment token could be found, this is a valid repayment chain.
70
+ return false;
71
+ } catch {
72
+ // Repayment token doesn't exist on repayment chain via PoolRebalanceRoutes, impossible to repay filler there.
73
+ return true;
74
+ }
75
+ } else {
76
+ return false;
77
+ }
78
+ }
79
+
80
+ // Verify that a fill sent to an EVM chain has a 20 byte address. If the fill does not, then attempt
81
+ // to repay the `msg.sender` of the relay transaction. Otherwise, return undefined.
66
82
  export async function verifyFillRepayment(
67
83
  _fill: FillWithBlock,
68
84
  destinationChainProvider: providers.Provider,
69
85
  matchedDeposit: DepositWithBlock,
70
- hubPoolClient: HubPoolClient,
71
- bundleEndBlockForMainnet: number
86
+ hubPoolClient: HubPoolClient
72
87
  ): Promise<FillWithBlock | undefined> {
73
- const fill = {
74
- ..._.cloneDeep(_fill),
75
- fromLiteChain: matchedDeposit.fromLiteChain,
76
- };
88
+ const fill = _.cloneDeep(_fill);
77
89
 
78
90
  // Slow fills don't result in repayments so they're always valid.
79
91
  if (isSlowFill(fill)) {
80
92
  return fill;
81
93
  }
82
94
 
83
- let repaymentChainId = _getRepaymentChainId(fill, hubPoolClient, bundleEndBlockForMainnet);
95
+ let repaymentChainId = getRepaymentChainId(fill, matchedDeposit);
96
+
97
+ // If repayment chain doesn't have a Pool Rebalance Route for the input token, then change the repayment
98
+ // chain to the destination chain.
99
+ if (forceDestinationRepayment(repaymentChainId, matchedDeposit, hubPoolClient)) {
100
+ repaymentChainId = fill.destinationChainId;
101
+ }
84
102
 
85
- // Repayments will always go to the fill.relayer address so check if its a valid EVM address. If its not, attempt
86
- // to change it to the msg.sender of the FilledRelay.
87
- if (_repaymentAddressNeedsToBeOverwritten(fill)) {
103
+ if (!isValidEvmAddress(fill.relayer)) {
88
104
  // TODO: Handle case where fill was sent on non-EVM chain, in which case the following call would fail
89
105
  // or return something unexpected. We'd want to return undefined here.
90
-
91
- // @todo: If chainIsEvm:
92
106
  const fillTransaction = await destinationChainProvider.getTransaction(fill.transactionHash);
93
107
  const destinationRelayer = fillTransaction?.from;
94
108
  // Repayment chain is still an EVM chain, but the msg.sender is a bytes32 address, so the fill is invalid.
95
109
  if (!isDefined(destinationRelayer) || !isValidEvmAddress(destinationRelayer)) {
96
110
  return undefined;
97
111
  }
98
- // If we can switch the repayment chain to the destination chain, then do so. We should only switch if the
99
- // destination chain has a valid repayment token that is equivalent to the deposited input token. This would
100
- // also be the same mapping as the repayment token on the repayment chain.
101
- if (
102
- !matchedDeposit.fromLiteChain &&
103
- hubPoolClient.areTokensEquivalent(fill.inputToken, fill.originChainId, fill.outputToken, fill.destinationChainId)
104
- ) {
112
+ if (!matchedDeposit.fromLiteChain) {
105
113
  repaymentChainId = fill.destinationChainId;
106
- }
107
- // If we can't switch the chain, then we need to verify that the msg.sender is a valid address on the repayment chain.
108
- // Because we already checked that the `destinationRelayer` was a valid EVM address above, we only need to check
109
- // that the repayment chain is an EVM chain.
110
- else {
114
+ } else {
115
+ // We can't switch repayment chain for a lite chain deposit so just check whether the repayment chain,
116
+ // which should be the origin chain, is an EVM chain.
111
117
  if (!chainIsEvm(repaymentChainId)) {
112
118
  return undefined;
113
119
  }
114
120
  }
115
121
  fill.relayer = destinationRelayer;
116
-
117
- // @todo: If chainIsSvm:
118
122
  }
119
123
 
120
124
  // Repayment address is now valid and repayment chain is either origin chain for lite chain or the destination
@@ -122,69 +126,3 @@ export async function verifyFillRepayment(
122
126
  fill.repaymentChainId = repaymentChainId;
123
127
  return fill;
124
128
  }
125
-
126
- function _getRepaymentChainId(
127
- relayData: FillRepaymentInformation,
128
- hubPoolClient: HubPoolClient,
129
- bundleEndBlockForMainnet: number
130
- ): number {
131
- if (relayData.fromLiteChain) {
132
- assert(!isSlowFill(relayData), "getRepaymentChainId: fromLiteChain and slow fill are mutually exclusive");
133
- return relayData.originChainId;
134
- }
135
-
136
- // Handle slow relay where FilledRelay.repaymentChainId = 0, as hardcoded in the SpokePool contract.
137
- // Slow relays always pay recipient on destination chain.
138
- if (isSlowFill(relayData)) {
139
- return relayData.destinationChainId;
140
- }
141
-
142
- // Repayment chain is valid if the input token and repayment chain are mapped to the same PoolRebalanceRoute.
143
- const repaymentTokenIsValid = _repaymentChainTokenIsValid(relayData, hubPoolClient, bundleEndBlockForMainnet);
144
- if (repaymentTokenIsValid) {
145
- return relayData.repaymentChainId;
146
- }
147
-
148
- // If repayment chain is not valid, default to origin chain since we always know the input token can be refunded.
149
- return relayData.originChainId;
150
- }
151
-
152
- function _repaymentChainTokenIsValid(
153
- relayData: FillRepaymentInformation,
154
- hubPoolClient: HubPoolClient,
155
- bundleEndBlockForMainnet: number
156
- ): boolean {
157
- if (
158
- !hubPoolClient.l2TokenHasPoolRebalanceRoute(relayData.inputToken, relayData.originChainId, bundleEndBlockForMainnet)
159
- ) {
160
- return false;
161
- }
162
- const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
163
- relayData.inputToken,
164
- relayData.originChainId,
165
- bundleEndBlockForMainnet
166
- );
167
- if (
168
- !hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
169
- l1TokenCounterpart,
170
- relayData.repaymentChainId,
171
- bundleEndBlockForMainnet
172
- )
173
- ) {
174
- return false;
175
- }
176
- return true;
177
- }
178
-
179
- function _repaymentAddressNeedsToBeOverwritten(fill: Fill): boolean {
180
- // Slow fills don't result in repayments so they're always valid.
181
- if (isSlowFill(fill)) {
182
- return false;
183
- }
184
-
185
- // @todo add Solana logic here:
186
- // - i.e. If chainIsSvm && !isValidSvmAddress(fill.relayer) then return false
187
- // If chainIsEvm && !isValidEvmAddress(fill.relayer) then return false
188
- // If chainIsEvm && isValidEvmAddress(fill.relayer) then return true
189
- return !isValidEvmAddress(fill.relayer);
190
- }
@@ -163,13 +163,12 @@ export function updateRunningBalanceForDeposit(
163
163
  runningBalances: RunningBalances,
164
164
  hubPoolClient: HubPoolClient,
165
165
  deposit: V3DepositWithBlock,
166
- updateAmount: BigNumber,
167
- mainnetBundleEndBlock: number
166
+ updateAmount: BigNumber
168
167
  ): void {
169
168
  const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
170
169
  deposit.inputToken,
171
170
  deposit.originChainId,
172
- mainnetBundleEndBlock
171
+ deposit.quoteBlockNumber
173
172
  );
174
173
  updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart, updateAmount);
175
174
  }
@@ -43,7 +43,6 @@ import {
43
43
  toBN,
44
44
  getTokenInfo,
45
45
  getUsdcSymbol,
46
- getL1TokenInfo,
47
46
  compareAddressesSimple,
48
47
  } from "../utils";
49
48
  import { AcrossConfigStoreClient as ConfigStoreClient } from "./AcrossConfigStoreClient/AcrossConfigStoreClient";
@@ -231,39 +230,38 @@ export class HubPoolClient extends BaseAbstractClient {
231
230
  return sortEventsDescending(l2Tokens)[0].l1Token;
232
231
  }
233
232
 
234
- protected getL1TokenForDeposit(
235
- deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">
236
- ): string {
233
+ /**
234
+ * Returns the L1 token that should be used for an L2 Bridge event. This function is
235
+ * designed to be used by the caller to associate the L2 token with its mapped L1 token
236
+ * at the HubPool equivalent block number of the L2 event.
237
+ * @param deposit Deposit event
238
+ * @param returns string L1 token counterpart for Deposit
239
+ */
240
+ getL1TokenForDeposit(deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">): string {
237
241
  // L1-->L2 token mappings are set via PoolRebalanceRoutes which occur on mainnet,
238
242
  // so we use the latest token mapping. This way if a very old deposit is filled, the relayer can use the
239
243
  // latest L2 token mapping to find the L1 token counterpart.
240
244
  return this.getL1TokenForL2TokenAtBlock(deposit.inputToken, deposit.originChainId, deposit.quoteBlockNumber);
241
245
  }
242
246
 
243
- l2TokenEnabledForL1Token(l1Token: string, destinationChainId: number): boolean {
244
- return this.l1TokensToDestinationTokens?.[l1Token]?.[destinationChainId] != undefined;
245
- }
246
-
247
- l2TokenEnabledForL1TokenAtBlock(l1Token: string, destinationChainId: number, hubBlockNumber: number): boolean {
248
- // Find the last mapping published before the target block.
249
- const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
250
- this.l1TokensToDestinationTokensWithBlock?.[l1Token]?.[destinationChainId] ?? []
251
- ).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= hubBlockNumber);
252
- return l2Token !== undefined;
247
+ /**
248
+ * Returns the L2 token that should be used as a counterpart to a deposit event. For example, the caller
249
+ * might want to know what the refund token will be on l2ChainId for the deposit event.
250
+ * @param l2ChainId Chain where caller wants to get L2 token counterpart for
251
+ * @param event Deposit event
252
+ * @returns string L2 token counterpart on l2ChainId
253
+ */
254
+ getL2TokenForDeposit(
255
+ deposit: Pick<DepositWithBlock, "originChainId" | "destinationChainId" | "inputToken" | "quoteBlockNumber">,
256
+ l2ChainId = deposit.destinationChainId
257
+ ): string {
258
+ const l1Token = this.getL1TokenForDeposit(deposit);
259
+ // Use the latest hub block number to find the L2 token counterpart.
260
+ return this.getL2TokenForL1TokenAtBlock(l1Token, l2ChainId, deposit.quoteBlockNumber);
253
261
  }
254
262
 
255
- l2TokenHasPoolRebalanceRoute(l2Token: string, l2ChainId: number, hubPoolBlock = this.latestBlockSearched): boolean {
256
- return Object.values(this.l1TokensToDestinationTokensWithBlock).some((destinationTokenMapping) => {
257
- return Object.entries(destinationTokenMapping).some(([_l2ChainId, setPoolRebalanceRouteEvents]) => {
258
- return setPoolRebalanceRouteEvents.some((e) => {
259
- return (
260
- e.blockNumber <= hubPoolBlock &&
261
- compareAddressesSimple(e.l2Token, l2Token) &&
262
- Number(_l2ChainId) === l2ChainId
263
- );
264
- });
265
- });
266
- });
263
+ l2TokenEnabledForL1Token(l1Token: string, destinationChainId: number): boolean {
264
+ return this.l1TokensToDestinationTokens?.[l1Token]?.[destinationChainId] != undefined;
267
265
  }
268
266
 
269
267
  /**
@@ -282,17 +280,6 @@ export class HubPoolClient extends BaseAbstractClient {
282
280
  return tokenInfo;
283
281
  }
284
282
 
285
- /**
286
- * @dev If tokenAddress + chain do not exist in TOKEN_SYMBOLS_MAP then this will throw.
287
- * @dev if the token matched in TOKEN_SYMBOLS_MAP does not have an L1 token address then this will throw.
288
- * @param tokenAddress Token address on `chain`
289
- * @param chain Chain where the `tokenAddress` exists in TOKEN_SYMBOLS_MAP.
290
- * @returns Token info for the given token address on the Hub chain including symbol and decimal and L1 address.
291
- */
292
- getL1TokenInfoForAddress(tokenAddress: string, chain: number): L1Token {
293
- return getL1TokenInfo(tokenAddress, chain);
294
- }
295
-
296
283
  /**
297
284
  * Resolve a given timestamp to a block number on the HubPool chain.
298
285
  * @param timestamp A single timestamp to be resolved to a block number on the HubPool chain.
@@ -512,17 +499,6 @@ export class HubPoolClient extends BaseAbstractClient {
512
499
  return this.getTokenInfoForL1Token(l1TokenCounterpart);
513
500
  }
514
501
 
515
- getTokenInfoForDeposit(deposit: Pick<Deposit, "inputToken" | "originChainId">): L1Token | undefined {
516
- return this.getTokenInfoForL1Token(
517
- this.getL1TokenForL2TokenAtBlock(deposit.inputToken, deposit.originChainId, this.latestBlockSearched)
518
- );
519
- }
520
-
521
- getTokenInfo(chainId: number | string, tokenAddress: string): L1Token | undefined {
522
- const deposit = { originChainId: parseInt(chainId.toString()), inputToken: tokenAddress };
523
- return this.getTokenInfoForDeposit(deposit);
524
- }
525
-
526
502
  areTokensEquivalent(
527
503
  tokenA: string,
528
504
  chainIdA: number,
@@ -530,23 +506,21 @@ export class HubPoolClient extends BaseAbstractClient {
530
506
  chainIdB: number,
531
507
  hubPoolBlock = this.latestBlockSearched
532
508
  ): boolean {
533
- if (
534
- !this.l2TokenHasPoolRebalanceRoute(tokenA, chainIdA, hubPoolBlock) ||
535
- !this.l2TokenHasPoolRebalanceRoute(tokenB, chainIdB, hubPoolBlock)
536
- ) {
537
- return false;
538
- }
539
- // Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
540
- const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
541
- const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
542
- if (l1TokenA !== l1TokenB) {
543
- return false;
544
- }
509
+ try {
510
+ // Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
511
+ const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
512
+ const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
513
+ if (l1TokenA !== l1TokenB) {
514
+ return false;
515
+ }
545
516
 
546
- // Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
547
- const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
548
- const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
549
- return tokenA === _tokenA && tokenB === _tokenB;
517
+ // Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
518
+ const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
519
+ const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
520
+ return tokenA === _tokenA && tokenB === _tokenB;
521
+ } catch {
522
+ return false; // One or both input tokens were not recognised.
523
+ }
550
524
  }
551
525
 
552
526
  getSpokeActivationBlockForChain(chainId: number): number {
@@ -17,7 +17,6 @@ import {
17
17
  isZeroAddress,
18
18
  toAddress,
19
19
  validateFillForDeposit,
20
- chainIsEvm,
21
20
  } from "../../utils";
22
21
  import {
23
22
  duplicateEvent,
@@ -42,7 +41,7 @@ import {
42
41
  } from "../../interfaces";
43
42
  import { BaseAbstractClient, UpdateFailureReason } from "../BaseAbstractClient";
44
43
  import { AcrossConfigStoreClient } from "../AcrossConfigStoreClient";
45
- import { getRefundInformationFromFill } from "../BundleDataClient";
44
+ import { getRepaymentChainId, forceDestinationRepayment } from "../BundleDataClient";
46
45
  import { HubPoolClient } from "../HubPoolClient";
47
46
 
48
47
  export type SpokePoolUpdateSuccess = {
@@ -366,25 +365,22 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
366
365
  fill: FillWithBlock
367
366
  ) => {
368
367
  if (validateFillForDeposit(fill, deposit).valid) {
369
- const fillRepaymentData = {
370
- ...fill,
371
- fromLiteChain: deposit.fromLiteChain,
372
- };
373
- const { chainToSendRefundTo: repaymentChainId } = getRefundInformationFromFill(
374
- fillRepaymentData,
375
- this.hubPoolClient!,
376
- this.hubPoolClient!.latestBlockSearched
377
- );
378
- // In order to keep this function sync, we can't call verifyFillRepayment so we'll log any fills where
379
- // the filler-specified repayment chain and repayment address is not a valid repayment upon
380
- // first glance. In other words, the repayment address is not a valid EVM address or the repayment chain
381
- // is not a valid EVM chain. In the case where the repayment address is not a valid EVM address, the dataworker
382
- // might be able to overwrite the repayment address to the msg.sender on the fill txn, but to keep this
383
- // functioon synchronous, we can't make that decision now. So this function might log some false positives.
368
+ const repaymentChainId = getRepaymentChainId(fill, deposit);
369
+ // In order to keep this function sync, we can't call verifyFillRepayment so we'll log any fills that
370
+ // we'll have to overwrite repayment information for. This includes fills for lite chains where the
371
+ // repayment address is invalid, and fills for non-lite chains where the repayment address is valid or
372
+ // the repayment chain is invalid. We don't check that the origin chain is a valid EVM chain for
373
+ // lite chain deposits yet because only EVM chains are supported on Across...for now. This means
374
+ // this logic will have to be revisited when we add SVM to log properly.
384
375
  if (
385
376
  this.hubPoolClient &&
386
377
  !isSlowFill(fill) &&
387
- (!chainIsEvm(repaymentChainId) || !isValidEvmAddress(fill.relayer))
378
+ (!isValidEvmAddress(fill.relayer) ||
379
+ forceDestinationRepayment(
380
+ repaymentChainId,
381
+ { ...deposit, quoteBlockNumber: this.hubPoolClient!.latestBlockSearched },
382
+ this.hubPoolClient
383
+ ))
388
384
  ) {
389
385
  groupedFills.unrepayableFills.push(fill);
390
386
  }
@@ -454,29 +450,6 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
454
450
  return `${event.depositId.toString()}-${event.originChainId}`;
455
451
  }
456
452
 
457
- protected canResolveZeroAddressOutputToken(deposit: DepositWithBlock): boolean {
458
- if (
459
- !this.hubPoolClient?.l2TokenHasPoolRebalanceRoute(
460
- deposit.inputToken,
461
- deposit.originChainId,
462
- deposit.quoteBlockNumber
463
- )
464
- ) {
465
- return false;
466
- } else {
467
- const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
468
- deposit.inputToken,
469
- deposit.originChainId,
470
- deposit.quoteBlockNumber
471
- );
472
- return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
473
- l1Token,
474
- deposit.destinationChainId,
475
- deposit.quoteBlockNumber
476
- );
477
- }
478
- }
479
-
480
453
  /**
481
454
  * A wrapper over the `_update` method that handles errors and logs. This method additionally calls into the
482
455
  * HubPoolClient to update the state of this client with data from the HubPool contract.
@@ -736,19 +709,8 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
736
709
  * @returns The destination token.
737
710
  */
738
711
  protected getDestinationTokenForDeposit(deposit: DepositWithBlock): string {
739
- if (!this.canResolveZeroAddressOutputToken(deposit)) {
740
- return ZERO_ADDRESS;
741
- }
742
- // L1 token should be resolved if we get here:
743
- const l1Token = this.hubPoolClient!.getL1TokenForL2TokenAtBlock(
744
- deposit.inputToken,
745
- deposit.originChainId,
746
- deposit.quoteBlockNumber
747
- )!;
748
- return (
749
- this.hubPoolClient!.getL2TokenForL1TokenAtBlock(l1Token, deposit.destinationChainId, deposit.quoteBlockNumber) ??
750
- ZERO_ADDRESS
751
- );
712
+ // If there is no rate model client return address(0).
713
+ return this.hubPoolClient?.getL2TokenForDeposit(deposit) ?? ZERO_ADDRESS;
752
714
  }
753
715
 
754
716
  /**
@@ -24,7 +24,7 @@ export class MockHubPoolClient extends HubPoolClient {
24
24
 
25
25
  private l1TokensMock: L1Token[] = []; // L1Tokens and their associated info.
26
26
  private tokenInfoToReturn: L1Token = { address: "", decimals: 0, symbol: "" };
27
-
27
+
28
28
  private spokePoolTokens: { [l1Token: string]: { [chainId: number]: string } } = {};
29
29
 
30
30
  private eventManager: EventManager;
@@ -91,7 +91,7 @@ export class MockHubPoolClient extends HubPoolClient {
91
91
  return this.l1TokensMock;
92
92
  }
93
93
 
94
- getTokenInfoForDeposit() {
94
+ getTokenInfoForAddress() {
95
95
  return this.tokenInfoToReturn;
96
96
  }
97
97
 
@@ -100,22 +100,6 @@ export class MockHubPoolClient extends HubPoolClient {
100
100
  this.spokePoolTokens[l1Token][chainId] = l2Token;
101
101
  }
102
102
 
103
- l2TokenEnabledForL1TokenAtBlock(l1Token: string, destinationChainId: number, hubBlockNumber: number): boolean {
104
- if (this.spokePoolTokens[l1Token]?.[destinationChainId]) {
105
- return true;
106
- } else {
107
- return super.l2TokenEnabledForL1TokenAtBlock(l1Token, destinationChainId, hubBlockNumber);
108
- }
109
- }
110
- l2TokenHasPoolRebalanceRoute(l2Token: string, chainId: number, hubPoolBlock: number): boolean {
111
- const l1Token = Object.keys(this.spokePoolTokens).find(
112
- (l1Token) => this.spokePoolTokens[l1Token]?.[chainId] === l2Token
113
- );
114
- if (!l1Token) {
115
- return super.l2TokenHasPoolRebalanceRoute(l2Token, chainId, hubPoolBlock);
116
- } else return true;
117
- }
118
-
119
103
  deleteTokenMapping(l1Token: string, chainId: number) {
120
104
  delete this.spokePoolTokens[l1Token]?.[chainId];
121
105
  }
@@ -252,14 +252,4 @@ export class QueryBase implements QueryInterface {
252
252
  );
253
253
  return price;
254
254
  }
255
-
256
- /**
257
- * Resolves the number of decimal places a token can have
258
- * @param tokenSymbol A valid Across-Enabled Token ID
259
- * @returns The number of decimals of precision for the corresponding tokenSymbol
260
- */
261
- getTokenDecimals(tokenSymbol: string): number {
262
- if (!this.symbolMapping[tokenSymbol]) throw new Error(`${tokenSymbol} does not exist in mapping`);
263
- return this.symbolMapping[tokenSymbol].decimals;
264
- }
265
255
  }
@@ -34,7 +34,6 @@ export interface QueryInterface {
34
34
  }>
35
35
  ) => Promise<TransactionCostEstimate>;
36
36
  getTokenPrice: (tokenSymbol: string) => Promise<number>;
37
- getTokenDecimals: (tokenSymbol: string) => number;
38
37
  }
39
38
 
40
39
  export const expectedCapitalCostsKeys = ["lowerBound", "upperBound", "cutoff", "decimals"];