@across-protocol/sdk 4.3.38 → 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 +8 -7
- package/dist/cjs/arch/svm/SpokeUtils.js +70 -23
- 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 +5 -5
- 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/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 +69 -22
- 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 +6 -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/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/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 +64 -13
- package/src/arch/svm/utils.ts +7 -4
- 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/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, this.logger, opts);
|
|
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,
|
|
125
|
+
logger: winston.Logger,
|
|
97
126
|
maxRetries = 2
|
|
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,7 @@ export async function findDeposit(
|
|
|
205
253
|
}
|
|
206
254
|
|
|
207
255
|
const provider = eventClient.getRpc();
|
|
208
|
-
const { slot: currentSlot } = await getNearestSlotTime(provider);
|
|
256
|
+
const { slot: currentSlot } = await getNearestSlotTime(provider, logger);
|
|
209
257
|
|
|
210
258
|
// If no slot is provided, use the current slot
|
|
211
259
|
// If a slot is provided, ensure it's not in the future
|
|
@@ -263,6 +311,7 @@ export async function relayFillStatus(
|
|
|
263
311
|
relayData: RelayData,
|
|
264
312
|
destinationChainId: number,
|
|
265
313
|
svmEventsClient: SvmCpiEventsClient,
|
|
314
|
+
logger: winston.Logger,
|
|
266
315
|
atHeight?: number
|
|
267
316
|
): Promise<FillStatus> {
|
|
268
317
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
@@ -276,7 +325,7 @@ export async function relayFillStatus(
|
|
|
276
325
|
const commitment = "confirmed";
|
|
277
326
|
const [fillStatusAccount, { slot: currentSlot, timestamp }] = await Promise.all([
|
|
278
327
|
fetchEncodedAccount(provider, fillStatusPda, { commitment }),
|
|
279
|
-
getNearestSlotTime(provider, { commitment }),
|
|
328
|
+
getNearestSlotTime(provider, logger, { commitment }),
|
|
280
329
|
]);
|
|
281
330
|
toSlot = currentSlot;
|
|
282
331
|
|
|
@@ -313,8 +362,8 @@ export async function fillStatusArray(
|
|
|
313
362
|
relayData: RelayData[],
|
|
314
363
|
destinationChainId: number,
|
|
315
364
|
svmEventsClient: SvmCpiEventsClient,
|
|
316
|
-
|
|
317
|
-
|
|
365
|
+
logger: winston.Logger,
|
|
366
|
+
atHeight?: number
|
|
318
367
|
): Promise<(FillStatus | undefined)[]> {
|
|
319
368
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
320
369
|
const provider = svmEventsClient.getRpc();
|
|
@@ -342,7 +391,7 @@ export async function fillStatusArray(
|
|
|
342
391
|
// Otherwise, initialize all statuses as undefined
|
|
343
392
|
const fillStatuses: (FillStatus | undefined)[] =
|
|
344
393
|
atHeight === undefined
|
|
345
|
-
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData)
|
|
394
|
+
? await fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData, logger)
|
|
346
395
|
: new Array(relayData.length).fill(undefined);
|
|
347
396
|
|
|
348
397
|
// Collect indices of deposits that still need their status resolved
|
|
@@ -358,7 +407,7 @@ export async function fillStatusArray(
|
|
|
358
407
|
const missingResults: { index: number; fillStatus: FillStatus }[] = [];
|
|
359
408
|
|
|
360
409
|
// Determine the toSlot to use for event reconstruction
|
|
361
|
-
const toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider)).slot;
|
|
410
|
+
const toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider, logger)).slot;
|
|
362
411
|
|
|
363
412
|
// @note: This path is mostly used for deposits past their fill deadline.
|
|
364
413
|
// If it becomes a bottleneck, consider returning an "Unknown" status that can be handled downstream.
|
|
@@ -396,11 +445,12 @@ export async function findFillEvent(
|
|
|
396
445
|
relayData: RelayData,
|
|
397
446
|
destinationChainId: number,
|
|
398
447
|
svmEventsClient: SvmCpiEventsClient,
|
|
448
|
+
logger: winston.Logger,
|
|
399
449
|
fromSlot: number,
|
|
400
450
|
toSlot?: number
|
|
401
451
|
): Promise<FillWithBlock | undefined> {
|
|
402
452
|
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
|
|
403
|
-
toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc())).slot);
|
|
453
|
+
toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc(), logger)).slot);
|
|
404
454
|
|
|
405
455
|
// Get fillStatus PDA using relayData
|
|
406
456
|
const programId = svmEventsClient.getProgramAddress();
|
|
@@ -873,14 +923,15 @@ async function resolveFillStatusFromPdaEvents(
|
|
|
873
923
|
async function fetchBatchFillStatusFromPdaAccounts(
|
|
874
924
|
provider: SVMProvider,
|
|
875
925
|
fillStatusPdas: Address[],
|
|
876
|
-
relayDataArray: RelayData[]
|
|
926
|
+
relayDataArray: RelayData[],
|
|
927
|
+
logger: winston.Logger
|
|
877
928
|
): Promise<(FillStatus | undefined)[]> {
|
|
878
929
|
const chunkSize = 100; // SVM method getMultipleAccounts allows a max of 100 addresses per request
|
|
879
930
|
const commitment = "confirmed";
|
|
880
931
|
|
|
881
932
|
const [pdaAccounts, { timestamp }] = await Promise.all([
|
|
882
933
|
Promise.all(chunk(fillStatusPdas, chunkSize).map((chunk) => fetchEncodedAccounts(provider, chunk, { commitment }))),
|
|
883
|
-
getNearestSlotTime(provider, { commitment }),
|
|
934
|
+
getNearestSlotTime(provider, logger, { commitment }),
|
|
884
935
|
]);
|
|
885
936
|
|
|
886
937
|
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,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;
|
|
@@ -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
|
}
|
|
@@ -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
|
|