@across-protocol/sdk 4.1.45-beta.1 → 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.
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +14 -23
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +1 -10
- package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +7 -7
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +36 -47
- package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/cjs/clients/HubPoolClient.d.ts +2 -6
- package/dist/cjs/clients/HubPoolClient.js +15 -37
- package/dist/cjs/clients/HubPoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +5 -19
- package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +1 -3
- package/dist/cjs/clients/mocks/MockHubPoolClient.js +1 -19
- package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js +0 -5
- package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
- package/dist/cjs/utils/DepositUtils.d.ts +0 -1
- package/dist/cjs/utils/DepositUtils.js +1 -5
- package/dist/cjs/utils/DepositUtils.js.map +1 -1
- package/dist/cjs/utils/TokenUtils.js +2 -0
- package/dist/cjs/utils/TokenUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +15 -24
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +1 -16
- package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +7 -28
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +50 -83
- package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +2 -2
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/esm/clients/HubPoolClient.d.ts +16 -13
- package/dist/esm/clients/HubPoolClient.js +34 -49
- package/dist/esm/clients/HubPoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +14 -28
- package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
- package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +1 -3
- package/dist/esm/clients/mocks/MockHubPoolClient.js +1 -19
- package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
- package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -6
- package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js +0 -10
- package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.js.map +1 -1
- package/dist/esm/utils/DepositUtils.d.ts +0 -1
- package/dist/esm/utils/DepositUtils.js +1 -5
- package/dist/esm/utils/DepositUtils.js.map +1 -1
- package/dist/esm/utils/TokenUtils.js +2 -0
- package/dist/esm/utils/TokenUtils.js.map +1 -1
- package/dist/types/clients/BundleDataClient/BundleDataClient.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 +7 -28
- package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
- package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
- package/dist/types/clients/HubPoolClient.d.ts +16 -13
- package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts +0 -1
- package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/clients/mocks/MockHubPoolClient.d.ts +1 -3
- package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts +0 -6
- package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts +0 -1
- package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts.map +1 -1
- package/dist/types/utils/DepositUtils.d.ts +0 -1
- package/dist/types/utils/DepositUtils.d.ts.map +1 -1
- package/dist/types/utils/TokenUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/clients/BundleDataClient/BundleDataClient.ts +21 -38
- package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +1 -36
- package/src/clients/BundleDataClient/utils/FillUtils.ts +71 -133
- package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +2 -3
- package/src/clients/HubPoolClient.ts +38 -64
- package/src/clients/SpokePoolClient/SpokePoolClient.ts +16 -54
- package/src/clients/mocks/MockHubPoolClient.ts +2 -18
- package/src/relayFeeCalculator/chain-queries/baseQuery.ts +0 -10
- package/src/relayFeeCalculator/relayFeeCalculator.ts +0 -1
- package/src/utils/DepositUtils.ts +1 -6
- package/src/utils/TokenUtils.ts +2 -0
|
@@ -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
|
-
|
|
8
|
+
fill: Fill,
|
|
23
9
|
hubPoolClient: HubPoolClient,
|
|
24
|
-
|
|
10
|
+
blockRangesForChains: number[][],
|
|
11
|
+
chainIdListForBundleEvaluationBlockNumbers: number[],
|
|
12
|
+
fromLiteChain: boolean
|
|
25
13
|
): {
|
|
26
14
|
chainToSendRefundTo: number;
|
|
27
15
|
repaymentToken: string;
|
|
28
16
|
} {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
43
|
+
endBlockForMainnet
|
|
50
44
|
);
|
|
51
45
|
return {
|
|
52
46
|
chainToSendRefundTo,
|
|
53
47
|
repaymentToken,
|
|
54
48
|
};
|
|
55
49
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
256
|
-
return
|
|
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
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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 {
|
|
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
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
(!
|
|
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
|
-
|
|
740
|
-
|
|
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
|
-
|
|
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"];
|
|
@@ -2,7 +2,7 @@ import assert from "assert";
|
|
|
2
2
|
import { SpokePoolClient } from "../clients";
|
|
3
3
|
import { DEFAULT_CACHING_TTL, EMPTY_MESSAGE, UNDEFINED_MESSAGE_HASH, ZERO_BYTES } from "../constants";
|
|
4
4
|
import { CachingMechanismInterface, Deposit, DepositWithBlock, Fill, RelayData, SlowFillRequest } from "../interfaces";
|
|
5
|
-
import { getMessageHash, isUnsafeDepositId
|
|
5
|
+
import { getMessageHash, isUnsafeDepositId } from "./SpokeUtils";
|
|
6
6
|
import { getNetworkName } from "./NetworkUtils";
|
|
7
7
|
import { bnZero } from "./BigNumberUtils";
|
|
8
8
|
import { getDepositInCache, getDepositKey, setDepositInCache } from "./CachingUtils";
|
|
@@ -208,11 +208,6 @@ export function isZeroValueDeposit(deposit: Pick<Deposit, "inputAmount" | "messa
|
|
|
208
208
|
return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
export function invalidOutputToken(deposit: Pick<DepositWithBlock, "outputToken">): boolean {
|
|
212
|
-
// If the output token is zero address, then it is invalid.
|
|
213
|
-
return isZeroAddress(deposit.outputToken);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
211
|
export function isZeroValueFillOrSlowFillRequest(
|
|
217
212
|
e: Pick<Fill | SlowFillRequest, "inputAmount" | "messageHash">
|
|
218
213
|
): boolean {
|
package/src/utils/TokenUtils.ts
CHANGED
|
@@ -147,6 +147,8 @@ export function getUsdcSymbol(l2Token: string, chainId: number): string | undefi
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
export function getL1TokenInfo(l2TokenAddress: string, chainId: number): L1Token {
|
|
150
|
+
if (chainId === CHAIN_IDs.MAINNET)
|
|
151
|
+
throw new Error("chainId should be an L2 chainId because many mappings re-use the same L1 token address");
|
|
150
152
|
const tokenObject = Object.values(TOKEN_SYMBOLS_MAP).find(({ addresses }) => addresses[chainId] === l2TokenAddress);
|
|
151
153
|
const l1TokenAddress = tokenObject?.addresses[CHAIN_IDs.MAINNET];
|
|
152
154
|
if (!l1TokenAddress) {
|