@across-protocol/sdk 4.3.38 → 4.3.41
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 +8 -7
- package/dist/cjs/arch/svm/SpokeUtils.js +76 -26
- package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/cjs/arch/svm/utils.d.ts +3 -2
- package/dist/cjs/arch/svm/utils.js +7 -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 +33 -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 +7 -6
- 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/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 +8 -7
- package/dist/esm/arch/svm/SpokeUtils.js +75 -25
- package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
- package/dist/esm/arch/svm/utils.d.ts +3 -2
- package/dist/esm/arch/svm/utils.js +8 -7
- 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 +33 -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 +7 -6
- package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js.map +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/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 +8 -7
- package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
- package/dist/types/arch/svm/utils.d.ts +3 -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/clients/SpokePoolClient/SVMSpokePoolClient.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/package.json +1 -1
- package/src/arch/svm/BlockUtils.ts +3 -1
- package/src/arch/svm/SpokeUtils.ts +69 -15
- package/src/arch/svm/utils.ts +9 -5
- package/src/clients/BaseAbstractClient.ts +25 -8
- package/src/clients/BundleDataClient/BundleDataClient.ts +2 -1
- package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +5 -1
- package/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +6 -5
- 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/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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RpcFromTransport, RpcTransport, SolanaRpcApiFromTransport } from "@solana/kit";
|
|
2
|
+
import { CachedSolanaRpcFactory } from "./cachedRpcFactory";
|
|
3
|
+
import { SolanaBaseRpcFactory } from "./baseRpcFactories";
|
|
4
|
+
import { Logger } from "winston";
|
|
5
|
+
export declare class QuorumFallbackSolanaRpcFactory extends SolanaBaseRpcFactory {
|
|
6
|
+
readonly nodeQuorumThreshold: number;
|
|
7
|
+
readonly logger: Logger;
|
|
8
|
+
readonly rpcFactories: {
|
|
9
|
+
transport: RpcTransport;
|
|
10
|
+
rpcClient: RpcFromTransport<SolanaRpcApiFromTransport<RpcTransport>, RpcTransport>;
|
|
11
|
+
rpcFactory: CachedSolanaRpcFactory;
|
|
12
|
+
}[];
|
|
13
|
+
constructor(factoryConstructorParams: ConstructorParameters<typeof CachedSolanaRpcFactory>[], nodeQuorumThreshold: number, logger: Logger);
|
|
14
|
+
createTransport(): RpcTransport;
|
|
15
|
+
_getQuorum(method: string, _params: Array<unknown>): number;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=quorumFallbackRpcFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quorumFallbackRpcFactory.d.ts","sourceRoot":"","sources":["../../../../src/providers/solana/quorumFallbackRpcFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,YAAY,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAA2B,MAAM,oBAAoB,CAAC;AAGnF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKjC,qBAAa,8BAA+B,SAAQ,oBAAoB;IASpE,QAAQ,CAAC,mBAAmB,EAAE,MAAM;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM;IATzB,QAAQ,CAAC,YAAY,EAAE;QACrB,SAAS,EAAE,YAAY,CAAC;QACxB,SAAS,EAAE,gBAAgB,CAAC,yBAAyB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;QACnF,UAAU,EAAE,sBAAsB,CAAC;KACpC,EAAE,CAAM;gBAGP,wBAAwB,EAAE,qBAAqB,CAAC,OAAO,sBAAsB,CAAC,EAAE,EACvE,mBAAmB,EAAE,MAAM,EAC3B,MAAM,EAAE,MAAM;IAkBlB,eAAe,IAAI,YAAY;IAiMtC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM;CAY5D"}
|
|
@@ -48,6 +48,7 @@ export declare function createSendErrorWithMessage(message: string, sendError: R
|
|
|
48
48
|
* @returns True if the results are equal, false otherwise.
|
|
49
49
|
*/
|
|
50
50
|
export declare function compareRpcResults(method: string, rpcResultA: unknown, rpcResultB: unknown): boolean;
|
|
51
|
+
export declare function compareSvmRpcResults(_method: string, rpcResultA: unknown, rpcResultB: unknown): boolean;
|
|
51
52
|
export declare enum CacheType {
|
|
52
53
|
NONE = 0,
|
|
53
54
|
WITH_TTL = 1,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/providers/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiBpD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,IAAI,WAAW,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,YAAsB,GAChC,MAAM,CAIR;AAmBD,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAOT;AAED,wBAAgB,kCAAkC,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAOnH;AA4BD;;GAEG;AACH,MAAM,WAAW,aAAa;IAE5B,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAInC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,qBAAqB,EAAE,YAAY,EAAE,MAAM,UAElG;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;EAG7F;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAkBnG;AAED,oBAAY,SAAS;IACnB,IAAI,IAAA;IACJ,QAAQ,IAAA;IACR,MAAM,IAAA;IACN,oBAAoB,IAAA;CACrB"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/providers/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiBpD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,IAAI,WAAW,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,YAAsB,GAChC,MAAM,CAIR;AAmBD,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAOT;AAED,wBAAgB,kCAAkC,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAOnH;AA4BD;;GAEG;AACH,MAAM,WAAW,aAAa;IAE5B,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAInC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,qBAAqB,EAAE,YAAY,EAAE,MAAM,UAElG;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;EAG7F;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAkBnG;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAEvG;AAED,oBAAY,SAAS;IACnB,IAAI,IAAA;IACJ,QAAQ,IAAA;IACR,MAAM,IAAA;IACN,oBAAoB,IAAA;CACrB"}
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import { getCurrentTime } from "../../utils/TimeUtils";
|
|
|
6
6
|
import { CHAIN_IDs } from "../../constants";
|
|
7
7
|
import { SVMProvider } from "./";
|
|
8
8
|
import { getNearestSlotTime } from "./utils";
|
|
9
|
+
import winston from "winston";
|
|
9
10
|
|
|
10
11
|
interface SVMBlock extends Block {}
|
|
11
12
|
|
|
@@ -32,6 +33,7 @@ function estimateBlocksElapsed(seconds: number, cushionPercentage = 0.0, _provid
|
|
|
32
33
|
|
|
33
34
|
export class SVMBlockFinder extends BlockFinder<SVMBlock> {
|
|
34
35
|
constructor(
|
|
36
|
+
private readonly logger: winston.Logger,
|
|
35
37
|
private readonly provider: SVMProvider,
|
|
36
38
|
private readonly blocks: SVMBlock[] = []
|
|
37
39
|
) {
|
|
@@ -97,7 +99,7 @@ export class SVMBlockFinder extends BlockFinder<SVMBlock> {
|
|
|
97
99
|
*/
|
|
98
100
|
private getBlockTime(slot?: bigint): Promise<{ slot: bigint; timestamp: number }> {
|
|
99
101
|
const opts = isDefined(slot) ? { slot } : undefined;
|
|
100
|
-
return getNearestSlotTime(this.provider, opts);
|
|
102
|
+
return getNearestSlotTime(this.provider, opts, this.logger);
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
// Grabs the most recent slot and caches it.
|
|
@@ -31,10 +31,11 @@ import {
|
|
|
31
31
|
signTransactionMessageWithSigners,
|
|
32
32
|
some,
|
|
33
33
|
type TransactionSigner,
|
|
34
|
+
type Commitment,
|
|
34
35
|
} from "@solana/kit";
|
|
35
36
|
import assert from "assert";
|
|
37
|
+
import winston from "winston";
|
|
36
38
|
import { arrayify } from "ethers/lib/utils";
|
|
37
|
-
import { Logger } from "winston";
|
|
38
39
|
import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "../../constants";
|
|
39
40
|
import { DepositWithBlock, FillStatus, FillWithBlock, RelayData, RelayExecutionEventInfo } from "../../interfaces";
|
|
40
41
|
import {
|
|
@@ -88,22 +89,51 @@ type ProtoFill = Omit<RelayData, "recipient" | "outputToken"> & {
|
|
|
88
89
|
outputToken: SvmAddress;
|
|
89
90
|
};
|
|
90
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
|
+
|
|
91
119
|
/**
|
|
92
120
|
* Retrieves the chain time at a particular slot.
|
|
93
121
|
*/
|
|
94
122
|
export function getTimestampForSlot(
|
|
95
123
|
provider: SVMProvider,
|
|
96
124
|
slotNumber: bigint,
|
|
97
|
-
maxRetries = 2
|
|
125
|
+
maxRetries = 2,
|
|
126
|
+
logger?: winston.Logger
|
|
98
127
|
): Promise<number | undefined> {
|
|
99
|
-
return _callGetTimestampForSlotWithRetry(provider, slotNumber, 0, maxRetries);
|
|
128
|
+
return _callGetTimestampForSlotWithRetry(provider, slotNumber, 0, maxRetries, logger);
|
|
100
129
|
}
|
|
101
130
|
|
|
102
131
|
async function _callGetTimestampForSlotWithRetry(
|
|
103
132
|
provider: SVMProvider,
|
|
104
133
|
slotNumber: bigint,
|
|
105
134
|
retryAttempt: number,
|
|
106
|
-
maxRetries: number
|
|
135
|
+
maxRetries: number,
|
|
136
|
+
logger?: winston.Logger
|
|
107
137
|
): Promise<number | undefined> {
|
|
108
138
|
// @note: getBlockTime receives a slot number, not a block number.
|
|
109
139
|
let _timestamp: bigint;
|
|
@@ -117,6 +147,7 @@ async function _callGetTimestampForSlotWithRetry(
|
|
|
117
147
|
|
|
118
148
|
const { __code: code } = err.context;
|
|
119
149
|
const slot = slotNumber.toString();
|
|
150
|
+
|
|
120
151
|
switch (err.context.__code) {
|
|
121
152
|
case SVM_SLOT_SKIPPED:
|
|
122
153
|
return undefined;
|
|
@@ -128,11 +159,27 @@ async function _callGetTimestampForSlotWithRetry(
|
|
|
128
159
|
if (retryAttempt >= maxRetries) {
|
|
129
160
|
throw new Error(`Timeout on SVM getBlockTime() for slot ${slot} after ${retryAttempt} retry attempts`);
|
|
130
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
|
+
});
|
|
131
170
|
await delay(delaySeconds);
|
|
132
|
-
return _callGetTimestampForSlotWithRetry(provider, slotNumber, ++retryAttempt, maxRetries);
|
|
171
|
+
return _callGetTimestampForSlotWithRetry(provider, slotNumber, ++retryAttempt, maxRetries, logger);
|
|
133
172
|
}
|
|
134
173
|
|
|
135
174
|
default:
|
|
175
|
+
logger?.debug({
|
|
176
|
+
at: "getTimestampForSlot",
|
|
177
|
+
message: "Caught error from getBlockTime()",
|
|
178
|
+
errorCode: code,
|
|
179
|
+
slot,
|
|
180
|
+
retryAttempt,
|
|
181
|
+
maxRetries,
|
|
182
|
+
});
|
|
136
183
|
throw new Error(`Unhandled SVM getBlockTime() error for slot ${slot}: ${code}`, { cause: err });
|
|
137
184
|
}
|
|
138
185
|
}
|
|
@@ -196,6 +243,7 @@ export function getDepositIdAtBlock(_contract: unknown, _blockTag: number): Prom
|
|
|
196
243
|
export async function findDeposit(
|
|
197
244
|
eventClient: SvmCpiEventsClient,
|
|
198
245
|
depositId: BigNumber,
|
|
246
|
+
logger: winston.Logger,
|
|
199
247
|
slot?: bigint,
|
|
200
248
|
secondsLookback = 2 * 24 * 60 * 60 // 2 days
|
|
201
249
|
): Promise<DepositWithBlock | undefined> {
|
|
@@ -205,7 +253,8 @@ export async function findDeposit(
|
|
|
205
253
|
}
|
|
206
254
|
|
|
207
255
|
const provider = eventClient.getRpc();
|
|
208
|
-
const
|
|
256
|
+
const opts = undefined;
|
|
257
|
+
const { slot: currentSlot } = await getNearestSlotTime(provider, opts, logger);
|
|
209
258
|
|
|
210
259
|
// If no slot is provided, use the current slot
|
|
211
260
|
// If a slot is provided, ensure it's not in the future
|
|
@@ -263,6 +312,7 @@ export async function relayFillStatus(
|
|
|
263
312
|
relayData: RelayData,
|
|
264
313
|
destinationChainId: number,
|
|
265
314
|
svmEventsClient: SvmCpiEventsClient,
|
|
315
|
+
logger: winston.Logger,
|
|
266
316
|
atHeight?: number
|
|
267
317
|
): Promise<FillStatus> {
|
|
268
318
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
@@ -276,7 +326,7 @@ export async function relayFillStatus(
|
|
|
276
326
|
const commitment = "confirmed";
|
|
277
327
|
const [fillStatusAccount, { slot: currentSlot, timestamp }] = await Promise.all([
|
|
278
328
|
fetchEncodedAccount(provider, fillStatusPda, { commitment }),
|
|
279
|
-
getNearestSlotTime(provider, { commitment }),
|
|
329
|
+
getNearestSlotTime(provider, { commitment }, logger),
|
|
280
330
|
]);
|
|
281
331
|
toSlot = currentSlot;
|
|
282
332
|
|
|
@@ -313,8 +363,8 @@ export async function fillStatusArray(
|
|
|
313
363
|
relayData: RelayData[],
|
|
314
364
|
destinationChainId: number,
|
|
315
365
|
svmEventsClient: SvmCpiEventsClient,
|
|
316
|
-
|
|
317
|
-
|
|
366
|
+
logger: winston.Logger,
|
|
367
|
+
atHeight?: number
|
|
318
368
|
): Promise<(FillStatus | undefined)[]> {
|
|
319
369
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
320
370
|
const provider = svmEventsClient.getRpc();
|
|
@@ -342,7 +392,7 @@ export async function fillStatusArray(
|
|
|
342
392
|
// Otherwise, initialize all statuses as undefined
|
|
343
393
|
const fillStatuses: (FillStatus | undefined)[] =
|
|
344
394
|
atHeight === undefined
|
|
345
|
-
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData)
|
|
395
|
+
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData, logger)
|
|
346
396
|
: new Array(relayData.length).fill(undefined);
|
|
347
397
|
|
|
348
398
|
// Collect indices of deposits that still need their status resolved
|
|
@@ -358,7 +408,8 @@ export async function fillStatusArray(
|
|
|
358
408
|
const missingResults: { index: number; fillStatus: FillStatus }[] = [];
|
|
359
409
|
|
|
360
410
|
// Determine the toSlot to use for event reconstruction
|
|
361
|
-
const
|
|
411
|
+
const opts = undefined;
|
|
412
|
+
const toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider, opts, logger)).slot;
|
|
362
413
|
|
|
363
414
|
// @note: This path is mostly used for deposits past their fill deadline.
|
|
364
415
|
// If it becomes a bottleneck, consider returning an "Unknown" status that can be handled downstream.
|
|
@@ -397,10 +448,12 @@ export async function findFillEvent(
|
|
|
397
448
|
destinationChainId: number,
|
|
398
449
|
svmEventsClient: SvmCpiEventsClient,
|
|
399
450
|
fromSlot: number,
|
|
400
|
-
toSlot?: number
|
|
451
|
+
toSlot?: number,
|
|
452
|
+
logger?: winston.Logger
|
|
401
453
|
): Promise<FillWithBlock | undefined> {
|
|
402
454
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
403
|
-
|
|
455
|
+
const opts = undefined;
|
|
456
|
+
toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc(), opts, logger)).slot);
|
|
404
457
|
|
|
405
458
|
// Get fillStatus PDA using relayData
|
|
406
459
|
const programId = svmEventsClient.getProgramAddress();
|
|
@@ -873,14 +926,15 @@ async function resolveFillStatusFromPdaEvents(
|
|
|
873
926
|
async function fetchBatchFillStatusFromPdaAccounts(
|
|
874
927
|
provider: SVMProvider,
|
|
875
928
|
fillStatusPdas: Address[],
|
|
876
|
-
relayDataArray: RelayData[]
|
|
929
|
+
relayDataArray: RelayData[],
|
|
930
|
+
logger: winston.Logger
|
|
877
931
|
): Promise<(FillStatus | undefined)[]> {
|
|
878
932
|
const chunkSize = 100; // SVM method getMultipleAccounts allows a max of 100 addresses per request
|
|
879
933
|
const commitment = "confirmed";
|
|
880
934
|
|
|
881
935
|
const [pdaAccounts, { timestamp }] = await Promise.all([
|
|
882
936
|
Promise.all(chunk(fillStatusPdas, chunkSize).map((chunk) => fetchEncodedAccounts(provider, chunk, { commitment }))),
|
|
883
|
-
getNearestSlotTime(provider, { commitment }),
|
|
937
|
+
getNearestSlotTime(provider, { commitment }, logger),
|
|
884
938
|
]);
|
|
885
939
|
|
|
886
940
|
const fillStatuses = pdaAccounts.flat().map((account, index) => {
|
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,15 @@ export function toAddress(address: SdkAddress): Address<string> {
|
|
|
67
68
|
*/
|
|
68
69
|
export async function getNearestSlotTime(
|
|
69
70
|
provider: SVMProvider,
|
|
70
|
-
opts: { slot: bigint } | { commitment: Commitment } = { commitment: "confirmed" }
|
|
71
|
+
opts: { slot: bigint } | { commitment: Commitment } = { commitment: "confirmed" },
|
|
72
|
+
logger?: winston.Logger
|
|
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);
|
|
76
|
+
const maxRetries = undefined; // Inherit defaults
|
|
74
77
|
|
|
75
78
|
do {
|
|
76
|
-
timestamp = await getTimestampForSlot(provider, slot);
|
|
79
|
+
timestamp = await getTimestampForSlot(provider, slot, maxRetries, logger);
|
|
77
80
|
} while (!isDefined(timestamp) && --slot);
|
|
78
81
|
assert(isDefined(timestamp), `Unable to resolve block time for SVM slot ${slot}`);
|
|
79
82
|
|
|
@@ -87,11 +90,12 @@ export async function getNearestSlotTime(
|
|
|
87
90
|
*/
|
|
88
91
|
export async function getLatestFinalizedSlotWithBlock(
|
|
89
92
|
provider: SVMProvider,
|
|
93
|
+
logger: winston.Logger,
|
|
90
94
|
maxSlot: bigint,
|
|
91
95
|
maxLookback = 1000
|
|
92
96
|
): Promise<number> {
|
|
93
97
|
const opts = { maxSupportedTransactionVersion: 0, transactionDetails: "none", rewards: false } as const;
|
|
94
|
-
const { slot: finalizedSlot } = await getNearestSlotTime(provider, { commitment: "finalized" });
|
|
98
|
+
const { slot: finalizedSlot } = await getNearestSlotTime(provider, { commitment: "finalized" }, logger);
|
|
95
99
|
const endSlot = biMin(maxSlot, finalizedSlot);
|
|
96
100
|
|
|
97
101
|
let slot = endSlot;
|
|
@@ -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,30 @@ 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 opts = undefined; // Inherit defaults
|
|
93
|
+
const { slot } = await getNearestSlotTime(provider, opts, logger);
|
|
94
|
+
to = Number(slot);
|
|
78
95
|
if (to < from) {
|
|
79
96
|
return UpdateFailureReason.AlreadyUpdated;
|
|
80
97
|
}
|
|
@@ -1652,7 +1652,8 @@ export class BundleDataClient {
|
|
|
1652
1652
|
spokePoolClient.chainId,
|
|
1653
1653
|
spokePoolClient.svmEventsClient,
|
|
1654
1654
|
spokePoolClient.deploymentBlock,
|
|
1655
|
-
spokePoolClient.latestHeightSearched
|
|
1655
|
+
spokePoolClient.latestHeightSearched,
|
|
1656
|
+
spokePoolClient.logger
|
|
1656
1657
|
);
|
|
1657
1658
|
} else if (isEVMSpokePoolClient(spokePoolClient)) {
|
|
1658
1659
|
return await findEvmFillEvent(
|
|
@@ -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 };
|
|
@@ -194,8 +194,9 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
194
194
|
*/
|
|
195
195
|
public override async getTimestampForBlock(slot: number): Promise<number> {
|
|
196
196
|
let _slot = BigInt(slot);
|
|
197
|
+
const maxRetries = undefined; // Inherit defaults
|
|
197
198
|
do {
|
|
198
|
-
const timestamp = await getTimestampForSlot(this.svmEventsClient.getRpc(), _slot);
|
|
199
|
+
const timestamp = await getTimestampForSlot(this.svmEventsClient.getRpc(), _slot, maxRetries, this.logger);
|
|
199
200
|
if (isDefined(timestamp)) {
|
|
200
201
|
return timestamp;
|
|
201
202
|
}
|
|
@@ -217,7 +218,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
217
218
|
* Finds a deposit based on its deposit ID on the SVM chain.
|
|
218
219
|
*/
|
|
219
220
|
public async findDeposit(depositId: BigNumber): Promise<DepositSearchResult> {
|
|
220
|
-
const deposit = await findDeposit(this.svmEventsClient, depositId);
|
|
221
|
+
const deposit = await findDeposit(this.svmEventsClient, depositId, this.logger);
|
|
221
222
|
if (!deposit) {
|
|
222
223
|
return {
|
|
223
224
|
found: false,
|
|
@@ -244,7 +245,7 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
244
245
|
* Retrieves the fill status for a given relay data from the SVM chain.
|
|
245
246
|
*/
|
|
246
247
|
public override relayFillStatus(relayData: RelayData, atHeight?: number): Promise<FillStatus> {
|
|
247
|
-
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, atHeight);
|
|
248
|
+
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, this.logger, atHeight);
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
/**
|
|
@@ -260,6 +261,6 @@ export class SVMSpokePoolClient extends SpokePoolClient {
|
|
|
260
261
|
): Promise<(FillStatus | undefined)[]> {
|
|
261
262
|
// @note: deploymentBlock actually refers to the deployment slot. Also, blockTag should be a slot number.
|
|
262
263
|
destinationChainId ??= this.chainId;
|
|
263
|
-
return fillStatusArray(this.programId, relayData, destinationChainId, this.svmEventsClient,
|
|
264
|
+
return fillStatusArray(this.programId, relayData, destinationChainId, this.svmEventsClient, this.logger, atHeight);
|
|
264
265
|
}
|
|
265
266
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CachedSolanaRpcFactory } from "
|
|
1
|
+
import { CachedSolanaRpcFactory } from "../solana/cachedRpcFactory";
|
|
2
2
|
import { MockRetrySolanaRpcFactory } from "./MockRetrySolanaRpcFactory";
|
|
3
3
|
|
|
4
4
|
// Creates mocked cached Solana RPC factory by using the mocked retry Solana RPC factory.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RateLimitedSolanaRpcFactory } from "
|
|
1
|
+
import { RateLimitedSolanaRpcFactory } from "../solana/rateLimitedRpcFactory";
|
|
2
2
|
import { MockSolanaRpcFactory } from "./MockSolanaRpcFactory";
|
|
3
3
|
|
|
4
4
|
// Creates mocked rate limited Solana RPC factory by using the mocked Solana RPC factory.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RetrySolanaRpcFactory } from "
|
|
1
|
+
import { RetrySolanaRpcFactory } from "../solana/retryRpcFactory";
|
|
2
2
|
import { MockRateLimitedSolanaRpcFactory } from "./MockRateLimitedSolanaRpcFactory";
|
|
3
3
|
|
|
4
4
|
// Creates mocked retry Solana RPC factory by using the mocked rate limited Solana RPC factory.
|
|
@@ -2,7 +2,7 @@ import { ClusterUrl, createSolanaRpcFromTransport, RpcTransport } from "@solana/
|
|
|
2
2
|
|
|
3
3
|
// This is abstract base class for creating Solana RPC clients and transports.
|
|
4
4
|
export abstract class SolanaBaseRpcFactory {
|
|
5
|
-
constructor(
|
|
5
|
+
constructor() {}
|
|
6
6
|
|
|
7
7
|
// This method must be implemented by the derived class to create a transport.
|
|
8
8
|
public abstract createTransport(): RpcTransport;
|
|
@@ -18,8 +18,8 @@ export abstract class SolanaBaseRpcFactory {
|
|
|
18
18
|
export abstract class SolanaClusterRpcFactory extends SolanaBaseRpcFactory {
|
|
19
19
|
constructor(
|
|
20
20
|
readonly clusterUrl: ClusterUrl,
|
|
21
|
-
|
|
21
|
+
readonly chainId: number
|
|
22
22
|
) {
|
|
23
|
-
super(
|
|
23
|
+
super();
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -7,6 +7,8 @@ import { CacheType } from "../utils";
|
|
|
7
7
|
import { jsonReplacerWithBigInts, jsonReviverWithBigInts } from "../../utils";
|
|
8
8
|
import { RetrySolanaRpcFactory } from "./retryRpcFactory";
|
|
9
9
|
|
|
10
|
+
// A CachedFactory contains a RetryFactory and provides a caching layer that caches
|
|
11
|
+
// the results of the RetryFactory's RPC calls.
|
|
10
12
|
export class CachedSolanaRpcFactory extends SolanaClusterRpcFactory {
|
|
11
13
|
public readonly getTransactionCachePrefix: string;
|
|
12
14
|
|