@across-protocol/sdk 4.1.29 → 4.1.30
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 +2 -2
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient.d.ts +0 -3
- package/dist/cjs/clients/SpokePoolClient.js +5 -64
- package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
- package/dist/cjs/relayFeeCalculator/chain-queries/factory.d.ts +9 -9
- package/dist/cjs/relayFeeCalculator/relayFeeCalculator.d.ts +9 -9
- package/dist/cjs/utils/CachingUtils.js +2 -2
- package/dist/cjs/utils/CachingUtils.js.map +1 -1
- package/dist/cjs/utils/DepositUtils.d.ts +14 -1
- package/dist/cjs/utils/DepositUtils.js +51 -3
- package/dist/cjs/utils/DepositUtils.js.map +1 -1
- package/dist/cjs/utils/SpokeUtils.d.ts +2 -18
- package/dist/cjs/utils/SpokeUtils.js +26 -130
- package/dist/cjs/utils/SpokeUtils.js.map +1 -1
- package/dist/cjs/utils/TokenUtils.d.ts +18 -18
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +2 -2
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient.d.ts +0 -14
- package/dist/esm/clients/SpokePoolClient.js +7 -82
- package/dist/esm/clients/SpokePoolClient.js.map +1 -1
- package/dist/esm/relayFeeCalculator/chain-queries/factory.d.ts +9 -9
- package/dist/esm/relayFeeCalculator/relayFeeCalculator.d.ts +9 -9
- package/dist/esm/utils/CachingUtils.js +1 -1
- package/dist/esm/utils/CachingUtils.js.map +1 -1
- package/dist/esm/utils/DepositUtils.d.ts +21 -1
- package/dist/esm/utils/DepositUtils.js +61 -2
- package/dist/esm/utils/DepositUtils.js.map +1 -1
- package/dist/esm/utils/SpokeUtils.d.ts +9 -36
- package/dist/esm/utils/SpokeUtils.js +32 -185
- package/dist/esm/utils/SpokeUtils.js.map +1 -1
- package/dist/esm/utils/TokenUtils.d.ts +18 -18
- package/dist/types/clients/SpokePoolClient.d.ts +0 -14
- package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/relayFeeCalculator/chain-queries/factory.d.ts +9 -9
- package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts +9 -9
- package/dist/types/utils/DepositUtils.d.ts +21 -1
- package/dist/types/utils/DepositUtils.d.ts.map +1 -1
- package/dist/types/utils/SpokeUtils.d.ts +9 -36
- package/dist/types/utils/SpokeUtils.d.ts.map +1 -1
- package/dist/types/utils/TokenUtils.d.ts +18 -18
- package/package.json +2 -2
- package/src/clients/BundleDataClient/BundleDataClient.ts +2 -2
- package/src/clients/SpokePoolClient.ts +14 -69
- package/src/utils/CachingUtils.ts +1 -1
- package/src/utils/DepositUtils.ts +73 -3
- package/src/utils/SpokeUtils.ts +22 -210
package/src/utils/SpokeUtils.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
2
|
import { BytesLike, Contract, PopulatedTransaction, providers, utils as ethersUtils } from "ethers";
|
|
3
|
-
import { CHAIN_IDs, MAX_SAFE_DEPOSIT_ID,
|
|
3
|
+
import { CHAIN_IDs, MAX_SAFE_DEPOSIT_ID, ZERO_ADDRESS, ZERO_BYTES } from "../constants";
|
|
4
4
|
import { Deposit, FillStatus, FillWithBlock, RelayData } from "../interfaces";
|
|
5
|
-
import { SpokePoolClient } from "../clients";
|
|
6
5
|
import { chunk } from "./ArrayUtils";
|
|
7
|
-
import { BigNumber, toBN,
|
|
6
|
+
import { bnUint32Max, BigNumber, toBN, bnZero } from "./BigNumberUtils";
|
|
8
7
|
import { keccak256 } from "./common";
|
|
9
8
|
import { isMessageEmpty } from "./DepositUtils";
|
|
10
9
|
import { isDefined } from "./TypeGuards";
|
|
@@ -60,219 +59,32 @@ export function populateV3Relay(
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* (getRelayDataHash()) for two reasons: performance and the fact that only Deposit includes the `message` field, which
|
|
66
|
-
* is required to compute a complete RelayData hash.
|
|
67
|
-
* note: This function should _not_ be used to query the SpokePool.fillStatuses mapping.
|
|
62
|
+
* Retrieves the time from the SpokePool contract at a particular block.
|
|
63
|
+
* @returns The time at the specified block tag.
|
|
68
64
|
*/
|
|
69
|
-
export function
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
return
|
|
73
|
-
data.depositor,
|
|
74
|
-
data.recipient,
|
|
75
|
-
data.exclusiveRelayer,
|
|
76
|
-
data.inputToken,
|
|
77
|
-
data.outputToken,
|
|
78
|
-
data.inputAmount,
|
|
79
|
-
data.outputAmount,
|
|
80
|
-
data.originChainId,
|
|
81
|
-
data.destinationChainId,
|
|
82
|
-
data.depositId,
|
|
83
|
-
data.fillDeadline,
|
|
84
|
-
data.exclusivityDeadline,
|
|
85
|
-
data.messageHash,
|
|
86
|
-
]
|
|
87
|
-
.map(String)
|
|
88
|
-
.join("-");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const RELAYDATA_KEYS = [
|
|
92
|
-
"depositId",
|
|
93
|
-
"originChainId",
|
|
94
|
-
"destinationChainId",
|
|
95
|
-
"depositor",
|
|
96
|
-
"recipient",
|
|
97
|
-
"inputToken",
|
|
98
|
-
"inputAmount",
|
|
99
|
-
"outputToken",
|
|
100
|
-
"outputAmount",
|
|
101
|
-
"fillDeadline",
|
|
102
|
-
"exclusivityDeadline",
|
|
103
|
-
"exclusiveRelayer",
|
|
104
|
-
"messageHash",
|
|
105
|
-
] as const;
|
|
106
|
-
|
|
107
|
-
// Ensure that each deposit element is included with the same value in the fill. This includes all elements defined
|
|
108
|
-
// by the depositor as well as destinationToken, which are pulled from other clients.
|
|
109
|
-
export function validateFillForDeposit(
|
|
110
|
-
relayData: Omit<RelayData, "message"> & { messageHash: string; destinationChainId: number },
|
|
111
|
-
deposit?: Omit<Deposit, "quoteTimestamp" | "fromLiteChain" | "toLiteChain">
|
|
112
|
-
): { valid: true } | { valid: false; reason: string } {
|
|
113
|
-
if (deposit === undefined) {
|
|
114
|
-
return { valid: false, reason: "Deposit is undefined" };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Note: this short circuits when a key is found where the comparison doesn't match.
|
|
118
|
-
// TODO: if we turn on "strict" in the tsconfig, the elements of FILL_DEPOSIT_COMPARISON_KEYS will be automatically
|
|
119
|
-
// validated against the fields in Fill and Deposit, generating an error if there is a discrepency.
|
|
120
|
-
let invalidKey = RELAYDATA_KEYS.find((key) => relayData[key].toString() !== deposit[key].toString());
|
|
121
|
-
|
|
122
|
-
// There should be no paths for `messageHash` to be unset, but mask it off anyway.
|
|
123
|
-
if (!isDefined(invalidKey) && [relayData.messageHash, deposit.messageHash].includes(UNDEFINED_MESSAGE_HASH)) {
|
|
124
|
-
invalidKey = "messageHash";
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return isDefined(invalidKey)
|
|
128
|
-
? { valid: false, reason: `${invalidKey} mismatch (${relayData[invalidKey]} != ${deposit[invalidKey]})` }
|
|
129
|
-
: { valid: true };
|
|
65
|
+
export async function getTimeAt(spokePool: Contract, blockNumber: number): Promise<number> {
|
|
66
|
+
const currentTime = await spokePool.getCurrentTime({ blockTag: blockNumber });
|
|
67
|
+
assert(BigNumber.isBigNumber(currentTime) && currentTime.lt(bnUint32Max));
|
|
68
|
+
return currentTime.toNumber();
|
|
130
69
|
}
|
|
131
70
|
|
|
132
71
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* @param
|
|
136
|
-
* @param
|
|
137
|
-
* @
|
|
138
|
-
* @param maxSearches The maximum number of searches to perform. This is used to prevent infinite loops.
|
|
139
|
-
* @returns The block range that contains the deposit ID.
|
|
140
|
-
* @note // We want to find the block range that satisfies these conditions:
|
|
141
|
-
* // - the low block has deposit count <= targetDepositId
|
|
142
|
-
* // - the high block has a deposit count > targetDepositId.
|
|
143
|
-
* // This way the caller can search for a V3FundsDeposited event between [low, high] that will always
|
|
144
|
-
* // contain the event emitted when deposit ID was incremented to targetDepositId + 1. This is the same transaction
|
|
145
|
-
* // where the deposit with deposit ID = targetDepositId was created.
|
|
72
|
+
* Return maximum of fill deadline buffer at start and end of block range.
|
|
73
|
+
* @param spokePool SpokePool contract instance
|
|
74
|
+
* @param startBlock start block
|
|
75
|
+
* @param endBlock end block
|
|
76
|
+
* @returns maximum of fill deadline buffer at start and end block
|
|
146
77
|
*/
|
|
147
|
-
export async function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
high: number;
|
|
156
|
-
}> {
|
|
157
|
-
// We can only perform this search when we have a safe deposit ID.
|
|
158
|
-
if (isUnsafeDepositId(targetDepositId))
|
|
159
|
-
throw new Error(
|
|
160
|
-
`Target deposit ID ${targetDepositId} is deterministic and therefore unresolvable via a binary search.`
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
// Resolve the deployment block number.
|
|
164
|
-
const deploymentBlock = spokePool.deploymentBlock;
|
|
165
|
-
|
|
166
|
-
// Set the initial high block to the most recent block number or the initial high block, whichever is smaller.
|
|
167
|
-
initHigh = Math.min(initHigh, spokePool.latestBlockSearched);
|
|
168
|
-
|
|
169
|
-
// We will now set a list of sanity checks to ensure that the binary search will not fail
|
|
170
|
-
// due to invalid input parameters.
|
|
171
|
-
// If any of these sanity checks fail, then we will throw an error.
|
|
172
|
-
(
|
|
173
|
-
[
|
|
174
|
-
// Sanity check to ensure that the spoke pool client is updated
|
|
175
|
-
[spokePool.isUpdated, "Spoke pool client is not updated"],
|
|
176
|
-
// Sanity check to ensure that initHigh is greater than or equal to initLow.
|
|
177
|
-
[initLow <= initHigh, "Binary search failed because low > high"],
|
|
178
|
-
// Sanity check to ensure that init Low is greater than or equal to zero.
|
|
179
|
-
[initLow >= deploymentBlock, "Binary search failed because low must be >= deploymentBlock"],
|
|
180
|
-
// Sanity check to ensure that maxSearches is greater than zero.
|
|
181
|
-
[maxSearches > 0, "maxSearches must be > 0"],
|
|
182
|
-
// Sanity check to ensure that deploymentBlock is greater than or equal to zero.
|
|
183
|
-
[deploymentBlock >= 0, "deploymentBlock must be >= 0"],
|
|
184
|
-
] as [boolean, string][]
|
|
185
|
-
).forEach(([condition, errorMessage]) => {
|
|
186
|
-
// If the condition is false, then we will throw an error.
|
|
187
|
-
if (!condition) {
|
|
188
|
-
throw new Error(errorMessage);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// Define a mapping of block numbers to number of deposits at that block. This saves repeated lookups.
|
|
193
|
-
const queriedIds: Record<number, BigNumber> = {};
|
|
194
|
-
|
|
195
|
-
// Define a llambda function to get the deposit ID at a block number. This function will first check the
|
|
196
|
-
// queriedIds cache to see if the deposit ID at the block number has already been queried. If not, it will
|
|
197
|
-
// make an eth_call request to get the deposit ID at the block number. It will then cache the deposit ID
|
|
198
|
-
// in the queriedIds cache.
|
|
199
|
-
const _getDepositIdAtBlock = async (blockNumber: number): Promise<BigNumber> => {
|
|
200
|
-
queriedIds[blockNumber] ??= await spokePool._getDepositIdAtBlock(blockNumber);
|
|
201
|
-
return queriedIds[blockNumber];
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
// Get the the deposit ID at the low block, and the deposit ID at the high block in parallel.
|
|
205
|
-
const [highestDepositIdInRange, lowestDepositIdInRange] = await Promise.all([
|
|
206
|
-
_getDepositIdAtBlock(initHigh),
|
|
207
|
-
_getDepositIdAtBlock(Math.max(deploymentBlock, initLow - 1)),
|
|
78
|
+
export async function getMaxFillDeadlineInRange(
|
|
79
|
+
spokePool: Contract,
|
|
80
|
+
startBlock: number,
|
|
81
|
+
endBlock: number
|
|
82
|
+
): Promise<number> {
|
|
83
|
+
const fillDeadlineBuffers = await Promise.all([
|
|
84
|
+
spokePool.fillDeadlineBuffer({ blockTag: startBlock }),
|
|
85
|
+
spokePool.fillDeadlineBuffer({ blockTag: endBlock }),
|
|
208
86
|
]);
|
|
209
|
-
|
|
210
|
-
// If the deposit ID at the initial high block is less than the target deposit ID, then we know that
|
|
211
|
-
// the target deposit ID must be greater than the initial high block, so we can throw an error.
|
|
212
|
-
if (highestDepositIdInRange.lte(targetDepositId)) {
|
|
213
|
-
// initLow = 5: Deposits Num: 10
|
|
214
|
-
// // targetId = 11 <- fail (triggers this error) // 10 <= 11
|
|
215
|
-
// // targetId = 10 <- fail (triggers this error) // 10 <= 10
|
|
216
|
-
// // targetId = 09 <- pass (does not trigger this error) // 10 <= 09
|
|
217
|
-
throw new Error(
|
|
218
|
-
`Target depositId is greater than the initial high block (${targetDepositId} > ${highestDepositIdInRange})`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// If the deposit ID at the initial low block is greater than the target deposit ID, then we know that
|
|
223
|
-
// the target deposit ID must be less than the initial low block, so we can throw an error.
|
|
224
|
-
if (lowestDepositIdInRange.gt(targetDepositId)) {
|
|
225
|
-
// initLow = 5: Deposits Num: 10
|
|
226
|
-
// initLow-1 = 4: Deposits Num: 2
|
|
227
|
-
// // targetId = 1 <- fail (triggers this error)
|
|
228
|
-
// // targetId = 2 <- pass (does not trigger this error)
|
|
229
|
-
// // targetId = 3 <- pass (does not trigger this error)
|
|
230
|
-
throw new Error(
|
|
231
|
-
`Target depositId is less than the initial low block (${targetDepositId.toString()} > ${lowestDepositIdInRange})`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Define the low and high block numbers for the binary search.
|
|
236
|
-
let low = initLow;
|
|
237
|
-
let high = initHigh;
|
|
238
|
-
// Define the number of searches performed so far.
|
|
239
|
-
let searches = 0;
|
|
240
|
-
|
|
241
|
-
do {
|
|
242
|
-
// Resolve the mid point of the block range.
|
|
243
|
-
const mid = Math.floor((low + high) / 2);
|
|
244
|
-
|
|
245
|
-
// Get the deposit ID at the mid point.
|
|
246
|
-
const midDepositId = await _getDepositIdAtBlock(mid);
|
|
247
|
-
|
|
248
|
-
// Let's define the latest ID of the current midpoint block.
|
|
249
|
-
const accountedIdByMidBlock = midDepositId.sub(bnOne);
|
|
250
|
-
|
|
251
|
-
// If our target deposit ID is less than the smallest range of our
|
|
252
|
-
// midpoint deposit ID range, then we know that the target deposit ID
|
|
253
|
-
// must be in the lower half of the block range.
|
|
254
|
-
if (targetDepositId.lte(accountedIdByMidBlock)) {
|
|
255
|
-
high = mid;
|
|
256
|
-
}
|
|
257
|
-
// If our target deposit ID is greater than the largest range of our
|
|
258
|
-
// midpoint deposit ID range, then we know that the target deposit ID
|
|
259
|
-
// must be in the upper half of the block range.
|
|
260
|
-
else {
|
|
261
|
-
low = mid + 1;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// We want to iterate until we've either found the block range or we've
|
|
265
|
-
// exceeded the maximum number of searches.
|
|
266
|
-
} while (++searches <= maxSearches && low < high);
|
|
267
|
-
|
|
268
|
-
// Sanity check to ensure that our low was not greater than our high.
|
|
269
|
-
if (low > high) {
|
|
270
|
-
throw new Error(`Binary search failed (${low} > ${high}). SHOULD NEVER HAPPEN (but here we are)`);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// We've either found the block range or we've exceeded the maximum number of searches.
|
|
274
|
-
// In either case, the block range is [low, high] so we can return it.
|
|
275
|
-
return { low, high };
|
|
87
|
+
return Math.max(fillDeadlineBuffers[0], fillDeadlineBuffers[1]);
|
|
276
88
|
}
|
|
277
89
|
|
|
278
90
|
/**
|