@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.
Files changed (123) 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 +76 -26
  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 +7 -6
  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 +33 -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 +7 -6
  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 +75 -25
  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 +8 -7
  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 +33 -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 +7 -6
  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/clients/SpokePoolClient/SVMSpokePoolClient.d.ts.map +1 -1
  93. package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts +1 -1
  94. package/dist/types/providers/mocks/MockCachedSolanaRpcFactory.d.ts.map +1 -1
  95. package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts +1 -1
  96. package/dist/types/providers/mocks/MockRateLimitedSolanaRpcFactory.d.ts.map +1 -1
  97. package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts +1 -1
  98. package/dist/types/providers/mocks/MockRetrySolanaRpcFactory.d.ts.map +1 -1
  99. package/dist/types/providers/solana/baseRpcFactories.d.ts +3 -3
  100. package/dist/types/providers/solana/baseRpcFactories.d.ts.map +1 -1
  101. package/dist/types/providers/solana/cachedRpcFactory.d.ts.map +1 -1
  102. package/dist/types/providers/solana/index.d.ts +1 -0
  103. package/dist/types/providers/solana/index.d.ts.map +1 -1
  104. package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts +17 -0
  105. package/dist/types/providers/solana/quorumFallbackRpcFactory.d.ts.map +1 -0
  106. package/dist/types/providers/utils.d.ts +1 -0
  107. package/dist/types/providers/utils.d.ts.map +1 -1
  108. package/package.json +1 -1
  109. package/src/arch/svm/BlockUtils.ts +3 -1
  110. package/src/arch/svm/SpokeUtils.ts +69 -15
  111. package/src/arch/svm/utils.ts +9 -5
  112. package/src/clients/BaseAbstractClient.ts +25 -8
  113. package/src/clients/BundleDataClient/BundleDataClient.ts +2 -1
  114. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +5 -1
  115. package/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +6 -5
  116. package/src/providers/mocks/MockCachedSolanaRpcFactory.ts +1 -1
  117. package/src/providers/mocks/MockRateLimitedSolanaRpcFactory.ts +1 -1
  118. package/src/providers/mocks/MockRetrySolanaRpcFactory.ts +1 -1
  119. package/src/providers/solana/baseRpcFactories.ts +3 -3
  120. package/src/providers/solana/cachedRpcFactory.ts +2 -0
  121. package/src/providers/solana/index.ts +1 -0
  122. package/src/providers/solana/quorumFallbackRpcFactory.ts +248 -0
  123. 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.41",
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, 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 { slot: currentSlot } = await getNearestSlotTime(provider);
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
- atHeight?: number,
317
- logger?: Logger
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 toSlot = atHeight ? BigInt(atHeight) : (await getNearestSlotTime(provider)).slot;
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
- toSlot ??= Number((await getNearestSlotTime(svmEventsClient.getRpc())).slot);
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) => {
@@ -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 provider.getSlot(opts).send();
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
- 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 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(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 };
@@ -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, atHeight, this.logger);
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(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";