@across-protocol/sdk 4.3.46 → 4.3.47
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/arch/evm/SpokeUtils.js +30 -28
- package/dist/cjs/arch/evm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/SpokeUtils.js +1 -1
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +4 -6
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +0 -5
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +0 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
- package/dist/cjs/clients/HubPoolClient.d.ts +9 -3
- package/dist/cjs/clients/HubPoolClient.js +81 -56
- package/dist/cjs/clients/HubPoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js +7 -5
- package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +13 -16
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +2 -2
- package/dist/cjs/clients/mocks/MockHubPoolClient.js +1 -1
- package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
- package/dist/cjs/constants.d.ts +3 -0
- package/dist/cjs/constants.js +10 -2
- package/dist/cjs/constants.js.map +1 -1
- package/dist/esm/arch/evm/SpokeUtils.js +33 -29
- package/dist/esm/arch/evm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/SpokeUtils.js +1 -1
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +5 -7
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +1 -6
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +0 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
- package/dist/esm/clients/HubPoolClient.d.ts +9 -3
- package/dist/esm/clients/HubPoolClient.js +87 -60
- package/dist/esm/clients/HubPoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js +8 -6
- package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +13 -18
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +2 -2
- package/dist/esm/clients/mocks/MockHubPoolClient.js +1 -1
- package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
- package/dist/esm/constants.d.ts +3 -0
- package/dist/esm/constants.js +12 -1
- package/dist/esm/constants.js.map +1 -1
- package/dist/types/arch/evm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
- package/dist/types/clients/HubPoolClient.d.ts +9 -3
- package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient/EVMSpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/mocks/MockHubPoolClient.d.ts +2 -2
- package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
- package/dist/types/constants.d.ts +3 -0
- package/dist/types/constants.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/arch/evm/SpokeUtils.ts +16 -9
- package/src/arch/svm/SpokeUtils.ts +12 -7
- package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +20 -14
- package/src/clients/BundleDataClient/utils/FillUtils.ts +1 -7
- package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +0 -2
- package/src/clients/HubPoolClient.ts +79 -50
- package/src/clients/SpokePoolClient/EVMSpokePoolClient.ts +22 -8
- package/src/clients/SpokePoolClient/SpokePoolClient.ts +31 -39
- package/src/clients/mocks/MockHubPoolClient.ts +3 -3
- package/src/constants.ts +12 -0
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
count2DDictionaryValues,
|
|
19
19
|
count3DDictionaryValues,
|
|
20
20
|
toAddressType,
|
|
21
|
-
isDefined,
|
|
22
21
|
} from "../../../utils";
|
|
23
22
|
import {
|
|
24
23
|
addLastRunningBalance,
|
|
@@ -154,15 +153,21 @@ export function _buildPoolRebalanceRoot(
|
|
|
154
153
|
([l2TokenAddress, { realizedLpFees: totalRealizedLpFee, totalRefundAmount }]) => {
|
|
155
154
|
// If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
|
|
156
155
|
// there are no relevant L1 running balances.
|
|
156
|
+
if (
|
|
157
|
+
!clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
|
|
158
|
+
toAddressType(l2TokenAddress, repaymentChainId),
|
|
159
|
+
repaymentChainId,
|
|
160
|
+
mainnetBundleEndBlock
|
|
161
|
+
)
|
|
162
|
+
) {
|
|
163
|
+
chainWithRefundsOnly.add(repaymentChainId);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
157
166
|
const l1Token = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
|
|
158
167
|
toAddressType(l2TokenAddress, repaymentChainId),
|
|
159
168
|
repaymentChainId,
|
|
160
169
|
mainnetBundleEndBlock
|
|
161
170
|
);
|
|
162
|
-
if (!l1Token) {
|
|
163
|
-
chainWithRefundsOnly.add(repaymentChainId);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
171
|
const l1TokenAddr = l1Token.toNative();
|
|
167
172
|
assert(l1Token.isEVM(), `Expected an EVM address: ${l1TokenAddr}`);
|
|
168
173
|
|
|
@@ -188,9 +193,6 @@ export function _buildPoolRebalanceRoot(
|
|
|
188
193
|
destinationChainId,
|
|
189
194
|
mainnetBundleEndBlock
|
|
190
195
|
);
|
|
191
|
-
|
|
192
|
-
assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
|
|
193
|
-
|
|
194
196
|
const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
|
|
195
197
|
updateRunningBalance(
|
|
196
198
|
runningBalances,
|
|
@@ -220,8 +222,6 @@ export function _buildPoolRebalanceRoot(
|
|
|
220
222
|
destinationChainId,
|
|
221
223
|
mainnetBundleEndBlock
|
|
222
224
|
);
|
|
223
|
-
assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
|
|
224
|
-
|
|
225
225
|
const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
|
|
226
226
|
updateRunningBalance(
|
|
227
227
|
runningBalances,
|
|
@@ -277,15 +277,21 @@ export function _buildPoolRebalanceRoot(
|
|
|
277
277
|
deposits.forEach((deposit) => {
|
|
278
278
|
// If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
|
|
279
279
|
// there are no relevant L1 running balances.
|
|
280
|
+
if (
|
|
281
|
+
!clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
|
|
282
|
+
deposit.inputToken,
|
|
283
|
+
deposit.originChainId,
|
|
284
|
+
mainnetBundleEndBlock
|
|
285
|
+
)
|
|
286
|
+
) {
|
|
287
|
+
chainWithRefundsOnly.add(deposit.originChainId);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
280
290
|
const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
|
|
281
291
|
toAddressType(inputToken, originChainId),
|
|
282
292
|
originChainId,
|
|
283
293
|
mainnetBundleEndBlock
|
|
284
294
|
);
|
|
285
|
-
if (!l1TokenCounterpart) {
|
|
286
|
-
chainWithRefundsOnly.add(deposit.originChainId);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
295
|
updateRunningBalance(runningBalances, originChainId, l1TokenCounterpart.toEvmAddress(), deposit.inputAmount);
|
|
290
296
|
});
|
|
291
297
|
});
|
|
@@ -37,21 +37,18 @@ export function getRefundInformationFromFill(
|
|
|
37
37
|
|
|
38
38
|
// Now figure out the equivalent L2 token for the repayment token. If the inputToken doesn't have a
|
|
39
39
|
// PoolRebalanceRoute, then the repayment chain would have been the originChainId after the getRepaymentChainId()
|
|
40
|
-
// call and we would have returned already, so the following call should always
|
|
40
|
+
// call and we would have returned already, so the following call should always succeed.
|
|
41
41
|
const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
|
|
42
42
|
relayData.inputToken,
|
|
43
43
|
relayData.originChainId,
|
|
44
44
|
bundleEndBlockForMainnet
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
-
assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
|
|
48
|
-
|
|
49
47
|
const repaymentToken = hubPoolClient.getL2TokenForL1TokenAtBlock(
|
|
50
48
|
l1TokenCounterpart,
|
|
51
49
|
chainToSendRefundTo,
|
|
52
50
|
bundleEndBlockForMainnet
|
|
53
51
|
);
|
|
54
|
-
assert(isDefined(repaymentToken), "getRefundInformationFromFill: repaymentToken is undefined");
|
|
55
52
|
|
|
56
53
|
return {
|
|
57
54
|
chainToSendRefundTo,
|
|
@@ -186,9 +183,6 @@ function _repaymentChainTokenIsValid(
|
|
|
186
183
|
relayData.originChainId,
|
|
187
184
|
bundleEndBlockForMainnet
|
|
188
185
|
);
|
|
189
|
-
if (!l1TokenCounterpart) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
186
|
if (
|
|
193
187
|
!hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
|
|
194
188
|
l1TokenCounterpart,
|
|
@@ -202,8 +202,6 @@ export function updateRunningBalanceForDeposit(
|
|
|
202
202
|
deposit.originChainId,
|
|
203
203
|
mainnetBundleEndBlock
|
|
204
204
|
);
|
|
205
|
-
assert(isDefined(l1TokenCounterpart), "updateRunningBalanceForDeposit: l1TokenCounterpart is undefined");
|
|
206
|
-
|
|
207
205
|
updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart.toEvmAddress(), updateAmount);
|
|
208
206
|
}
|
|
209
207
|
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
fetchTokenInfo,
|
|
35
35
|
getCachedBlockForTimestamp,
|
|
36
36
|
getCurrentTime,
|
|
37
|
+
getNetworkName,
|
|
37
38
|
isDefined,
|
|
38
39
|
mapAsync,
|
|
39
40
|
paginatedEventQuery,
|
|
@@ -74,11 +75,17 @@ type HubPoolEvent =
|
|
|
74
75
|
| "RootBundleExecuted"
|
|
75
76
|
| "CrossChainContractsSet";
|
|
76
77
|
|
|
78
|
+
type L1TokensToDestinationTokens = {
|
|
79
|
+
[l1Token: string]: { [destinationChainId: number]: Address };
|
|
80
|
+
};
|
|
81
|
+
|
|
77
82
|
export type LpFeeRequest = Pick<Deposit, "originChainId" | "inputToken" | "inputAmount" | "quoteTimestamp"> & {
|
|
78
83
|
paymentChainId?: number;
|
|
79
84
|
};
|
|
80
85
|
|
|
81
86
|
export class HubPoolClient extends BaseAbstractClient {
|
|
87
|
+
// L1Token -> destinationChainId -> destinationToken
|
|
88
|
+
protected l1TokensToDestinationTokens: L1TokensToDestinationTokens = {};
|
|
82
89
|
protected l1Tokens: L1TokenInfo[] = []; // L1Tokens and their associated info.
|
|
83
90
|
// @dev `token` here is a 20-byte hex sting
|
|
84
91
|
protected lpTokens: { [token: string]: LpToken } = {};
|
|
@@ -185,16 +192,24 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
185
192
|
l1Token: EvmAddress,
|
|
186
193
|
destinationChainId: number,
|
|
187
194
|
latestHubBlock = Number.MAX_SAFE_INTEGER
|
|
188
|
-
): Address
|
|
195
|
+
): Address {
|
|
189
196
|
if (!this.l1TokensToDestinationTokensWithBlock?.[l1Token.toEvmAddress()]?.[destinationChainId]) {
|
|
190
|
-
|
|
197
|
+
const chain = getNetworkName(destinationChainId);
|
|
198
|
+
const { symbol } = this.l1Tokens.find(({ address }) => address.eq(l1Token)) ?? { symbol: l1Token.toString() };
|
|
199
|
+
throw new Error(`Could not find SpokePool mapping for ${symbol} on ${chain} and L1 token ${l1Token}`);
|
|
191
200
|
}
|
|
192
201
|
// Find the last mapping published before the target block.
|
|
193
|
-
const l2Token: DestinationTokenWithBlock | undefined =
|
|
194
|
-
l1Token.toEvmAddress()
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
|
|
203
|
+
this.l1TokensToDestinationTokensWithBlock[l1Token.toEvmAddress()][destinationChainId]
|
|
204
|
+
).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= latestHubBlock);
|
|
205
|
+
if (!l2Token) {
|
|
206
|
+
const chain = getNetworkName(destinationChainId);
|
|
207
|
+
const { symbol } = this.l1Tokens.find(({ address }) => address.eq(l1Token)) ?? { symbol: l1Token.toString() };
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Could not find SpokePool mapping for ${symbol} on ${chain} at or before HubPool block ${latestHubBlock}!`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return l2Token.l2Token;
|
|
198
213
|
}
|
|
199
214
|
|
|
200
215
|
// Returns the latest L1 token to use for an L2 token as of the input hub block.
|
|
@@ -202,27 +217,32 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
202
217
|
l2Token: Address,
|
|
203
218
|
destinationChainId: number,
|
|
204
219
|
latestHubBlock = Number.MAX_SAFE_INTEGER
|
|
205
|
-
): EvmAddress
|
|
206
|
-
const l2Tokens = Object.keys(this.l1TokensToDestinationTokensWithBlock)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
(
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
): EvmAddress {
|
|
221
|
+
const l2Tokens = Object.keys(this.l1TokensToDestinationTokensWithBlock)
|
|
222
|
+
.filter((l1Token) => this.l2TokenEnabledForL1Token(EvmAddress.from(l1Token), destinationChainId))
|
|
223
|
+
.map((l1Token) => {
|
|
224
|
+
// Return all matching L2 token mappings that are equal to or earlier than the target block.
|
|
225
|
+
// @dev Since tokens on L2s (like Solana) can have 32 byte addresses, filter on the lower 20 bytes of the token only.
|
|
226
|
+
return this.l1TokensToDestinationTokensWithBlock[l1Token][destinationChainId].filter(
|
|
227
|
+
(dstTokenWithBlock) =>
|
|
228
|
+
dstTokenWithBlock.l2Token.truncateToBytes20() === l2Token.truncateToBytes20() &&
|
|
229
|
+
dstTokenWithBlock.blockNumber <= latestHubBlock
|
|
230
|
+
);
|
|
231
|
+
})
|
|
232
|
+
.flat();
|
|
233
|
+
if (l2Tokens.length === 0) {
|
|
234
|
+
const chain = getNetworkName(destinationChainId);
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Could not find HubPool mapping for ${l2Token} on ${chain} at or before HubPool block ${latestHubBlock}!`
|
|
213
237
|
);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
: [];
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
return l2Tokens.length === 0 ? undefined : sortEventsDescending(l2Tokens)[0].l1Token;
|
|
238
|
+
}
|
|
239
|
+
// Find the last mapping published before the target block.
|
|
240
|
+
return sortEventsDescending(l2Tokens)[0].l1Token;
|
|
221
241
|
}
|
|
222
242
|
|
|
223
243
|
protected getL1TokenForDeposit(
|
|
224
244
|
deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">
|
|
225
|
-
): EvmAddress
|
|
245
|
+
): EvmAddress {
|
|
226
246
|
// L1-->L2 token mappings are set via PoolRebalanceRoutes which occur on mainnet,
|
|
227
247
|
// so we use the latest token mapping. This way if a very old deposit is filled, the relayer can use the
|
|
228
248
|
// latest L2 token mapping to find the L1 token counterpart.
|
|
@@ -230,7 +250,7 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
230
250
|
}
|
|
231
251
|
|
|
232
252
|
l2TokenEnabledForL1Token(l1Token: EvmAddress, destinationChainId: number): boolean {
|
|
233
|
-
return this.
|
|
253
|
+
return this.l1TokensToDestinationTokens?.[l1Token.toEvmAddress()]?.[destinationChainId] != undefined;
|
|
234
254
|
}
|
|
235
255
|
|
|
236
256
|
l2TokenEnabledForL1TokenAtBlock(l1Token: EvmAddress, destinationChainId: number, hubBlockNumber: number): boolean {
|
|
@@ -238,12 +258,21 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
238
258
|
const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
|
|
239
259
|
this.l1TokensToDestinationTokensWithBlock?.[l1Token.toEvmAddress()]?.[destinationChainId] ?? []
|
|
240
260
|
).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= hubBlockNumber);
|
|
241
|
-
return l2Token !== undefined
|
|
261
|
+
return l2Token !== undefined;
|
|
242
262
|
}
|
|
243
263
|
|
|
244
264
|
l2TokenHasPoolRebalanceRoute(l2Token: Address, l2ChainId: number, hubPoolBlock = this.latestHeightSearched): boolean {
|
|
245
|
-
|
|
246
|
-
|
|
265
|
+
return Object.values(this.l1TokensToDestinationTokensWithBlock).some((destinationTokenMapping) => {
|
|
266
|
+
return Object.entries(destinationTokenMapping).some(([_l2ChainId, setPoolRebalanceRouteEvents]) => {
|
|
267
|
+
return setPoolRebalanceRouteEvents.some((e) => {
|
|
268
|
+
return (
|
|
269
|
+
e.blockNumber <= hubPoolBlock &&
|
|
270
|
+
e.l2Token.truncateToBytes20() === l2Token.truncateToBytes20() &&
|
|
271
|
+
Number(_l2ChainId) === l2ChainId
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
247
276
|
}
|
|
248
277
|
|
|
249
278
|
/**
|
|
@@ -378,11 +407,9 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
378
407
|
const hubPoolTokens: { [k: string]: EvmAddress } = {};
|
|
379
408
|
const getHubPoolToken = (deposit: LpFeeRequest, quoteBlockNumber: number): EvmAddress | undefined => {
|
|
380
409
|
const tokenKey = `${deposit.originChainId}-${deposit.inputToken}`;
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
return (hubPoolTokens[tokenKey] ??= l1Token);
|
|
410
|
+
if (this.l2TokenHasPoolRebalanceRoute(deposit.inputToken, deposit.originChainId, quoteBlockNumber)) {
|
|
411
|
+
return (hubPoolTokens[tokenKey] ??= this.getL1TokenForDeposit({ ...deposit, quoteBlockNumber }));
|
|
412
|
+
} else return undefined;
|
|
386
413
|
};
|
|
387
414
|
const getHubPoolTokens = (): EvmAddress[] => dedupArray(Object.values(hubPoolTokens).filter(isDefined));
|
|
388
415
|
|
|
@@ -521,14 +548,14 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
521
548
|
// Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
|
|
522
549
|
const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
|
|
523
550
|
const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
|
|
524
|
-
if (!l1TokenA
|
|
551
|
+
if (!l1TokenA.eq(l1TokenB)) {
|
|
525
552
|
return false;
|
|
526
553
|
}
|
|
527
554
|
|
|
528
555
|
// Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
|
|
529
556
|
const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
|
|
530
557
|
const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
|
|
531
|
-
return
|
|
558
|
+
return tokenA.eq(_tokenA) && tokenB.eq(_tokenB);
|
|
532
559
|
}
|
|
533
560
|
|
|
534
561
|
getSpokeActivationBlockForChain(chainId: number): number {
|
|
@@ -968,22 +995,24 @@ export class HubPoolClient extends BaseAbstractClient {
|
|
|
968
995
|
destinationToken = svmUsdc;
|
|
969
996
|
}
|
|
970
997
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
998
|
+
// If the destination token is set to the zero address in an event, then this means Across should no longer
|
|
999
|
+
// rebalance to this chain.
|
|
1000
|
+
if (!destinationToken.isZeroAddress()) {
|
|
1001
|
+
assign(this.l1TokensToDestinationTokens, [args.l1Token, args.destinationChainId], destinationToken);
|
|
1002
|
+
assign(
|
|
1003
|
+
this.l1TokensToDestinationTokensWithBlock,
|
|
1004
|
+
[args.l1Token, args.destinationChainId],
|
|
1005
|
+
[
|
|
1006
|
+
{
|
|
1007
|
+
l1Token: EvmAddress.from(args.l1Token),
|
|
1008
|
+
l2Token: destinationToken,
|
|
1009
|
+
blockNumber: args.blockNumber,
|
|
1010
|
+
txnIndex: args.txnIndex,
|
|
1011
|
+
logIndex: args.logIndex,
|
|
1012
|
+
txnRef: args.txnRef,
|
|
1013
|
+
},
|
|
1014
|
+
]
|
|
1015
|
+
);
|
|
987
1016
|
}
|
|
988
1017
|
}
|
|
989
1018
|
}
|
|
@@ -11,6 +11,7 @@ import { DepositWithBlock, FillStatus, RelayData } from "../../interfaces";
|
|
|
11
11
|
import {
|
|
12
12
|
BigNumber,
|
|
13
13
|
DepositSearchResult,
|
|
14
|
+
getMessageHash,
|
|
14
15
|
getNetworkName,
|
|
15
16
|
InvalidFill,
|
|
16
17
|
MakeOptional,
|
|
@@ -194,18 +195,31 @@ export class EVMSpokePoolClient extends SpokePoolClient {
|
|
|
194
195
|
};
|
|
195
196
|
}
|
|
196
197
|
|
|
198
|
+
const spreadEvent = spreadEventWithBlockNumber(event) as Omit<
|
|
199
|
+
DepositWithBlock,
|
|
200
|
+
"originChainId" | "inputToken" | "outputToken" | "depositor" | "recipient" | "exclusiveRelayer"
|
|
201
|
+
> & {
|
|
202
|
+
inputToken: string;
|
|
203
|
+
outputToken: string;
|
|
204
|
+
depositor: string;
|
|
205
|
+
recipient: string;
|
|
206
|
+
exclusiveRelayer: string;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const originChainId = this.chainId;
|
|
197
210
|
deposit = {
|
|
198
|
-
...
|
|
199
|
-
inputToken: toAddressType(event.args.inputToken, event.args.originChainId),
|
|
200
|
-
outputToken: toAddressType(event.args.outputToken, event.args.destinationChainId),
|
|
201
|
-
depositor: toAddressType(event.args.depositor, this.chainId),
|
|
202
|
-
recipient: toAddressType(event.args.recipient, event.args.destinationChainId),
|
|
203
|
-
exclusiveRelayer: toAddressType(event.args.exclusiveRelayer, event.args.destinationChainId),
|
|
211
|
+
...spreadEvent,
|
|
204
212
|
originChainId: this.chainId,
|
|
205
|
-
|
|
213
|
+
inputToken: toAddressType(spreadEvent.inputToken, originChainId),
|
|
214
|
+
outputToken: toAddressType(spreadEvent.outputToken, spreadEvent.destinationChainId),
|
|
215
|
+
depositor: toAddressType(spreadEvent.depositor, originChainId),
|
|
216
|
+
recipient: toAddressType(spreadEvent.recipient, spreadEvent.destinationChainId),
|
|
217
|
+
exclusiveRelayer: toAddressType(spreadEvent.exclusiveRelayer, spreadEvent.destinationChainId),
|
|
218
|
+
quoteBlockNumber: await this.getBlockNumber(spreadEvent.quoteTimestamp),
|
|
219
|
+
messageHash: getMessageHash(spreadEvent.message),
|
|
206
220
|
fromLiteChain: true, // To be updated immediately afterwards.
|
|
207
221
|
toLiteChain: true, // To be updated immediately afterwards.
|
|
208
|
-
}
|
|
222
|
+
};
|
|
209
223
|
|
|
210
224
|
if (deposit.outputToken.isZeroAddress()) {
|
|
211
225
|
deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
|
|
@@ -472,22 +472,18 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
472
472
|
)
|
|
473
473
|
) {
|
|
474
474
|
return false;
|
|
475
|
+
} else {
|
|
476
|
+
const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
|
|
477
|
+
deposit.inputToken,
|
|
478
|
+
deposit.originChainId,
|
|
479
|
+
deposit.quoteBlockNumber
|
|
480
|
+
);
|
|
481
|
+
return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
|
|
482
|
+
l1Token,
|
|
483
|
+
deposit.destinationChainId,
|
|
484
|
+
deposit.quoteBlockNumber
|
|
485
|
+
);
|
|
475
486
|
}
|
|
476
|
-
|
|
477
|
-
const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
|
|
478
|
-
deposit.inputToken,
|
|
479
|
-
deposit.originChainId,
|
|
480
|
-
deposit.quoteBlockNumber
|
|
481
|
-
);
|
|
482
|
-
if (!l1Token) {
|
|
483
|
-
return false;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
|
|
487
|
-
l1Token,
|
|
488
|
-
deposit.destinationChainId,
|
|
489
|
-
deposit.quoteBlockNumber
|
|
490
|
-
);
|
|
491
487
|
}
|
|
492
488
|
|
|
493
489
|
/**
|
|
@@ -523,11 +519,12 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
523
519
|
}
|
|
524
520
|
|
|
525
521
|
// Performs the indexing of a deposit-like spoke pool event.
|
|
522
|
+
const originChainId = this.chainId;
|
|
526
523
|
const queryDepositEvents = async (eventName: string) => {
|
|
527
524
|
const depositEvents = (queryResults[eventsToQuery.indexOf(eventName)] ?? []).map((_event) => {
|
|
528
525
|
const event = _event as Omit<
|
|
529
526
|
DepositWithBlock,
|
|
530
|
-
"depositor" | "recipient" | "inputToken" | "outputToken" | "exclusiveRelayer"
|
|
527
|
+
"originChainId" | "depositor" | "recipient" | "inputToken" | "outputToken" | "exclusiveRelayer"
|
|
531
528
|
> & {
|
|
532
529
|
depositor: string;
|
|
533
530
|
recipient: string;
|
|
@@ -537,12 +534,14 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
537
534
|
};
|
|
538
535
|
return {
|
|
539
536
|
...event,
|
|
540
|
-
|
|
537
|
+
originChainId,
|
|
538
|
+
depositor: toAddressType(event.depositor, originChainId),
|
|
541
539
|
recipient: toAddressType(event.recipient, event.destinationChainId),
|
|
542
|
-
inputToken: toAddressType(event.inputToken,
|
|
540
|
+
inputToken: toAddressType(event.inputToken, originChainId),
|
|
543
541
|
outputToken: toAddressType(event.outputToken, event.destinationChainId),
|
|
544
542
|
exclusiveRelayer: toAddressType(event.exclusiveRelayer, event.destinationChainId),
|
|
545
|
-
|
|
543
|
+
messageHash: getMessageHash(event.message),
|
|
544
|
+
} satisfies Omit<DepositWithBlock, "quoteBlockNumber" | "fromLiteChain" | "toLiteChain">;
|
|
546
545
|
});
|
|
547
546
|
if (depositEvents.length > 0) {
|
|
548
547
|
this.log(
|
|
@@ -563,17 +562,11 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
563
562
|
// Derive and append the common properties that are not part of the onchain event.
|
|
564
563
|
const deposit = {
|
|
565
564
|
...event,
|
|
566
|
-
messageHash: getMessageHash(event.message),
|
|
567
565
|
quoteBlockNumber,
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
fromLiteChain: true,
|
|
571
|
-
toLiteChain: true,
|
|
566
|
+
fromLiteChain: this.isOriginLiteChain(event),
|
|
567
|
+
toLiteChain: this.isDestinationLiteChain(event),
|
|
572
568
|
};
|
|
573
569
|
|
|
574
|
-
deposit.fromLiteChain = this.isOriginLiteChain(deposit);
|
|
575
|
-
deposit.toLiteChain = this.isDestinationLiteChain(deposit);
|
|
576
|
-
|
|
577
570
|
if (deposit.outputToken.isZeroAddress()) {
|
|
578
571
|
deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
|
|
579
572
|
}
|
|
@@ -697,10 +690,12 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
697
690
|
});
|
|
698
691
|
|
|
699
692
|
// Performs indexing of filled relay-like events.
|
|
693
|
+
const destinationChainId = this.chainId;
|
|
700
694
|
const queryFilledRelayEvents = (eventName: string) => {
|
|
701
695
|
const fillEvents = (queryResults[eventsToQuery.indexOf(eventName)] ?? []).map((_event) => {
|
|
702
696
|
const event = _event as Omit<
|
|
703
697
|
FillWithBlock,
|
|
698
|
+
| "destinationChainId"
|
|
704
699
|
| "depositor"
|
|
705
700
|
| "recipient"
|
|
706
701
|
| "inputToken"
|
|
@@ -717,19 +712,21 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
717
712
|
relayer: string;
|
|
718
713
|
relayExecutionInfo: Omit<RelayExecutionEventInfo, "updatedRecipient"> & { updatedRecipient: string };
|
|
719
714
|
};
|
|
715
|
+
|
|
720
716
|
return {
|
|
721
717
|
...event,
|
|
718
|
+
destinationChainId,
|
|
722
719
|
depositor: toAddressType(event.depositor, event.originChainId),
|
|
723
|
-
recipient: toAddressType(event.recipient,
|
|
720
|
+
recipient: toAddressType(event.recipient, destinationChainId),
|
|
724
721
|
inputToken: toAddressType(event.inputToken, event.originChainId),
|
|
725
|
-
outputToken: toAddressType(event.outputToken,
|
|
726
|
-
exclusiveRelayer: toAddressType(event.exclusiveRelayer,
|
|
727
|
-
relayer: toAddressType(event.relayer,
|
|
722
|
+
outputToken: toAddressType(event.outputToken, destinationChainId),
|
|
723
|
+
exclusiveRelayer: toAddressType(event.exclusiveRelayer, destinationChainId),
|
|
724
|
+
relayer: toAddressType(event.relayer, event.repaymentChainId),
|
|
728
725
|
relayExecutionInfo: {
|
|
729
726
|
...event.relayExecutionInfo,
|
|
730
727
|
updatedRecipient: toAddressType(event.relayExecutionInfo.updatedRecipient, this.chainId),
|
|
731
728
|
},
|
|
732
|
-
}
|
|
729
|
+
} satisfies FillWithBlock;
|
|
733
730
|
});
|
|
734
731
|
|
|
735
732
|
if (fillEvents.length > 0) {
|
|
@@ -740,16 +737,11 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
|
|
|
740
737
|
|
|
741
738
|
// @note The type assertions here suppress errors that might arise due to incomplete types. For now, verify via
|
|
742
739
|
// test that the types are complete. A broader change in strategy for safely unpacking events will be introduced.
|
|
743
|
-
for (const
|
|
744
|
-
const fill = {
|
|
745
|
-
...event,
|
|
746
|
-
destinationChainId: this.chainId,
|
|
747
|
-
};
|
|
748
|
-
|
|
740
|
+
for (const fill of fillEvents) {
|
|
749
741
|
// Sanity check that this event is not a duplicate.
|
|
750
742
|
const duplicateFill = this.fills[fill.originChainId]?.find((f) => duplicateEvent(fill, f));
|
|
751
743
|
if (duplicateFill) {
|
|
752
|
-
duplicateEvents.push(
|
|
744
|
+
duplicateEvents.push(fill);
|
|
753
745
|
continue;
|
|
754
746
|
}
|
|
755
747
|
|
|
@@ -118,9 +118,9 @@ export class MockHubPoolClient extends HubPoolClient {
|
|
|
118
118
|
delete this.spokePoolTokens[l1Token]?.[chainId];
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
getL1TokenForL2TokenAtBlock(l2Token: Address, chainId: number, blockNumber: number): EvmAddress
|
|
121
|
+
getL1TokenForL2TokenAtBlock(l2Token: Address, chainId: number, blockNumber: number): EvmAddress {
|
|
122
122
|
const l1Token = Object.keys(this.spokePoolTokens).find(
|
|
123
|
-
(l1Token) => this.spokePoolTokens[l1Token]?.[chainId]
|
|
123
|
+
(l1Token) => this.spokePoolTokens[l1Token]?.[chainId].eq(l2Token)
|
|
124
124
|
);
|
|
125
125
|
if (isDefined(l1Token)) {
|
|
126
126
|
return EvmAddress.from(l1Token);
|
|
@@ -129,7 +129,7 @@ export class MockHubPoolClient extends HubPoolClient {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
getL2TokenForL1TokenAtBlock(l1Token: EvmAddress, chainId: number, blockNumber: number): Address
|
|
132
|
+
getL2TokenForL1TokenAtBlock(l1Token: EvmAddress, chainId: number, blockNumber: number): Address {
|
|
133
133
|
const l2Token = this.spokePoolTokens[l1Token.toEvmAddress()]?.[chainId];
|
|
134
134
|
return l2Token ?? super.getL2TokenForL1TokenAtBlock(l1Token, chainId, blockNumber);
|
|
135
135
|
}
|
package/src/constants.ts
CHANGED
|
@@ -93,3 +93,15 @@ export const CUSTOM_GAS_TOKENS = {
|
|
|
93
93
|
[CHAIN_IDs.LENS]: "GHO",
|
|
94
94
|
[CHAIN_IDs.LENS_SEPOLIA]: "GHO",
|
|
95
95
|
};
|
|
96
|
+
|
|
97
|
+
// Blocks where SpokePools were upgraded from v2 to v2.5. This is where the fillStatus mapping
|
|
98
|
+
// was introduced. This mapping should only be updated on subsequent upgrades where there are
|
|
99
|
+
// breaking changes and the exact upgrade block is required to bound certain queries.
|
|
100
|
+
export const SPOKEPOOL_UPGRADE_BLOCKS = {
|
|
101
|
+
[CHAIN_IDs.ARBITRUM]: 183082059,
|
|
102
|
+
[CHAIN_IDs.BASE]: 10874747,
|
|
103
|
+
[CHAIN_IDs.MAINNET]: 19277695,
|
|
104
|
+
[CHAIN_IDs.OPTIMISM]: 116469982,
|
|
105
|
+
[CHAIN_IDs.POLYGON]: 53793776,
|
|
106
|
+
[CHAIN_IDs.ZK_SYNC]: 27157340,
|
|
107
|
+
};
|