@across-protocol/sdk 4.3.37 → 4.3.40
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/svm/BlockUtils.d.ts +3 -1
- package/dist/cjs/arch/svm/BlockUtils.js +3 -2
- package/dist/cjs/arch/svm/BlockUtils.js.map +1 -1
- package/dist/cjs/arch/svm/SpokeUtils.d.ts +9 -8
- package/dist/cjs/arch/svm/SpokeUtils.js +106 -130
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/provider.d.ts +1 -1
- package/dist/cjs/arch/svm/provider.js +2 -1
- package/dist/cjs/arch/svm/provider.js.map +1 -1
- package/dist/cjs/arch/svm/utils.d.ts +5 -2
- package/dist/cjs/arch/svm/utils.js +23 -6
- package/dist/cjs/arch/svm/utils.js.map +1 -1
- package/dist/cjs/clients/BaseAbstractClient.d.ts +3 -1
- package/dist/cjs/clients/BaseAbstractClient.js +31 -13
- package/dist/cjs/clients/BaseAbstractClient.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +1 -1
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +1 -1
- package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js +5 -5
- package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js +2 -2
- package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js +2 -2
- package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
- package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
- package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js +2 -2
- package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
- package/dist/cjs/providers/solana/baseRpcFactories.d.ts +3 -3
- package/dist/cjs/providers/solana/baseRpcFactories.js +4 -8
- package/dist/cjs/providers/solana/baseRpcFactories.js.map +1 -1
- package/dist/cjs/providers/solana/cachedRpcFactory.js.map +1 -1
- package/dist/cjs/providers/solana/index.d.ts +1 -0
- package/dist/cjs/providers/solana/index.js +1 -0
- package/dist/cjs/providers/solana/index.js.map +1 -1
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.d.ts +16 -0
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js +208 -0
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js.map +1 -0
- package/dist/cjs/providers/utils.d.ts +1 -0
- package/dist/cjs/providers/utils.js +5 -1
- package/dist/cjs/providers/utils.js.map +1 -1
- package/dist/cjs/utils/BlockExplorerUtils.js +1 -1
- package/dist/cjs/utils/BlockExplorerUtils.js.map +1 -1
- package/dist/esm/arch/svm/BlockUtils.d.ts +3 -1
- package/dist/esm/arch/svm/BlockUtils.js +3 -2
- package/dist/esm/arch/svm/BlockUtils.js.map +1 -1
- package/dist/esm/arch/svm/SpokeUtils.d.ts +9 -8
- package/dist/esm/arch/svm/SpokeUtils.js +109 -131
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/provider.d.ts +1 -1
- package/dist/esm/arch/svm/provider.js +1 -1
- package/dist/esm/arch/svm/provider.js.map +1 -1
- package/dist/esm/arch/svm/utils.d.ts +11 -2
- package/dist/esm/arch/svm/utils.js +28 -6
- package/dist/esm/arch/svm/utils.js.map +1 -1
- package/dist/esm/clients/BaseAbstractClient.d.ts +3 -1
- package/dist/esm/clients/BaseAbstractClient.js +31 -13
- package/dist/esm/clients/BaseAbstractClient.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +1 -1
- package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js +5 -5
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
- package/dist/esm/pool/poolClient.js +1 -1
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js +1 -1
- package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js +1 -1
- package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
- package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
- package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js +1 -1
- package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
- package/dist/esm/providers/solana/baseRpcFactories.d.ts +3 -3
- package/dist/esm/providers/solana/baseRpcFactories.js +4 -8
- package/dist/esm/providers/solana/baseRpcFactories.js.map +1 -1
- package/dist/esm/providers/solana/cachedRpcFactory.js +2 -0
- package/dist/esm/providers/solana/cachedRpcFactory.js.map +1 -1
- package/dist/esm/providers/solana/index.d.ts +1 -0
- package/dist/esm/providers/solana/index.js +1 -0
- package/dist/esm/providers/solana/index.js.map +1 -1
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.d.ts +16 -0
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.js +225 -0
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.js.map +1 -0
- package/dist/esm/providers/utils.d.ts +1 -0
- package/dist/esm/providers/utils.js +3 -0
- package/dist/esm/providers/utils.js.map +1 -1
- package/dist/esm/utils/AddressUtils.js +1 -1
- package/dist/esm/utils/AddressUtils.js.map +1 -1
- package/dist/esm/utils/BlockExplorerUtils.js +1 -1
- package/dist/esm/utils/BlockExplorerUtils.js.map +1 -1
- package/dist/esm/utils/abi/index.d.ts +1 -1
- package/dist/esm/utils/abi/index.js +1 -1
- package/dist/types/arch/svm/BlockUtils.d.ts +3 -1
- package/dist/types/arch/svm/BlockUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/SpokeUtils.d.ts +9 -8
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/provider.d.ts +1 -1
- package/dist/types/arch/svm/provider.d.ts.map +1 -1
- package/dist/types/arch/svm/utils.d.ts +11 -2
- package/dist/types/arch/svm/utils.d.ts.map +1 -1
- package/dist/types/clients/BaseAbstractClient.d.ts +3 -1
- package/dist/types/clients/BaseAbstractClient.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
- package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
- package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
- package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
- package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
- package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/solana/baseRpcFactories.d.ts +3 -3
- package/dist/types/providers/solana/baseRpcFactories.d.ts.map +1 -1
- package/dist/types/providers/solana/cachedRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/solana/index.d.ts +1 -0
- package/dist/types/providers/solana/index.d.ts.map +1 -1
- package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts +17 -0
- package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts.map +1 -0
- package/dist/types/providers/utils.d.ts +1 -0
- package/dist/types/providers/utils.d.ts.map +1 -1
- package/dist/types/utils/abi/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/arch/svm/BlockUtils.ts +3 -1
- package/src/arch/svm/SpokeUtils.ts +100 -137
- package/src/arch/svm/provider.ts +1 -0
- package/src/arch/svm/utils.ts +30 -4
- package/src/caching/Arweave/ArweaveClient.ts +1 -1
- package/src/clients/BaseAbstractClient.ts +24 -8
- package/src/clients/BundleDataClient/BundleDataClient.ts +1 -0
- package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +5 -1
- package/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +5 -5
- package/src/pool/poolClient.ts +1 -1
- package/src/providers/mocks/MockCachedSolanaRpcFactory.ts +1 -1
- package/src/providers/mocks/MockRateLimitedSolanaRpcFactory.ts +1 -1
- package/src/providers/mocks/MockRetrySolanaRpcFactory.ts +1 -1
- package/src/providers/rateLimitedProvider.ts +1 -1
- package/src/providers/solana/baseRpcFactories.ts +3 -3
- package/src/providers/solana/cachedRpcFactory.ts +2 -0
- package/src/providers/solana/index.ts +1 -0
- package/src/providers/solana/quorumFallbackRpcFactory.ts +248 -0
- package/src/providers/utils.ts +4 -0
- package/src/utils/AddressUtils.ts +1 -1
- package/src/utils/BlockExplorerUtils.ts +1 -1
- package/src/utils/abi/index.ts +1 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MessageTransmitterClient, SvmSpokeClient, TokenMessengerMinterClient } from "@across-protocol/contracts";
|
|
2
2
|
import { decodeFillStatusAccount, fetchState } from "@across-protocol/contracts/dist/src/svm/clients/SvmSpoke";
|
|
3
3
|
import { decodeMessageHeader, hashNonEmptyMessage } from "@across-protocol/contracts/dist/src/svm/web3-v1";
|
|
4
|
-
import { intToU8Array32 } from "@across-protocol/contracts/dist/src/svm/web3-v1/conversionUtils";
|
|
5
4
|
import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
|
|
6
5
|
import {
|
|
7
6
|
ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
@@ -32,10 +31,11 @@ import {
|
|
|
32
31
|
signTransactionMessageWithSigners,
|
|
33
32
|
some,
|
|
34
33
|
type TransactionSigner,
|
|
34
|
+
type Commitment,
|
|
35
35
|
} from "@solana/kit";
|
|
36
36
|
import assert from "assert";
|
|
37
|
-
import
|
|
38
|
-
import {
|
|
37
|
+
import winston from "winston";
|
|
38
|
+
import { arrayify } from "ethers/lib/utils";
|
|
39
39
|
import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "../../constants";
|
|
40
40
|
import { DepositWithBlock, FillStatus, FillWithBlock, RelayData, RelayExecutionEventInfo } from "../../interfaces";
|
|
41
41
|
import {
|
|
@@ -54,7 +54,6 @@ import {
|
|
|
54
54
|
toAddressType,
|
|
55
55
|
} from "../../utils";
|
|
56
56
|
import {
|
|
57
|
-
bigToU8a32,
|
|
58
57
|
createDefaultTransaction,
|
|
59
58
|
getCCTPNoncePda,
|
|
60
59
|
getEventAuthority,
|
|
@@ -66,6 +65,7 @@ import {
|
|
|
66
65
|
toAddress,
|
|
67
66
|
unwrapEventData,
|
|
68
67
|
getRootBundlePda,
|
|
68
|
+
toSvmRelayData,
|
|
69
69
|
} from "./";
|
|
70
70
|
import { SvmCpiEventsClient } from "./eventsClient";
|
|
71
71
|
import { SVM_BLOCK_NOT_AVAILABLE, SVM_SLOT_SKIPPED, isSolanaError } from "./provider";
|
|
@@ -89,22 +89,51 @@ type ProtoFill = Omit<RelayData, "recipient" | "outputToken"> & {
|
|
|
89
89
|
outputToken: SvmAddress;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
+
export function getSlot(provider: SVMProvider, commitment: Commitment, logger: winston.Logger): Promise<bigint> {
|
|
93
|
+
return _callGetSlotWithRetry(provider, commitment, logger);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function _callGetSlotWithRetry(
|
|
97
|
+
provider: SVMProvider,
|
|
98
|
+
commitment: Commitment,
|
|
99
|
+
logger: winston.Logger
|
|
100
|
+
): Promise<bigint> {
|
|
101
|
+
try {
|
|
102
|
+
return await provider.getSlot({ commitment }).send();
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (isSolanaError(err)) {
|
|
105
|
+
const { __code: code } = err.context;
|
|
106
|
+
logger.debug({
|
|
107
|
+
at: "_getSlotWithRetry",
|
|
108
|
+
message: "Caught error from getSlot()",
|
|
109
|
+
code,
|
|
110
|
+
commitment,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// TODO: Implement retry logic once we better understand how these errors look:
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
/**
|
|
93
120
|
* Retrieves the chain time at a particular slot.
|
|
94
121
|
*/
|
|
95
122
|
export function getTimestampForSlot(
|
|
96
123
|
provider: SVMProvider,
|
|
97
124
|
slotNumber: bigint,
|
|
125
|
+
logger: winston.Logger,
|
|
98
126
|
maxRetries = 2
|
|
99
127
|
): Promise<number | undefined> {
|
|
100
|
-
return _callGetTimestampForSlotWithRetry(provider, slotNumber, 0, maxRetries);
|
|
128
|
+
return _callGetTimestampForSlotWithRetry(provider, slotNumber, 0, maxRetries, logger);
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
async function _callGetTimestampForSlotWithRetry(
|
|
104
132
|
provider: SVMProvider,
|
|
105
133
|
slotNumber: bigint,
|
|
106
134
|
retryAttempt: number,
|
|
107
|
-
maxRetries: number
|
|
135
|
+
maxRetries: number,
|
|
136
|
+
logger: winston.Logger
|
|
108
137
|
): Promise<number | undefined> {
|
|
109
138
|
// @note: getBlockTime receives a slot number, not a block number.
|
|
110
139
|
let _timestamp: bigint;
|
|
@@ -118,6 +147,7 @@ async function _callGetTimestampForSlotWithRetry(
|
|
|
118
147
|
|
|
119
148
|
const { __code: code } = err.context;
|
|
120
149
|
const slot = slotNumber.toString();
|
|
150
|
+
|
|
121
151
|
switch (err.context.__code) {
|
|
122
152
|
case SVM_SLOT_SKIPPED:
|
|
123
153
|
return undefined;
|
|
@@ -129,11 +159,27 @@ async function _callGetTimestampForSlotWithRetry(
|
|
|
129
159
|
if (retryAttempt >= maxRetries) {
|
|
130
160
|
throw new Error(`Timeout on SVM getBlockTime() for slot ${slot} after ${retryAttempt} retry attempts`);
|
|
131
161
|
}
|
|
162
|
+
logger.debug({
|
|
163
|
+
at: "getTimestampForSlot",
|
|
164
|
+
message: `Retrying getBlockTime() after ${delaySeconds} seconds for retry attempt #${retryAttempt}`,
|
|
165
|
+
slot,
|
|
166
|
+
retryAttempt,
|
|
167
|
+
maxRetries,
|
|
168
|
+
delaySeconds,
|
|
169
|
+
});
|
|
132
170
|
await delay(delaySeconds);
|
|
133
|
-
return _callGetTimestampForSlotWithRetry(provider, slotNumber, ++retryAttempt, maxRetries);
|
|
171
|
+
return _callGetTimestampForSlotWithRetry(provider, slotNumber, ++retryAttempt, maxRetries, logger);
|
|
134
172
|
}
|
|
135
173
|
|
|
136
174
|
default:
|
|
175
|
+
logger.debug({
|
|
176
|
+
at: "getTimestampForSlot",
|
|
177
|
+
message: "Caught error from getBlockTime()",
|
|
178
|
+
errorCode: code,
|
|
179
|
+
slot,
|
|
180
|
+
retryAttempt,
|
|
181
|
+
maxRetries,
|
|
182
|
+
});
|
|
137
183
|
throw new Error(`Unhandled SVM getBlockTime() error for slot ${slot}: ${code}`, { cause: err });
|
|
138
184
|
}
|
|
139
185
|
}
|
|
@@ -197,6 +243,7 @@ export function getDepositIdAtBlock(_contract: unknown, _blockTag: number): Prom
|
|
|
197
243
|
export async function findDeposit(
|
|
198
244
|
eventClient: SvmCpiEventsClient,
|
|
199
245
|
depositId: BigNumber,
|
|
246
|
+
logger: winston.Logger,
|
|
200
247
|
slot?: bigint,
|
|
201
248
|
secondsLookback = 2 * 24 * 60 * 60 // 2 days
|
|
202
249
|
): Promise<DepositWithBlock | undefined> {
|
|
@@ -206,7 +253,7 @@ export async function findDeposit(
|
|
|
206
253
|
}
|
|
207
254
|
|
|
208
255
|
const provider = eventClient.getRpc();
|
|
209
|
-
const { slot: currentSlot } = await getNearestSlotTime(provider);
|
|
256
|
+
const { slot: currentSlot } = await getNearestSlotTime(provider, logger);
|
|
210
257
|
|
|
211
258
|
// If no slot is provided, use the current slot
|
|
212
259
|
// If a slot is provided, ensure it's not in the future
|
|
@@ -264,6 +311,7 @@ export async function relayFillStatus(
|
|
|
264
311
|
relayData: RelayData,
|
|
265
312
|
destinationChainId: number,
|
|
266
313
|
svmEventsClient: SvmCpiEventsClient,
|
|
314
|
+
logger: winston.Logger,
|
|
267
315
|
atHeight?: number
|
|
268
316
|
): Promise<FillStatus> {
|
|
269
317
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
@@ -277,7 +325,7 @@ export async function relayFillStatus(
|
|
|
277
325
|
const commitment = "confirmed";
|
|
278
326
|
const [fillStatusAccount, { slot: currentSlot, timestamp }] = await Promise.all([
|
|
279
327
|
fetchEncodedAccount(provider, fillStatusPda, { commitment }),
|
|
280
|
-
getNearestSlotTime(provider, { commitment }),
|
|
328
|
+
getNearestSlotTime(provider, logger, { commitment }),
|
|
281
329
|
]);
|
|
282
330
|
toSlot = currentSlot;
|
|
283
331
|
|
|
@@ -314,8 +362,8 @@ export async function fillStatusArray(
|
|
|
314
362
|
relayData: RelayData[],
|
|
315
363
|
destinationChainId: number,
|
|
316
364
|
svmEventsClient: SvmCpiEventsClient,
|
|
317
|
-
|
|
318
|
-
|
|
365
|
+
logger: winston.Logger,
|
|
366
|
+
atHeight?: number
|
|
319
367
|
): Promise<(FillStatus | undefined)[]> {
|
|
320
368
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
321
369
|
const provider = svmEventsClient.getRpc();
|
|
@@ -343,7 +391,7 @@ export async function fillStatusArray(
|
|
|
343
391
|
// Otherwise, initialize all statuses as undefined
|
|
344
392
|
const fillStatuses: (FillStatus | undefined)[] =
|
|
345
393
|
atHeight === undefined
|
|
346
|
-
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData)
|
|
394
|
+
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData, logger)
|
|
347
395
|
: new Array(relayData.length).fill(undefined);
|
|
348
396
|
|
|
349
397
|
// Collect indices of deposits that still need their status resolved
|
|
@@ -359,7 +407,7 @@ export async function fillStatusArray(
|
|
|
359
407
|
const missingResults: { index: number; fillStatus: FillStatus }[] = [];
|
|
360
408
|
|
|
361
409
|
// Determine the toSlot to use for event reconstruction
|
|
362
|
-
const toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider)).slot;
|
|
410
|
+
const toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider, logger)).slot;
|
|
363
411
|
|
|
364
412
|
// @note: This path is mostly used for deposits past their fill deadline.
|
|
365
413
|
// If it becomes a bottleneck, consider returning an "Unknown" status that can be handled downstream.
|
|
@@ -397,11 +445,12 @@ export async function findFillEvent(
|
|
|
397
445
|
relayData: RelayData,
|
|
398
446
|
destinationChainId: number,
|
|
399
447
|
svmEventsClient: SvmCpiEventsClient,
|
|
448
|
+
logger: winston.Logger,
|
|
400
449
|
fromSlot: number,
|
|
401
450
|
toSlot?: number
|
|
402
451
|
): Promise<FillWithBlock | undefined> {
|
|
403
452
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
404
|
-
toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc())).slot);
|
|
453
|
+
toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc(), logger)).slot);
|
|
405
454
|
|
|
406
455
|
// Get fillStatus PDA using relayData
|
|
407
456
|
const programId = svmEventsClient.getProgramAddress();
|
|
@@ -465,11 +514,10 @@ export async function fillRelayInstruction(
|
|
|
465
514
|
relayData: ProtoFill,
|
|
466
515
|
signer: TransactionSigner<string>,
|
|
467
516
|
recipientTokenAccount: Address<string>,
|
|
468
|
-
repaymentAddress: EvmAddress | SvmAddress
|
|
469
|
-
repaymentChainId
|
|
517
|
+
repaymentAddress: EvmAddress | SvmAddress,
|
|
518
|
+
repaymentChainId: number
|
|
470
519
|
) {
|
|
471
520
|
const program = toAddress(spokePool);
|
|
472
|
-
|
|
473
521
|
assert(
|
|
474
522
|
repaymentAddress.isValidOn(repaymentChainId),
|
|
475
523
|
`Invalid repayment address for chain ${repaymentChainId}: ${repaymentAddress.toNative()}.`
|
|
@@ -480,61 +528,29 @@ export async function fillRelayInstruction(
|
|
|
480
528
|
|
|
481
529
|
const relayer = SvmAddress.from(signer.address);
|
|
482
530
|
|
|
483
|
-
|
|
484
|
-
const relayerTokenAccount = await getAssociatedTokenAddress(relayer, relayData.outputToken);
|
|
485
|
-
|
|
486
|
-
const [statePda, fillStatusPda, eventAuthority] = await Promise.all([
|
|
531
|
+
const [statePda, fillStatusPda, eventAuthority, delegatePda, relayerTokenAccount] = await Promise.all([
|
|
487
532
|
getStatePda(program),
|
|
488
533
|
getFillStatusPda(program, relayData, relayData.destinationChainId),
|
|
489
534
|
getEventAuthority(program),
|
|
535
|
+
getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), signer.address, program),
|
|
536
|
+
getAssociatedTokenAddress(relayer, relayData.outputToken),
|
|
490
537
|
]);
|
|
491
538
|
|
|
492
|
-
const
|
|
493
|
-
const shortenedBuffer = new Uint8Array(Buffer.from(relayData.depositId.toHexString().slice(2), "hex"));
|
|
494
|
-
depositIdBuffer.set(shortenedBuffer, 32 - shortenedBuffer.length);
|
|
495
|
-
|
|
496
|
-
const delegatePda = await getFillRelayDelegatePda(
|
|
497
|
-
relayDataHash,
|
|
498
|
-
BigInt(repaymentChainId),
|
|
499
|
-
toAddress(relayer),
|
|
500
|
-
program
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
const [recipient, outputToken, exclusiveRelayer, depositor, inputToken] = [
|
|
504
|
-
relayData.recipient,
|
|
505
|
-
relayData.outputToken,
|
|
506
|
-
relayData.exclusiveRelayer,
|
|
507
|
-
relayData.depositor,
|
|
508
|
-
relayData.inputToken,
|
|
509
|
-
].map(toAddress);
|
|
510
|
-
|
|
539
|
+
const svmRelayData = toSvmRelayData(relayData);
|
|
511
540
|
return SvmSpokeClient.getFillRelayInstruction({
|
|
512
541
|
signer,
|
|
513
542
|
state: statePda,
|
|
514
543
|
delegate: toAddress(SvmAddress.from(delegatePda.toString())),
|
|
515
|
-
mint: outputToken,
|
|
544
|
+
mint: svmRelayData.outputToken,
|
|
516
545
|
relayerTokenAccount: relayerTokenAccount,
|
|
517
546
|
recipientTokenAccount: recipientTokenAccount,
|
|
518
547
|
fillStatus: fillStatusPda,
|
|
519
548
|
eventAuthority,
|
|
520
549
|
program,
|
|
521
550
|
relayHash: relayDataHash,
|
|
522
|
-
relayData: some(
|
|
523
|
-
depositor,
|
|
524
|
-
recipient,
|
|
525
|
-
exclusiveRelayer,
|
|
526
|
-
inputToken,
|
|
527
|
-
outputToken,
|
|
528
|
-
inputAmount: bigToU8a32(relayData.inputAmount.toBigInt()),
|
|
529
|
-
outputAmount: relayData.outputAmount.toBigInt(),
|
|
530
|
-
originChainId: BigInt(relayData.originChainId),
|
|
531
|
-
fillDeadline: relayData.fillDeadline,
|
|
532
|
-
exclusivityDeadline: relayData.exclusivityDeadline,
|
|
533
|
-
depositId: depositIdBuffer,
|
|
534
|
-
message: new Uint8Array(Buffer.from(relayData.message.slice(2), "hex")),
|
|
535
|
-
}),
|
|
551
|
+
relayData: some(svmRelayData),
|
|
536
552
|
repaymentChainId: some(BigInt(repaymentChainId)),
|
|
537
|
-
repaymentAddress: toAddress(repaymentAddress),
|
|
553
|
+
repaymentAddress: some(toAddress(repaymentAddress)),
|
|
538
554
|
});
|
|
539
555
|
}
|
|
540
556
|
|
|
@@ -575,7 +591,7 @@ export async function getFillRelayTx(
|
|
|
575
591
|
repaymentChainId: number,
|
|
576
592
|
repaymentAddress: SdkAddress
|
|
577
593
|
) {
|
|
578
|
-
const
|
|
594
|
+
const svmRelayData = toSvmRelayData(relayData);
|
|
579
595
|
|
|
580
596
|
assert(
|
|
581
597
|
repaymentAddress.isValidOn(repaymentChainId),
|
|
@@ -583,44 +599,27 @@ export async function getFillRelayTx(
|
|
|
583
599
|
);
|
|
584
600
|
|
|
585
601
|
const program = toAddress(spokePoolAddr);
|
|
586
|
-
const _relayDataHash = getRelayDataHash(relayData, destinationChainId);
|
|
602
|
+
const _relayDataHash = getRelayDataHash(relayData, relayData.destinationChainId);
|
|
587
603
|
const relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));
|
|
588
604
|
|
|
589
|
-
const [state, delegate] = await Promise.all([
|
|
605
|
+
const [state, delegate, mintInfo, fillStatus, eventAuthority] = await Promise.all([
|
|
590
606
|
getStatePda(program),
|
|
591
607
|
getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), toAddress(repaymentAddress), program),
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const mint = toAddress(outputToken);
|
|
595
|
-
const mintInfo = await getMintInfo(solanaClient, mint);
|
|
596
|
-
|
|
597
|
-
const [recipientAta, relayerAta, fillStatus, eventAuthority] = await Promise.all([
|
|
598
|
-
getAssociatedTokenAddress(recipient, outputToken, mintInfo.programAddress),
|
|
599
|
-
getAssociatedTokenAddress(SvmAddress.from(signer.address), outputToken, mintInfo.programAddress),
|
|
600
|
-
getFillStatusPda(program, relayData, destinationChainId),
|
|
608
|
+
getMintInfo(solanaClient, svmRelayData.outputToken),
|
|
609
|
+
getFillStatusPda(program, relayData, relayData.destinationChainId),
|
|
601
610
|
getEventAuthority(program),
|
|
602
611
|
]);
|
|
603
612
|
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
inputToken: toAddress(inputToken),
|
|
609
|
-
outputToken: mint,
|
|
610
|
-
inputAmount: bigToU8a32(relayData.inputAmount.toBigInt()),
|
|
611
|
-
outputAmount: relayData.outputAmount.toBigInt(),
|
|
612
|
-
originChainId: relayData.originChainId,
|
|
613
|
-
depositId: new Uint8Array(intToU8Array32(relayData.depositId.toNumber())),
|
|
614
|
-
fillDeadline: relayData.fillDeadline,
|
|
615
|
-
exclusivityDeadline: relayData.exclusivityDeadline,
|
|
616
|
-
message: new Uint8Array(Buffer.from(relayData.message, "hex")),
|
|
617
|
-
};
|
|
613
|
+
const [recipientAta, relayerAta] = await Promise.all([
|
|
614
|
+
getAssociatedTokenAddress(relayData.recipient, relayData.outputToken, mintInfo.programAddress),
|
|
615
|
+
getAssociatedTokenAddress(SvmAddress.from(signer.address), relayData.outputToken, mintInfo.programAddress),
|
|
616
|
+
]);
|
|
618
617
|
|
|
619
618
|
const fillInput: SvmSpokeClient.FillRelayInput = {
|
|
620
619
|
signer: signer,
|
|
621
620
|
state,
|
|
622
621
|
delegate,
|
|
623
|
-
mint,
|
|
622
|
+
mint: svmRelayData.outputToken,
|
|
624
623
|
relayerTokenAccount: relayerAta,
|
|
625
624
|
recipientTokenAccount: recipientAta,
|
|
626
625
|
fillStatus,
|
|
@@ -777,48 +776,16 @@ export async function getSlowFillRequestTx(
|
|
|
777
776
|
},
|
|
778
777
|
signer: TransactionSigner
|
|
779
778
|
) {
|
|
780
|
-
const {
|
|
781
|
-
depositor,
|
|
782
|
-
recipient,
|
|
783
|
-
inputToken,
|
|
784
|
-
outputToken,
|
|
785
|
-
exclusiveRelayer,
|
|
786
|
-
destinationChainId,
|
|
787
|
-
originChainId,
|
|
788
|
-
depositId,
|
|
789
|
-
fillDeadline,
|
|
790
|
-
exclusivityDeadline,
|
|
791
|
-
message,
|
|
792
|
-
} = relayData;
|
|
793
|
-
|
|
794
779
|
const program = toAddress(spokePoolAddr);
|
|
795
|
-
const relayDataHash = getRelayDataHash(relayData, destinationChainId);
|
|
780
|
+
const relayDataHash = getRelayDataHash(relayData, relayData.destinationChainId);
|
|
796
781
|
|
|
797
782
|
const [state, fillStatus, eventAuthority] = await Promise.all([
|
|
798
783
|
getStatePda(program),
|
|
799
|
-
getFillStatusPda(program, relayData, destinationChainId),
|
|
784
|
+
getFillStatusPda(program, relayData, relayData.destinationChainId),
|
|
800
785
|
getEventAuthority(program),
|
|
801
786
|
]);
|
|
802
787
|
|
|
803
|
-
const
|
|
804
|
-
const shortenedBuffer = arrayify(depositId.toHexString());
|
|
805
|
-
depositIdBuffer.set(shortenedBuffer, 32 - shortenedBuffer.length);
|
|
806
|
-
|
|
807
|
-
const relayDataInput: SvmSpokeClient.RequestSlowFillInput["relayData"] = {
|
|
808
|
-
depositor: toAddress(depositor),
|
|
809
|
-
recipient: toAddress(recipient),
|
|
810
|
-
exclusiveRelayer: toAddress(exclusiveRelayer),
|
|
811
|
-
inputToken: toAddress(inputToken),
|
|
812
|
-
outputToken: toAddress(outputToken),
|
|
813
|
-
inputAmount: bigToU8a32(relayData.inputAmount.toBigInt()),
|
|
814
|
-
outputAmount: relayData.outputAmount.toBigInt(),
|
|
815
|
-
originChainId: BigInt(originChainId),
|
|
816
|
-
depositId: depositIdBuffer,
|
|
817
|
-
fillDeadline: fillDeadline,
|
|
818
|
-
exclusivityDeadline: exclusivityDeadline,
|
|
819
|
-
message: arrayify(message),
|
|
820
|
-
};
|
|
821
|
-
|
|
788
|
+
const svmRelayData = toSvmRelayData(relayData);
|
|
822
789
|
const requestSlowFillInput: SvmSpokeClient.RequestSlowFillInput = {
|
|
823
790
|
signer,
|
|
824
791
|
state,
|
|
@@ -826,7 +793,7 @@ export async function getSlowFillRequestTx(
|
|
|
826
793
|
eventAuthority,
|
|
827
794
|
program,
|
|
828
795
|
relayHash: arrayify(relayDataHash),
|
|
829
|
-
relayData:
|
|
796
|
+
relayData: svmRelayData,
|
|
830
797
|
systemProgram: SYSTEM_PROGRAM_ADDRESS,
|
|
831
798
|
};
|
|
832
799
|
|
|
@@ -882,28 +849,23 @@ export async function getAssociatedTokenAddress(
|
|
|
882
849
|
}
|
|
883
850
|
|
|
884
851
|
export function getRelayDataHash(relayData: RelayData, destinationChainId: number): string {
|
|
885
|
-
|
|
852
|
+
assert(relayData.message.startsWith("0x"), "Message must be a hex string");
|
|
886
853
|
const uint64Encoder = getU64Encoder();
|
|
887
|
-
const uint32Encoder = getU32Encoder();
|
|
888
854
|
|
|
889
|
-
|
|
890
|
-
const
|
|
855
|
+
const svmRelayData = toSvmRelayData(relayData);
|
|
856
|
+
const relayDataEncoder = SvmSpokeClient.getRelayDataEncoder();
|
|
857
|
+
const encodedRelayData = relayDataEncoder.encode(svmRelayData);
|
|
858
|
+
const encodedMessage = Buffer.from(relayData.message.slice(2), "hex");
|
|
891
859
|
|
|
860
|
+
// Reformat the encoded relay data the same way it is done in the SvmSpoke:
|
|
861
|
+
// https://github.com/across-protocol/contracts/blob/3310f8dc716407a5f97ef5fd2eae63df83251f2f/programs/svm-spoke/src/utils/merkle_proof_utils.rs#L5
|
|
862
|
+
const messageOffset = encodedRelayData.length - 4 - encodedMessage.length;
|
|
892
863
|
const contentToHash = Buffer.concat([
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
encodeAddress(relayData.exclusiveRelayer),
|
|
896
|
-
encodeAddress(relayData.inputToken),
|
|
897
|
-
encodeAddress(relayData.outputToken),
|
|
898
|
-
arrayify(hexZeroPad(hexlify(relayData.inputAmount), 32)),
|
|
899
|
-
Uint8Array.from(uint64Encoder.encode(BigInt(relayData.outputAmount.toString()))),
|
|
900
|
-
Uint8Array.from(uint64Encoder.encode(BigInt(relayData.originChainId.toString()))),
|
|
901
|
-
arrayify(hexZeroPad(hexlify(relayData.depositId), 32)),
|
|
902
|
-
Uint8Array.from(uint32Encoder.encode(relayData.fillDeadline)),
|
|
903
|
-
Uint8Array.from(uint32Encoder.encode(relayData.exclusivityDeadline)),
|
|
904
|
-
hashNonEmptyMessage(Buffer.from(arrayify(relayData.message))),
|
|
864
|
+
encodedRelayData.slice(0, messageOffset),
|
|
865
|
+
hashNonEmptyMessage(encodedMessage),
|
|
905
866
|
Uint8Array.from(uint64Encoder.encode(BigInt(destinationChainId))),
|
|
906
867
|
]);
|
|
868
|
+
|
|
907
869
|
return keccak256(contentToHash);
|
|
908
870
|
}
|
|
909
871
|
|
|
@@ -961,14 +923,15 @@ async function resolveFillStatusFromPdaEvents(
|
|
|
961
923
|
async function fetchBatchFillStatusFromPdaAccounts(
|
|
962
924
|
provider: SVMProvider,
|
|
963
925
|
fillStatusPdas: Address[],
|
|
964
|
-
relayDataArray: RelayData[]
|
|
926
|
+
relayDataArray: RelayData[],
|
|
927
|
+
logger: winston.Logger
|
|
965
928
|
): Promise<(FillStatus | undefined)[]> {
|
|
966
929
|
const chunkSize = 100; // SVM method getMultipleAccounts allows a max of 100 addresses per request
|
|
967
930
|
const commitment = "confirmed";
|
|
968
931
|
|
|
969
932
|
const [pdaAccounts, { timestamp }] = await Promise.all([
|
|
970
933
|
Promise.all(chunk(fillStatusPdas, chunkSize).map((chunk) => fetchEncodedAccounts(provider, chunk, { commitment }))),
|
|
971
|
-
getNearestSlotTime(provider, { commitment }),
|
|
934
|
+
getNearestSlotTime(provider, logger, { commitment }),
|
|
972
935
|
]);
|
|
973
936
|
|
|
974
937
|
const fillStatuses = pdaAccounts.flat().map((account, index) => {
|
package/src/arch/svm/provider.ts
CHANGED
|
@@ -6,4 +6,5 @@ export {
|
|
|
6
6
|
isSolanaError,
|
|
7
7
|
SOLANA_ERROR__JSON_RPC__SERVER_ERROR_BLOCK_NOT_AVAILABLE as SVM_BLOCK_NOT_AVAILABLE,
|
|
8
8
|
SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SLOT_SKIPPED as SVM_SLOT_SKIPPED,
|
|
9
|
+
SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE as SVM_TRANSACTION_PREFLIGHT_FAILURE,
|
|
9
10
|
} from "@solana/kit";
|
package/src/arch/svm/utils.ts
CHANGED
|
@@ -25,8 +25,9 @@ import bs58 from "bs58";
|
|
|
25
25
|
import { ethers } from "ethers";
|
|
26
26
|
import { FillType, RelayData } from "../../interfaces";
|
|
27
27
|
import { BigNumber, Address as SdkAddress, biMin, getRelayDataHash, isDefined, isUint8Array } from "../../utils";
|
|
28
|
-
import { getTimestampForSlot } from "./SpokeUtils";
|
|
28
|
+
import { getTimestampForSlot, getSlot } from "./SpokeUtils";
|
|
29
29
|
import { AttestedCCTPMessage, EventName, SVMEventNames, SVMProvider } from "./types";
|
|
30
|
+
import winston from "winston";
|
|
30
31
|
|
|
31
32
|
export { isSolanaError } from "@solana/kit";
|
|
32
33
|
|
|
@@ -67,13 +68,14 @@ export function toAddress(address: SdkAddress): Address<string> {
|
|
|
67
68
|
*/
|
|
68
69
|
export async function getNearestSlotTime(
|
|
69
70
|
provider: SVMProvider,
|
|
71
|
+
logger: winston.Logger,
|
|
70
72
|
opts: { slot: bigint } | { commitment: Commitment } = { commitment: "confirmed" }
|
|
71
73
|
): Promise<{ slot: bigint; timestamp: number }> {
|
|
72
74
|
let timestamp: number | undefined;
|
|
73
|
-
let slot = "slot" in opts ? opts.slot : await
|
|
75
|
+
let slot = "slot" in opts ? opts.slot : await getSlot(provider, opts.commitment, logger);
|
|
74
76
|
|
|
75
77
|
do {
|
|
76
|
-
timestamp = await getTimestampForSlot(provider, slot);
|
|
78
|
+
timestamp = await getTimestampForSlot(provider, slot, logger);
|
|
77
79
|
} while (!isDefined(timestamp) && --slot);
|
|
78
80
|
assert(isDefined(timestamp), `Unable to resolve block time for SVM slot ${slot}`);
|
|
79
81
|
|
|
@@ -87,11 +89,12 @@ export async function getNearestSlotTime(
|
|
|
87
89
|
*/
|
|
88
90
|
export async function getLatestFinalizedSlotWithBlock(
|
|
89
91
|
provider: SVMProvider,
|
|
92
|
+
logger: winston.Logger,
|
|
90
93
|
maxSlot: bigint,
|
|
91
94
|
maxLookback = 1000
|
|
92
95
|
): Promise<number> {
|
|
93
96
|
const opts = { maxSupportedTransactionVersion: 0, transactionDetails: "none", rewards: false } as const;
|
|
94
|
-
const { slot: finalizedSlot } = await getNearestSlotTime(provider, { commitment: "finalized" });
|
|
97
|
+
const { slot: finalizedSlot } = await getNearestSlotTime(provider, logger, { commitment: "finalized" });
|
|
95
98
|
const endSlot = biMin(maxSlot, finalizedSlot);
|
|
96
99
|
|
|
97
100
|
let slot = endSlot;
|
|
@@ -430,6 +433,29 @@ export const simulateAndDecode = async <P extends (buf: Buffer) => unknown>(
|
|
|
430
433
|
return parser(Buffer.from(simulationResult.value.returnData.data[0], "base64")) as ReturnType<P>;
|
|
431
434
|
};
|
|
432
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Converts a common `RelayData` type to an SvmSpokeClient.RelayData` type. This is useful for when we need
|
|
438
|
+
* to interface directly with the SvmSpoke.
|
|
439
|
+
* @param relayData The common RelayData TS type.
|
|
440
|
+
* @returns RelayData which conforms to the typing of the SvmSpoke.
|
|
441
|
+
*/
|
|
442
|
+
export function toSvmRelayData(relayData: RelayData): SvmSpokeClient.RelayData {
|
|
443
|
+
return {
|
|
444
|
+
originChainId: BigInt(relayData.originChainId),
|
|
445
|
+
depositor: address(relayData.depositor.toBase58()),
|
|
446
|
+
recipient: address(relayData.recipient.toBase58()),
|
|
447
|
+
depositId: ethers.utils.arrayify(ethers.utils.hexZeroPad(relayData.depositId.toHexString(), 32)),
|
|
448
|
+
inputToken: address(relayData.inputToken.toBase58()),
|
|
449
|
+
outputToken: address(relayData.outputToken.toBase58()),
|
|
450
|
+
inputAmount: ethers.utils.arrayify(ethers.utils.hexZeroPad(relayData.inputAmount.toHexString(), 32)),
|
|
451
|
+
outputAmount: relayData.outputAmount.toBigInt(),
|
|
452
|
+
message: Uint8Array.from(Buffer.from(relayData.message.slice(2), "hex")),
|
|
453
|
+
fillDeadline: relayData.fillDeadline,
|
|
454
|
+
exclusiveRelayer: address(relayData.exclusiveRelayer.toBase58()),
|
|
455
|
+
exclusivityDeadline: relayData.exclusivityDeadline,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
433
459
|
/**
|
|
434
460
|
* Returns the PDA for the CCTP nonce.
|
|
435
461
|
* @param solanaClient The Solana client.
|
|
@@ -101,7 +101,7 @@ export class ArweaveClient {
|
|
|
101
101
|
const transactionUrl = `${this.gatewayUrl}/${transactionID}`;
|
|
102
102
|
// We should query in via Axios directly to the gateway URL. The reasoning behind this is
|
|
103
103
|
// that the Arweave SDK's `getData` method is too slow and does not provide a way to set a timeout.
|
|
104
|
-
// Therefore, something that could take
|
|
104
|
+
// Therefore, something that could take milliseconds to complete could take tens of minutes.
|
|
105
105
|
const { data, status: responseStatus } = await axios.get<Record<string, unknown>>(transactionUrl);
|
|
106
106
|
// Ensure that the result is successful. If it is not, the retrieved value is not our expected type
|
|
107
107
|
// but rather a {status: string, statusText: string} object. We can detect that and return null.
|
|
@@ -2,6 +2,7 @@ import { providers } from "ethers";
|
|
|
2
2
|
import { CachingMechanismInterface } from "../interfaces";
|
|
3
3
|
import { EventSearchConfig, isDefined, MakeOptional } from "../utils";
|
|
4
4
|
import { getNearestSlotTime, SVMProvider } from "../arch/svm";
|
|
5
|
+
import winston from "winston";
|
|
5
6
|
|
|
6
7
|
export enum UpdateFailureReason {
|
|
7
8
|
NotReady,
|
|
@@ -59,9 +60,7 @@ export abstract class BaseAbstractClient {
|
|
|
59
60
|
* @provider Ethers RPC provider instance.
|
|
60
61
|
* @returns An EventSearchConfig instance if valid, otherwise an UpdateFailureReason.
|
|
61
62
|
*/
|
|
62
|
-
public async updateSearchConfig(
|
|
63
|
-
provider: providers.Provider | SVMProvider
|
|
64
|
-
): Promise<EventSearchConfig | UpdateFailureReason> {
|
|
63
|
+
public async updateSearchConfig(provider: providers.Provider): Promise<EventSearchConfig | UpdateFailureReason> {
|
|
65
64
|
const from = this.firstHeightToSearch;
|
|
66
65
|
let { to } = this.eventSearchConfig;
|
|
67
66
|
if (isDefined(to)) {
|
|
@@ -69,12 +68,29 @@ export abstract class BaseAbstractClient {
|
|
|
69
68
|
throw new Error(`Invalid event search config from (${from}) > to (${to})`);
|
|
70
69
|
}
|
|
71
70
|
} else {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const { slot } = await getNearestSlotTime(provider);
|
|
76
|
-
to = Number(slot);
|
|
71
|
+
to = await provider.getBlockNumber();
|
|
72
|
+
if (to < from) {
|
|
73
|
+
return UpdateFailureReason.AlreadyUpdated;
|
|
77
74
|
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { maxLookBack } = this.eventSearchConfig;
|
|
78
|
+
return { from, to, maxLookBack };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async updateSvmSearchConfig(
|
|
82
|
+
provider: SVMProvider,
|
|
83
|
+
logger: winston.Logger
|
|
84
|
+
): Promise<EventSearchConfig | UpdateFailureReason> {
|
|
85
|
+
const from = this.firstHeightToSearch;
|
|
86
|
+
let { to } = this.eventSearchConfig;
|
|
87
|
+
if (isDefined(to)) {
|
|
88
|
+
if (from > to) {
|
|
89
|
+
throw new Error(`Invalid event search config from (${from}) > to (${to})`);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const { slot } = await getNearestSlotTime(provider, logger);
|
|
93
|
+
to = Number(slot);
|
|
78
94
|
if (to < from) {
|
|
79
95
|
return UpdateFailureReason.AlreadyUpdated;
|
|
80
96
|
}
|
|
@@ -41,7 +41,11 @@ export async function getWidestPossibleExpectedBlockRange(
|
|
|
41
41
|
assert(isSVMSpokePoolClient(spokePoolClient));
|
|
42
42
|
|
|
43
43
|
const maxSlot = resolveEndBlock(chainId, idx); // Respect any configured buffer for Solana.
|
|
44
|
-
return getLatestFinalizedSlotWithBlock(
|
|
44
|
+
return getLatestFinalizedSlotWithBlock(
|
|
45
|
+
spokePoolClient.svmEventsClient.getRpc(),
|
|
46
|
+
spokePoolClient.logger,
|
|
47
|
+
BigInt(maxSlot)
|
|
48
|
+
);
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
const latestPossibleBundleEndBlockNumbers = await Promise.all(
|
|
@@ -115,7 +115,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
115
115
|
* Performs an update to refresh the state of this client by querying SVM events.
|
|
116
116
|
*/
|
|
117
117
|
protected async _update(eventsToQuery: string[]): Promise<SpokePoolUpdate> {
|
|
118
|
-
const searchConfig = await this.
|
|
118
|
+
const searchConfig = await this.updateSvmSearchConfig(this.svmEventsClient.getRpc(), this.logger);
|
|
119
119
|
if (isUpdateFailureReason(searchConfig)) {
|
|
120
120
|
const reason = searchConfig;
|
|
121
121
|
return { success: false, reason };
|
|
@@ -195,7 +195,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
195
195
|
public override async getTimestampForBlock(slot: number): Promise<number> {
|
|
196
196
|
let _slot = BigInt(slot);
|
|
197
197
|
do {
|
|
198
|
-
const timestamp = await getTimestampForSlot(this.svmEventsClient.getRpc(), _slot);
|
|
198
|
+
const timestamp = await getTimestampForSlot(this.svmEventsClient.getRpc(), _slot, this.logger);
|
|
199
199
|
if (isDefined(timestamp)) {
|
|
200
200
|
return timestamp;
|
|
201
201
|
}
|
|
@@ -217,7 +217,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
217
217
|
* Finds a deposit based on its deposit ID on the SVM chain.
|
|
218
218
|
*/
|
|
219
219
|
public async findDeposit(depositId: BigNumber): Promise<DepositSearchResult> {
|
|
220
|
-
const deposit = await findDeposit(this.svmEventsClient, depositId);
|
|
220
|
+
const deposit = await findDeposit(this.svmEventsClient, depositId, this.logger);
|
|
221
221
|
if (!deposit) {
|
|
222
222
|
return {
|
|
223
223
|
found: false,
|
|
@@ -244,7 +244,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
244
244
|
* Retrieves the fill status for a given relay data from the SVM chain.
|
|
245
245
|
*/
|
|
246
246
|
public override relayFillStatus(relayData: RelayData, atHeight?: number): Promise<FillStatus> {
|
|
247
|
-
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, atHeight);
|
|
247
|
+
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, this.logger, atHeight);
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
/**
|
|
@@ -260,6 +260,6 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
260
260
|
): Promise<(FillStatus | undefined)[]> {
|
|
261
261
|
// @note: deploymentBlock actually refers to the deployment slot. Also, blockTag should be a slot number.
|
|
262
262
|
destinationChainId ??= this.chainId;
|
|
263
|
-
return fillStatusArray(this.programId, relayData, destinationChainId, this.svmEventsClient,
|
|
263
|
+
return fillStatusArray(this.programId, relayData, destinationChainId, this.svmEventsClient, this.logger, atHeight);
|
|
264
264
|
}
|
|
265
265
|
}
|