@across-protocol/sdk 4.3.71 → 4.3.73
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/SpokeUtils.d.ts +2 -2
- package/dist/cjs/arch/svm/SpokeUtils.js +3 -3
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/provider.d.ts +12 -1
- package/dist/cjs/arch/svm/provider.js +17 -6
- package/dist/cjs/arch/svm/provider.js.map +1 -1
- package/dist/cjs/arch/svm/types.d.ts +5 -1
- package/dist/cjs/arch/svm/types.js.map +1 -1
- package/dist/cjs/arch/svm/utils.d.ts +4 -5
- package/dist/cjs/arch/svm/utils.js +19 -14
- package/dist/cjs/arch/svm/utils.js.map +1 -1
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.d.ts +1 -1
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js +7 -3
- package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js.map +1 -1
- package/dist/cjs/providers/solana/retryRpcFactory.d.ts +1 -2
- package/dist/cjs/providers/solana/retryRpcFactory.js +4 -16
- package/dist/cjs/providers/solana/retryRpcFactory.js.map +1 -1
- package/dist/cjs/providers/solana/utils.d.ts +1 -0
- package/dist/cjs/providers/solana/utils.js +15 -0
- package/dist/cjs/providers/solana/utils.js.map +1 -1
- package/dist/esm/arch/svm/SpokeUtils.d.ts +2 -2
- package/dist/esm/arch/svm/SpokeUtils.js +3 -3
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/provider.d.ts +28 -1
- package/dist/esm/arch/svm/provider.js +29 -1
- package/dist/esm/arch/svm/provider.js.map +1 -1
- package/dist/esm/arch/svm/types.d.ts +5 -1
- package/dist/esm/arch/svm/types.js.map +1 -1
- package/dist/esm/arch/svm/utils.d.ts +4 -5
- package/dist/esm/arch/svm/utils.js +18 -12
- package/dist/esm/arch/svm/utils.js.map +1 -1
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.d.ts +1 -1
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.js +8 -3
- package/dist/esm/providers/solana/quorumFallbackRpcFactory.js.map +1 -1
- package/dist/esm/providers/solana/retryRpcFactory.d.ts +1 -8
- package/dist/esm/providers/solana/retryRpcFactory.js +4 -24
- package/dist/esm/providers/solana/retryRpcFactory.js.map +1 -1
- package/dist/esm/providers/solana/utils.d.ts +7 -0
- package/dist/esm/providers/solana/utils.js +22 -1
- package/dist/esm/providers/solana/utils.js.map +1 -1
- package/dist/types/arch/svm/SpokeUtils.d.ts +2 -2
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/provider.d.ts +28 -1
- package/dist/types/arch/svm/provider.d.ts.map +1 -1
- package/dist/types/arch/svm/types.d.ts +5 -1
- package/dist/types/arch/svm/types.d.ts.map +1 -1
- package/dist/types/arch/svm/utils.d.ts +4 -5
- package/dist/types/arch/svm/utils.d.ts.map +1 -1
- package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts +1 -1
- package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/solana/retryRpcFactory.d.ts +1 -8
- package/dist/types/providers/solana/retryRpcFactory.d.ts.map +1 -1
- package/dist/types/providers/solana/utils.d.ts +7 -0
- package/dist/types/providers/solana/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/arch/svm/SpokeUtils.ts +5 -4
- package/src/arch/svm/provider.ts +46 -1
- package/src/arch/svm/types.ts +6 -0
- package/src/arch/svm/utils.ts +17 -11
- package/src/providers/solana/quorumFallbackRpcFactory.ts +10 -4
- package/src/providers/solana/retryRpcFactory.ts +5 -27
- package/src/providers/solana/utils.ts +24 -0
package/src/arch/svm/utils.ts
CHANGED
|
@@ -26,11 +26,8 @@ import { ethers } from "ethers";
|
|
|
26
26
|
import { FillType, RelayData, RelayDataWithMessageHash } from "../../interfaces";
|
|
27
27
|
import { BigNumber, Address as SdkAddress, biMin, getMessageHash, isDefined, isUint8Array } from "../../utils";
|
|
28
28
|
import { getTimestampForSlot, getSlot, getRelayDataHash } from "./SpokeUtils";
|
|
29
|
-
import { AttestedCCTPMessage, EventName, SVMEventNames, SVMProvider } from "./types";
|
|
29
|
+
import { AttestedCCTPMessage, EventName, SVMEventNames, SVMProvider, LatestBlockhash } from "./types";
|
|
30
30
|
import winston from "winston";
|
|
31
|
-
|
|
32
|
-
export { isSolanaError } from "@solana/kit";
|
|
33
|
-
|
|
34
31
|
/**
|
|
35
32
|
* Basic void TransactionSigner type
|
|
36
33
|
*/
|
|
@@ -397,12 +394,16 @@ export function getRandomSvmAddress() {
|
|
|
397
394
|
* @param signer - The signer of the transaction.
|
|
398
395
|
* @returns The default transaction.
|
|
399
396
|
*/
|
|
400
|
-
export const createDefaultTransaction = async (
|
|
401
|
-
|
|
397
|
+
export const createDefaultTransaction = async (
|
|
398
|
+
rpcClient: SVMProvider,
|
|
399
|
+
signer: TransactionSigner,
|
|
400
|
+
latestBlockhash?: LatestBlockhash
|
|
401
|
+
) => {
|
|
402
|
+
latestBlockhash = isDefined(latestBlockhash) ? latestBlockhash : (await rpcClient.getLatestBlockhash().send()).value;
|
|
402
403
|
return pipe(
|
|
403
404
|
createTransactionMessage({ version: 0 }),
|
|
404
405
|
(tx) => setTransactionMessageFeePayerSigner(signer, tx),
|
|
405
|
-
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash
|
|
406
|
+
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash!, tx)
|
|
406
407
|
);
|
|
407
408
|
};
|
|
408
409
|
|
|
@@ -418,9 +419,13 @@ export const simulateAndDecode = async <P extends (buf: Buffer) => unknown>(
|
|
|
418
419
|
solanaClient: SVMProvider,
|
|
419
420
|
ix: IInstruction,
|
|
420
421
|
signer: KeyPairSigner,
|
|
421
|
-
parser: P
|
|
422
|
+
parser: P,
|
|
423
|
+
latestBlockhash?: LatestBlockhash
|
|
422
424
|
): Promise<ReturnType<P>> => {
|
|
423
|
-
const simulationTx = appendTransactionMessageInstruction(
|
|
425
|
+
const simulationTx = appendTransactionMessageInstruction(
|
|
426
|
+
ix,
|
|
427
|
+
await createDefaultTransaction(solanaClient, signer, latestBlockhash)
|
|
428
|
+
);
|
|
424
429
|
|
|
425
430
|
const simulationResult = await solanaClient
|
|
426
431
|
.simulateTransaction(getBase64EncodedWireTransaction(await signTransactionMessageWithSigners(simulationTx)), {
|
|
@@ -470,7 +475,8 @@ export const getCCTPNoncePda = async (
|
|
|
470
475
|
solanaClient: SVMProvider,
|
|
471
476
|
signer: KeyPairSigner,
|
|
472
477
|
nonce: number,
|
|
473
|
-
sourceDomain: number
|
|
478
|
+
sourceDomain: number,
|
|
479
|
+
latestBlockhash?: LatestBlockhash
|
|
474
480
|
) => {
|
|
475
481
|
const [messageTransmitterPda] = await getProgramDerivedAddress({
|
|
476
482
|
programAddress: MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
|
|
@@ -489,7 +495,7 @@ export const getCCTPNoncePda = async (
|
|
|
489
495
|
throw new Error("Invalid buffer");
|
|
490
496
|
};
|
|
491
497
|
|
|
492
|
-
return await simulateAndDecode(solanaClient, getNonceIx, signer, parserFunction);
|
|
498
|
+
return await simulateAndDecode(solanaClient, getNonceIx, signer, parserFunction, latestBlockhash);
|
|
493
499
|
};
|
|
494
500
|
|
|
495
501
|
/**
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { Logger } from "winston";
|
|
1
2
|
import { RpcFromTransport, RpcResponse, RpcTransport, SolanaRpcApiFromTransport } from "@solana/kit";
|
|
2
|
-
import { CachedSolanaRpcFactory } from "./cachedRpcFactory";
|
|
3
|
-
import { SolanaBaseRpcFactory, SolanaClusterRpcFactory } from "./baseRpcFactories";
|
|
4
3
|
import { isPromiseFulfilled, isPromiseRejected } from "../../utils/TypeGuards";
|
|
5
4
|
import { compareSvmRpcResults, createSendErrorWithMessage } from "../utils";
|
|
6
|
-
import {
|
|
5
|
+
import { CachedSolanaRpcFactory } from "./cachedRpcFactory";
|
|
6
|
+
import { SolanaBaseRpcFactory, SolanaClusterRpcFactory } from "./baseRpcFactories";
|
|
7
|
+
import { shouldFailImmediate } from "./utils";
|
|
7
8
|
|
|
8
9
|
// This factory stores multiple Cached RPC factories so that users of this factory can specify multiple RPC providers
|
|
9
10
|
// and the factory will fallback through them if any RPC calls fail. This factory also implements quorum logic amongst
|
|
@@ -64,13 +65,18 @@ export class QuorumFallbackSolanaRpcFactory extends SolanaBaseRpcFactory {
|
|
|
64
65
|
throw error;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// If one RPC provider reverted, others likely will too. Skip them.
|
|
69
|
+
if (quorumThreshold === 1 && shouldFailImmediate(method, error)) {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
const currentFactory = factory.rpcFactory.clusterUrl;
|
|
68
74
|
const nextFactory = fallbackFactories.shift()!;
|
|
69
75
|
this.logger.debug({
|
|
70
76
|
at: "FallbackSolanaRpcFactory#createTransport::tryWithFallback",
|
|
71
77
|
message: `[${method}] ${currentFactory} failed, falling back to ${nextFactory.rpcFactory.clusterUrl}, new fallback providers length: ${fallbackFactories.length}`,
|
|
72
78
|
method,
|
|
73
|
-
error,
|
|
79
|
+
jsonError: error,
|
|
74
80
|
});
|
|
75
81
|
return tryWithFallback(nextFactory, ...args);
|
|
76
82
|
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { Logger } from "winston";
|
|
1
2
|
import { RpcTransport, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR } from "@solana/kit";
|
|
2
3
|
import { getThrowSolanaErrorResponseTransformer } from "@solana/rpc-transformers";
|
|
4
|
+
import { isSolanaError } from "../../arch/svm";
|
|
5
|
+
import { delay } from "../../utils";
|
|
3
6
|
import { SolanaClusterRpcFactory } from "./baseRpcFactories";
|
|
4
7
|
import { RateLimitedSolanaRpcFactory } from "./rateLimitedRpcFactory";
|
|
5
|
-
import {
|
|
6
|
-
import { delay } from "../../utils";
|
|
7
|
-
import { Logger } from "winston";
|
|
8
|
+
import { shouldFailImmediate } from "./utils";
|
|
8
9
|
|
|
9
10
|
// This factory adds retry logic on top of the RateLimitedSolanaRpcFactory.
|
|
10
11
|
// It follows the same composition pattern as other factories in this module.
|
|
@@ -67,7 +68,7 @@ export class RetrySolanaRpcFactory extends SolanaClusterRpcFactory {
|
|
|
67
68
|
getThrowSolanaErrorResponseTransformer()(response, { methodName: method, params });
|
|
68
69
|
return response;
|
|
69
70
|
} catch (error) {
|
|
70
|
-
if (retryAttempt++ >= this.retries ||
|
|
71
|
+
if (retryAttempt++ >= this.retries || shouldFailImmediate(method, error)) {
|
|
71
72
|
throw error;
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -82,29 +83,6 @@ export class RetrySolanaRpcFactory extends SolanaClusterRpcFactory {
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
/**
|
|
86
|
-
* Determine whether a Solana RPC error indicates an unrecoverable error that should not be retried.
|
|
87
|
-
* @param method RPC method name
|
|
88
|
-
* @param error Error object from the RPC call
|
|
89
|
-
* @returns True if the request should be aborted immediately, otherwise false
|
|
90
|
-
*/
|
|
91
|
-
private shouldFailImmediate(method: string, error: unknown): boolean {
|
|
92
|
-
if (!isSolanaError(error)) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// JSON-RPC errors: https://www.quicknode.com/docs/solana/error-references
|
|
97
|
-
const { __code: code } = error.context;
|
|
98
|
-
switch (method) {
|
|
99
|
-
case "getBlock":
|
|
100
|
-
case "getBlockTime":
|
|
101
|
-
// No block at the requested slot. This may not be correct for blocks > 1 year old.
|
|
102
|
-
return [SVM_SLOT_SKIPPED, SVM_LONG_TERM_STORAGE_SLOT_SKIPPED].includes(code);
|
|
103
|
-
default:
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
86
|
/**
|
|
109
87
|
* Identify whether an error thrown was the result of an RPC provider 429 response.
|
|
110
88
|
* @param error Error object from the RPC query.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RpcTransport } from "@solana/rpc-spec";
|
|
2
|
+
import { isSolanaError, SVM_SLOT_SKIPPED, SVM_LONG_TERM_STORAGE_SLOT_SKIPPED } from "../../arch/svm";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* This is the type we pass to define a Solana RPC request "task".
|
|
@@ -12,3 +13,26 @@ export interface SolanaRateLimitTask {
|
|
|
12
13
|
resolve: (result: unknown) => void;
|
|
13
14
|
reject: (err: unknown) => void;
|
|
14
15
|
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Determine whether a Solana RPC error indicates an unrecoverable error that should not be retried.
|
|
19
|
+
* @param method RPC method name.
|
|
20
|
+
* @param error Error object from the RPC call.
|
|
21
|
+
* @returns True if the request should be aborted immediately, otherwise false.
|
|
22
|
+
*/
|
|
23
|
+
export function shouldFailImmediate(method: string, error: unknown): boolean {
|
|
24
|
+
if (!isSolanaError(error)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// JSON-RPC errors: https://www.quicknode.com/docs/solana/error-references
|
|
29
|
+
const { __code: code } = error.context;
|
|
30
|
+
switch (method) {
|
|
31
|
+
case "getBlock":
|
|
32
|
+
case "getBlockTime":
|
|
33
|
+
// No block at the requested slot. This may not be correct for blocks > 1 year old.
|
|
34
|
+
return [SVM_SLOT_SKIPPED, SVM_LONG_TERM_STORAGE_SLOT_SKIPPED].includes(code);
|
|
35
|
+
default:
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|