@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.
Files changed (122) hide show
  1. package/dist/cjs/arch/svm/BlockUtils.d.ts +3 -1
  2. package/dist/cjs/arch/svm/BlockUtils.js +3 -2
  3. package/dist/cjs/arch/svm/BlockUtils.js.map +1 -1
  4. package/dist/cjs/arch/svm/SpokeUtils.d.ts +8 -7
  5. package/dist/cjs/arch/svm/SpokeUtils.js +70 -23
  6. package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
  7. package/dist/cjs/arch/svm/utils.d.ts +3 -2
  8. package/dist/cjs/arch/svm/utils.js +5 -5
  9. package/dist/cjs/arch/svm/utils.js.map +1 -1
  10. package/dist/cjs/clients/BaseAbstractClient.d.ts +3 -1
  11. package/dist/cjs/clients/BaseAbstractClient.js +31 -13
  12. package/dist/cjs/clients/BaseAbstractClient.js.map +1 -1
  13. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +1 -1
  14. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  15. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +1 -1
  16. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  17. package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js +5 -5
  18. package/dist/cjs/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
  19. package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
  20. package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js +2 -2
  21. package/dist/cjs/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
  22. package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
  23. package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js +2 -2
  24. package/dist/cjs/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
  25. package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
  26. package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js +2 -2
  27. package/dist/cjs/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
  28. package/dist/cjs/providers/solana/baseRpcFactories.d.ts +3 -3
  29. package/dist/cjs/providers/solana/baseRpcFactories.js +4 -8
  30. package/dist/cjs/providers/solana/baseRpcFactories.js.map +1 -1
  31. package/dist/cjs/providers/solana/cachedRpcFactory.js.map +1 -1
  32. package/dist/cjs/providers/solana/index.d.ts +1 -0
  33. package/dist/cjs/providers/solana/index.js +1 -0
  34. package/dist/cjs/providers/solana/index.js.map +1 -1
  35. package/dist/cjs/providers/solana/quorumFallbackRpcFactory.d.ts +16 -0
  36. package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js +208 -0
  37. package/dist/cjs/providers/solana/quorumFallbackRpcFactory.js.map +1 -0
  38. package/dist/cjs/providers/utils.d.ts +1 -0
  39. package/dist/cjs/providers/utils.js +5 -1
  40. package/dist/cjs/providers/utils.js.map +1 -1
  41. package/dist/esm/arch/svm/BlockUtils.d.ts +3 -1
  42. package/dist/esm/arch/svm/BlockUtils.js +3 -2
  43. package/dist/esm/arch/svm/BlockUtils.js.map +1 -1
  44. package/dist/esm/arch/svm/SpokeUtils.d.ts +8 -7
  45. package/dist/esm/arch/svm/SpokeUtils.js +69 -22
  46. package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
  47. package/dist/esm/arch/svm/utils.d.ts +3 -2
  48. package/dist/esm/arch/svm/utils.js +6 -6
  49. package/dist/esm/arch/svm/utils.js.map +1 -1
  50. package/dist/esm/clients/BaseAbstractClient.d.ts +3 -1
  51. package/dist/esm/clients/BaseAbstractClient.js +31 -13
  52. package/dist/esm/clients/BaseAbstractClient.js.map +1 -1
  53. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +1 -1
  54. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  55. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +1 -1
  56. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  57. package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js +5 -5
  58. package/dist/esm/clients/SpokePoolClient/SVMSpokePoolClient.js.map +1 -1
  59. package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
  60. package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js +1 -1
  61. package/dist/esm/providers/mocks/MockCachedSolanaRpcFactory.js.map +1 -1
  62. package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
  63. package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js +1 -1
  64. package/dist/esm/providers/mocks/MockRateLimitedSolanaRpcFactory.js.map +1 -1
  65. package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
  66. package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js +1 -1
  67. package/dist/esm/providers/mocks/MockRetrySolanaRpcFactory.js.map +1 -1
  68. package/dist/esm/providers/solana/baseRpcFactories.d.ts +3 -3
  69. package/dist/esm/providers/solana/baseRpcFactories.js +4 -8
  70. package/dist/esm/providers/solana/baseRpcFactories.js.map +1 -1
  71. package/dist/esm/providers/solana/cachedRpcFactory.js +2 -0
  72. package/dist/esm/providers/solana/cachedRpcFactory.js.map +1 -1
  73. package/dist/esm/providers/solana/index.d.ts +1 -0
  74. package/dist/esm/providers/solana/index.js +1 -0
  75. package/dist/esm/providers/solana/index.js.map +1 -1
  76. package/dist/esm/providers/solana/quorumFallbackRpcFactory.d.ts +16 -0
  77. package/dist/esm/providers/solana/quorumFallbackRpcFactory.js +225 -0
  78. package/dist/esm/providers/solana/quorumFallbackRpcFactory.js.map +1 -0
  79. package/dist/esm/providers/utils.d.ts +1 -0
  80. package/dist/esm/providers/utils.js +3 -0
  81. package/dist/esm/providers/utils.js.map +1 -1
  82. package/dist/types/arch/svm/BlockUtils.d.ts +3 -1
  83. package/dist/types/arch/svm/BlockUtils.d.ts.map +1 -1
  84. package/dist/types/arch/svm/SpokeUtils.d.ts +8 -7
  85. package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
  86. package/dist/types/arch/svm/utils.d.ts +3 -2
  87. package/dist/types/arch/svm/utils.d.ts.map +1 -1
  88. package/dist/types/clients/BaseAbstractClient.d.ts +3 -1
  89. package/dist/types/clients/BaseAbstractClient.d.ts.map +1 -1
  90. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  91. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
  92. package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
  93. package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts.map +1 -1
  94. package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
  95. package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts.map +1 -1
  96. package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
  97. package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts.map +1 -1
  98. package/dist/types/providers/solana/baseRpcFactories.d.ts +3 -3
  99. package/dist/types/providers/solana/baseRpcFactories.d.ts.map +1 -1
  100. package/dist/types/providers/solana/cachedRpcFactory.d.ts.map +1 -1
  101. package/dist/types/providers/solana/index.d.ts +1 -0
  102. package/dist/types/providers/solana/index.d.ts.map +1 -1
  103. package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts +17 -0
  104. package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts.map +1 -0
  105. package/dist/types/providers/utils.d.ts +1 -0
  106. package/dist/types/providers/utils.d.ts.map +1 -1
  107. package/package.json +1 -1
  108. package/src/arch/svm/BlockUtils.ts +3 -1
  109. package/src/arch/svm/SpokeUtils.ts +64 -13
  110. package/src/arch/svm/utils.ts +7 -4
  111. package/src/clients/BaseAbstractClient.ts +24 -8
  112. package/src/clients/BundleDataClient/BundleDataClient.ts +1 -0
  113. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +5 -1
  114. package/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +5 -5
  115. package/src/providers/mocks/MockCachedSolanaRpcFactory.ts +1 -1
  116. package/src/providers/mocks/MockRateLimitedSolanaRpcFactory.ts +1 -1
  117. package/src/providers/mocks/MockRetrySolanaRpcFactory.ts +1 -1
  118. package/src/providers/solana/baseRpcFactories.ts +3 -3
  119. package/src/providers/solana/cachedRpcFactory.ts +2 -0
  120. package/src/providers/solana/index.ts +1 -0
  121. package/src/providers/solana/quorumFallbackRpcFactory.ts +248 -0
  122. 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@across-protocol/sdk",
3
3
  "author": "UMA Team",
4
- "version": "4.3.38",
4
+ "version": "4.3.40",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://docs.across.to/reference/sdk",
7
7
  "files": [
@@ -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
- atHeight?: number,
317
- logger?: Logger
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) => {
@@ -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 provider.getSlot(opts).send();
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
- if (provider instanceof providers.Provider) {
73
- to = await provider.getBlockNumber();
74
- } else {
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
  }
@@ -1651,6 +1651,7 @@ export class BundleDataClient {
1651
1651
  deposit,
1652
1652
  spokePoolClient.chainId,
1653
1653
  spokePoolClient.svmEventsClient,
1654
+ spokePoolClient.logger,
1654
1655
  spokePoolClient.deploymentBlock,
1655
1656
  spokePoolClient.latestHeightSearched
1656
1657
  );
@@ -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(spokePoolClient.svmEventsClient.getRpc(), BigInt(maxSlot));
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.updateSearchConfig(this.svmEventsClient.getRpc());
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, atHeight, this.logger);
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(readonly chainId: number) {}
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
- ...baseConstructorParams: ConstructorParameters<typeof SolanaBaseRpcFactory>
21
+ readonly chainId: number
22
22
  ) {
23
- super(...baseConstructorParams);
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
 
@@ -3,4 +3,5 @@ export * from "./cachedRpcFactory";
3
3
  export * from "./defaultRpcFactory";
4
4
  export * from "./rateLimitedRpcFactory";
5
5
  export * from "./retryRpcFactory";
6
+ export * from "./quorumFallbackRpcFactory";
6
7
  export * from "./utils";