@chainlink/ccip-sdk 0.91.0 → 0.92.0

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 (273) hide show
  1. package/README.md +127 -80
  2. package/dist/aptos/hasher.d.ts.map +1 -1
  3. package/dist/aptos/hasher.js +7 -6
  4. package/dist/aptos/hasher.js.map +1 -1
  5. package/dist/aptos/index.d.ts +7 -2
  6. package/dist/aptos/index.d.ts.map +1 -1
  7. package/dist/aptos/index.js +29 -20
  8. package/dist/aptos/index.js.map +1 -1
  9. package/dist/aptos/logs.d.ts +5 -3
  10. package/dist/aptos/logs.d.ts.map +1 -1
  11. package/dist/aptos/logs.js +64 -27
  12. package/dist/aptos/logs.js.map +1 -1
  13. package/dist/aptos/token.d.ts.map +1 -1
  14. package/dist/aptos/token.js +2 -1
  15. package/dist/aptos/token.js.map +1 -1
  16. package/dist/aptos/types.js +6 -6
  17. package/dist/aptos/types.js.map +1 -1
  18. package/dist/chain.d.ts +36 -11
  19. package/dist/chain.d.ts.map +1 -1
  20. package/dist/chain.js +34 -2
  21. package/dist/chain.js.map +1 -1
  22. package/dist/commits.d.ts +2 -3
  23. package/dist/commits.d.ts.map +1 -1
  24. package/dist/commits.js +19 -8
  25. package/dist/commits.js.map +1 -1
  26. package/dist/errors/CCIPError.d.ts +48 -0
  27. package/dist/errors/CCIPError.d.ts.map +1 -0
  28. package/dist/errors/CCIPError.js +65 -0
  29. package/dist/errors/CCIPError.js.map +1 -0
  30. package/dist/errors/codes.d.ts +120 -0
  31. package/dist/errors/codes.d.ts.map +1 -0
  32. package/dist/errors/codes.js +156 -0
  33. package/dist/errors/codes.js.map +1 -0
  34. package/dist/errors/index.d.ts +26 -0
  35. package/dist/errors/index.d.ts.map +1 -0
  36. package/dist/errors/index.js +51 -0
  37. package/dist/errors/index.js.map +1 -0
  38. package/dist/errors/recovery.d.ts +6 -0
  39. package/dist/errors/recovery.d.ts.map +1 -0
  40. package/dist/errors/recovery.js +118 -0
  41. package/dist/errors/recovery.js.map +1 -0
  42. package/dist/errors/specialized.d.ts +637 -0
  43. package/dist/errors/specialized.d.ts.map +1 -0
  44. package/dist/errors/specialized.js +1298 -0
  45. package/dist/errors/specialized.js.map +1 -0
  46. package/dist/errors/utils.d.ts +11 -0
  47. package/dist/errors/utils.d.ts.map +1 -0
  48. package/dist/errors/utils.js +61 -0
  49. package/dist/errors/utils.js.map +1 -0
  50. package/dist/evm/abi/CommitStore_1_5.js +1 -1
  51. package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1 -1
  52. package/dist/evm/abi/OffRamp_1_5.js +1 -1
  53. package/dist/evm/abi/OnRamp_1_5.js +1 -1
  54. package/dist/evm/abi/PriceRegistry_1_2.d.ts +443 -0
  55. package/dist/evm/abi/PriceRegistry_1_2.d.ts.map +1 -0
  56. package/dist/evm/abi/PriceRegistry_1_2.js +439 -0
  57. package/dist/evm/abi/PriceRegistry_1_2.js.map +1 -0
  58. package/dist/evm/const.d.ts +1 -0
  59. package/dist/evm/const.d.ts.map +1 -1
  60. package/dist/evm/const.js +2 -0
  61. package/dist/evm/const.js.map +1 -1
  62. package/dist/evm/hasher.d.ts.map +1 -1
  63. package/dist/evm/hasher.js +7 -6
  64. package/dist/evm/hasher.js.map +1 -1
  65. package/dist/evm/index.d.ts +9 -13
  66. package/dist/evm/index.d.ts.map +1 -1
  67. package/dist/evm/index.js +85 -68
  68. package/dist/evm/index.js.map +1 -1
  69. package/dist/evm/logs.d.ts.map +1 -1
  70. package/dist/evm/logs.js +47 -16
  71. package/dist/evm/logs.js.map +1 -1
  72. package/dist/evm/messages.d.ts +7 -6
  73. package/dist/evm/messages.d.ts.map +1 -1
  74. package/dist/evm/offchain.js +1 -1
  75. package/dist/evm/offchain.js.map +1 -1
  76. package/dist/evm/types.d.ts +10 -0
  77. package/dist/evm/types.d.ts.map +1 -0
  78. package/dist/evm/types.js +2 -0
  79. package/dist/evm/types.js.map +1 -0
  80. package/dist/execution.d.ts.map +1 -1
  81. package/dist/execution.js +9 -5
  82. package/dist/execution.js.map +1 -1
  83. package/dist/extra-args.d.ts.map +1 -1
  84. package/dist/extra-args.js +4 -3
  85. package/dist/extra-args.js.map +1 -1
  86. package/dist/gas.d.ts.map +1 -1
  87. package/dist/gas.js +3 -2
  88. package/dist/gas.js.map +1 -1
  89. package/dist/hasher/hasher.d.ts.map +1 -1
  90. package/dist/hasher/hasher.js +2 -1
  91. package/dist/hasher/hasher.js.map +1 -1
  92. package/dist/hasher/merklemulti.d.ts.map +1 -1
  93. package/dist/hasher/merklemulti.js +9 -8
  94. package/dist/hasher/merklemulti.js.map +1 -1
  95. package/dist/index.d.ts +5 -2
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +6 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/offchain.d.ts.map +1 -1
  100. package/dist/offchain.js +5 -8
  101. package/dist/offchain.js.map +1 -1
  102. package/dist/requests.d.ts +1 -1
  103. package/dist/requests.d.ts.map +1 -1
  104. package/dist/requests.js +37 -43
  105. package/dist/requests.js.map +1 -1
  106. package/dist/selectors.d.ts.map +1 -1
  107. package/dist/selectors.js +22 -0
  108. package/dist/selectors.js.map +1 -1
  109. package/dist/solana/cleanup.d.ts +2 -2
  110. package/dist/solana/cleanup.d.ts.map +1 -1
  111. package/dist/solana/cleanup.js +2 -3
  112. package/dist/solana/cleanup.js.map +1 -1
  113. package/dist/solana/exec.d.ts.map +1 -1
  114. package/dist/solana/exec.js +12 -12
  115. package/dist/solana/exec.js.map +1 -1
  116. package/dist/solana/hasher.d.ts.map +1 -1
  117. package/dist/solana/hasher.js +6 -5
  118. package/dist/solana/hasher.js.map +1 -1
  119. package/dist/solana/index.d.ts +30 -13
  120. package/dist/solana/index.d.ts.map +1 -1
  121. package/dist/solana/index.js +96 -143
  122. package/dist/solana/index.js.map +1 -1
  123. package/dist/solana/logs.d.ts +15 -0
  124. package/dist/solana/logs.d.ts.map +1 -0
  125. package/dist/solana/logs.js +106 -0
  126. package/dist/solana/logs.js.map +1 -0
  127. package/dist/solana/offchain.d.ts.map +1 -1
  128. package/dist/solana/offchain.js +6 -5
  129. package/dist/solana/offchain.js.map +1 -1
  130. package/dist/solana/patchBorsh.d.ts.map +1 -1
  131. package/dist/solana/patchBorsh.js +3 -2
  132. package/dist/solana/patchBorsh.js.map +1 -1
  133. package/dist/solana/send.d.ts.map +1 -1
  134. package/dist/solana/send.js +8 -7
  135. package/dist/solana/send.js.map +1 -1
  136. package/dist/solana/utils.d.ts +7 -8
  137. package/dist/solana/utils.d.ts.map +1 -1
  138. package/dist/solana/utils.js +23 -11
  139. package/dist/solana/utils.js.map +1 -1
  140. package/dist/sui/discovery.d.ts +18 -0
  141. package/dist/sui/discovery.d.ts.map +1 -0
  142. package/dist/sui/discovery.js +116 -0
  143. package/dist/sui/discovery.js.map +1 -0
  144. package/dist/sui/events.d.ts +36 -0
  145. package/dist/sui/events.d.ts.map +1 -0
  146. package/dist/sui/events.js +179 -0
  147. package/dist/sui/events.js.map +1 -0
  148. package/dist/sui/hasher.d.ts.map +1 -1
  149. package/dist/sui/hasher.js +6 -5
  150. package/dist/sui/hasher.js.map +1 -1
  151. package/dist/sui/index.d.ts +69 -41
  152. package/dist/sui/index.d.ts.map +1 -1
  153. package/dist/sui/index.js +402 -65
  154. package/dist/sui/index.js.map +1 -1
  155. package/dist/sui/manuallyExec/encoder.d.ts +8 -0
  156. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -0
  157. package/dist/sui/manuallyExec/encoder.js +76 -0
  158. package/dist/sui/manuallyExec/encoder.js.map +1 -0
  159. package/dist/sui/manuallyExec/index.d.ts +37 -0
  160. package/dist/sui/manuallyExec/index.d.ts.map +1 -0
  161. package/dist/sui/manuallyExec/index.js +81 -0
  162. package/dist/sui/manuallyExec/index.js.map +1 -0
  163. package/dist/sui/objects.d.ts +46 -0
  164. package/dist/sui/objects.d.ts.map +1 -0
  165. package/dist/sui/objects.js +259 -0
  166. package/dist/sui/objects.js.map +1 -0
  167. package/dist/ton/bindings/offramp.d.ts +48 -0
  168. package/dist/ton/bindings/offramp.d.ts.map +1 -0
  169. package/dist/ton/bindings/offramp.js +63 -0
  170. package/dist/ton/bindings/offramp.js.map +1 -0
  171. package/dist/ton/bindings/onramp.d.ts +40 -0
  172. package/dist/ton/bindings/onramp.d.ts.map +1 -0
  173. package/dist/ton/bindings/onramp.js +51 -0
  174. package/dist/ton/bindings/onramp.js.map +1 -0
  175. package/dist/ton/bindings/router.d.ts +47 -0
  176. package/dist/ton/bindings/router.d.ts.map +1 -0
  177. package/dist/ton/bindings/router.js +51 -0
  178. package/dist/ton/bindings/router.js.map +1 -0
  179. package/dist/ton/exec.d.ts +18 -0
  180. package/dist/ton/exec.d.ts.map +1 -0
  181. package/dist/ton/exec.js +28 -0
  182. package/dist/ton/exec.js.map +1 -0
  183. package/dist/ton/hasher.d.ts +27 -0
  184. package/dist/ton/hasher.d.ts.map +1 -0
  185. package/dist/ton/hasher.js +134 -0
  186. package/dist/ton/hasher.js.map +1 -0
  187. package/dist/ton/index.d.ts +247 -0
  188. package/dist/ton/index.d.ts.map +1 -0
  189. package/dist/ton/index.js +781 -0
  190. package/dist/ton/index.js.map +1 -0
  191. package/dist/ton/logs.d.ts +26 -0
  192. package/dist/ton/logs.d.ts.map +1 -0
  193. package/dist/ton/logs.js +126 -0
  194. package/dist/ton/logs.js.map +1 -0
  195. package/dist/ton/types.d.ts +37 -0
  196. package/dist/ton/types.d.ts.map +1 -0
  197. package/dist/ton/types.js +92 -0
  198. package/dist/ton/types.js.map +1 -0
  199. package/dist/ton/utils.d.ts +67 -0
  200. package/dist/ton/utils.d.ts.map +1 -0
  201. package/dist/ton/utils.js +425 -0
  202. package/dist/ton/utils.js.map +1 -0
  203. package/dist/types.d.ts +4 -2
  204. package/dist/types.d.ts.map +1 -1
  205. package/dist/types.js +1 -0
  206. package/dist/types.js.map +1 -1
  207. package/dist/utils.d.ts +10 -0
  208. package/dist/utils.d.ts.map +1 -1
  209. package/dist/utils.js +52 -17
  210. package/dist/utils.js.map +1 -1
  211. package/package.json +12 -10
  212. package/src/aptos/hasher.ts +10 -6
  213. package/src/aptos/index.ts +50 -31
  214. package/src/aptos/logs.ts +85 -29
  215. package/src/aptos/token.ts +5 -1
  216. package/src/aptos/types.ts +6 -6
  217. package/src/chain.ts +83 -12
  218. package/src/commits.ts +23 -11
  219. package/src/errors/CCIPError.ts +86 -0
  220. package/src/errors/codes.ts +179 -0
  221. package/src/errors/index.ts +175 -0
  222. package/src/errors/recovery.ts +170 -0
  223. package/src/errors/specialized.ts +1655 -0
  224. package/src/errors/utils.ts +73 -0
  225. package/src/evm/abi/CommitStore_1_5.ts +1 -1
  226. package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1 -1
  227. package/src/evm/abi/OffRamp_1_5.ts +1 -1
  228. package/src/evm/abi/OnRamp_1_5.ts +1 -1
  229. package/src/evm/abi/PriceRegistry_1_2.ts +438 -0
  230. package/src/evm/const.ts +2 -0
  231. package/src/evm/hasher.ts +7 -6
  232. package/src/evm/index.ts +104 -86
  233. package/src/evm/logs.ts +64 -16
  234. package/src/evm/messages.ts +14 -14
  235. package/src/evm/offchain.ts +1 -1
  236. package/src/evm/types.ts +11 -0
  237. package/src/execution.ts +13 -9
  238. package/src/extra-args.ts +4 -3
  239. package/src/gas.ts +10 -3
  240. package/src/hasher/hasher.ts +2 -1
  241. package/src/hasher/merklemulti.ts +18 -8
  242. package/src/index.ts +14 -2
  243. package/src/offchain.ts +10 -14
  244. package/src/requests.ts +51 -53
  245. package/src/selectors.ts +23 -0
  246. package/src/solana/cleanup.ts +2 -4
  247. package/src/solana/exec.ts +13 -13
  248. package/src/solana/hasher.ts +9 -5
  249. package/src/solana/index.ts +126 -200
  250. package/src/solana/logs.ts +155 -0
  251. package/src/solana/offchain.ts +10 -7
  252. package/src/solana/patchBorsh.ts +3 -2
  253. package/src/solana/send.ts +14 -7
  254. package/src/solana/utils.ts +31 -17
  255. package/src/sui/discovery.ts +163 -0
  256. package/src/sui/events.ts +328 -0
  257. package/src/sui/hasher.ts +6 -5
  258. package/src/sui/index.ts +528 -80
  259. package/src/sui/manuallyExec/encoder.ts +88 -0
  260. package/src/sui/manuallyExec/index.ts +137 -0
  261. package/src/sui/objects.ts +358 -0
  262. package/src/ton/bindings/offramp.ts +96 -0
  263. package/src/ton/bindings/onramp.ts +72 -0
  264. package/src/ton/bindings/router.ts +65 -0
  265. package/src/ton/exec.ts +44 -0
  266. package/src/ton/hasher.ts +184 -0
  267. package/src/ton/index.ts +989 -0
  268. package/src/ton/logs.ts +157 -0
  269. package/src/ton/types.ts +143 -0
  270. package/src/ton/utils.ts +514 -0
  271. package/src/types.ts +6 -2
  272. package/src/utils.ts +58 -23
  273. package/tsconfig.json +2 -1
@@ -13,7 +13,6 @@ import {
13
13
  SYSVAR_CLOCK_PUBKEY,
14
14
  SystemProgram,
15
15
  } from '@solana/web3.js'
16
- import type BN from 'bn.js'
17
16
  import bs58 from 'bs58'
18
17
  import {
19
18
  type BytesLike,
@@ -29,13 +28,31 @@ import {
29
28
  import { type Memoized, memoize } from 'micro-memoize'
30
29
  import type { PickDeep, SetRequired } from 'type-fest'
31
30
 
31
+ import { type LogFilter, type TokenInfo, type TokenPoolRemote, Chain } from '../chain.ts'
32
32
  import {
33
- type LogFilter,
34
- type RateLimiterState,
35
- type TokenInfo,
36
- type TokenPoolRemote,
37
- Chain,
38
- } from '../chain.ts'
33
+ CCIPBlockTimeNotFoundError,
34
+ CCIPContractNotRouterError,
35
+ CCIPDataFormatUnsupportedError,
36
+ CCIPExecutionReportChainMismatchError,
37
+ CCIPExecutionStateInvalidError,
38
+ CCIPExtraArgsInvalidError,
39
+ CCIPExtraArgsLengthInvalidError,
40
+ CCIPLogDataMissingError,
41
+ CCIPLogsAddressRequiredError,
42
+ CCIPOnRampRequiredError,
43
+ CCIPSolanaExtraArgsEncodingError,
44
+ CCIPSolanaOffRampEventsNotFoundError,
45
+ CCIPSolanaRefAddressesNotFoundError,
46
+ CCIPSolanaTopicsInvalidError,
47
+ CCIPSplTokenInvalidError,
48
+ CCIPTokenDataParseError,
49
+ CCIPTokenNotConfiguredError,
50
+ CCIPTokenPoolChainConfigNotFoundError,
51
+ CCIPTokenPoolInfoNotFoundError,
52
+ CCIPTokenPoolStateNotFoundError,
53
+ CCIPTransactionNotFoundError,
54
+ CCIPWalletInvalidError,
55
+ } from '../errors/index.ts'
39
56
  import { type EVMExtraArgsV2, type ExtraArgs, EVMExtraArgsV2Tag } from '../extra-args.ts'
40
57
  import type { LeafHasher } from '../hasher/common.ts'
41
58
  import SELECTORS from '../selectors.ts'
@@ -61,6 +78,7 @@ import {
61
78
  ExecutionState,
62
79
  } from '../types.ts'
63
80
  import {
81
+ bytesToBuffer,
64
82
  createRateLimitedFetch,
65
83
  decodeAddress,
66
84
  decodeOnRampAddress,
@@ -79,11 +97,12 @@ import { IDL as BURN_MINT_TOKEN_POOL } from './idl/1.6.0/BURN_MINT_TOKEN_POOL.ts
79
97
  import { IDL as CCIP_CCTP_TOKEN_POOL } from './idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts'
80
98
  import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
81
99
  import { IDL as CCIP_ROUTER_IDL } from './idl/1.6.0/CCIP_ROUTER.ts'
100
+ import { getTransactionsForAddress } from './logs.ts'
82
101
  import { fetchSolanaOffchainTokenData } from './offchain.ts'
83
102
  import { generateUnsignedCcipSend, getFee } from './send.ts'
84
103
  import { type CCIPMessage_V1_6_Solana, type UnsignedSolanaTx, isWallet } from './types.ts'
85
104
  import {
86
- bytesToBuffer,
105
+ convertRateLimiter,
87
106
  getErrorFromLogs,
88
107
  hexDiscriminator,
89
108
  parseSolanaLogs,
@@ -99,18 +118,20 @@ import { patchBorsh } from './patchBorsh.ts'
99
118
 
100
119
  const routerCoder = new BorshCoder(CCIP_ROUTER_IDL)
101
120
  const offrampCoder = new BorshCoder(CCIP_OFFRAMP_IDL)
102
- const tokenPoolCoder = new BorshCoder({
121
+ const TOKEN_POOL_IDL = {
103
122
  ...BURN_MINT_TOKEN_POOL,
104
123
  types: BASE_TOKEN_POOL.types,
105
124
  events: BASE_TOKEN_POOL.events,
106
125
  errors: [...BASE_TOKEN_POOL.errors, ...BURN_MINT_TOKEN_POOL.errors],
107
- })
108
- const cctpTokenPoolCoder = new BorshCoder({
126
+ }
127
+ const tokenPoolCoder = new BorshCoder(TOKEN_POOL_IDL)
128
+ const CCTP_TOKEN_POOL_IDL = {
109
129
  ...CCIP_CCTP_TOKEN_POOL,
110
130
  types: [...BASE_TOKEN_POOL.types, ...CCIP_CCTP_TOKEN_POOL.types],
111
131
  events: [...BASE_TOKEN_POOL.events, ...CCIP_CCTP_TOKEN_POOL.events],
112
132
  errors: [...BASE_TOKEN_POOL.errors, ...CCIP_CCTP_TOKEN_POOL.errors],
113
- })
133
+ }
134
+ const cctpTokenPoolCoder = new BorshCoder(CCTP_TOKEN_POOL_IDL)
114
135
  // const commonCoder = new BorshCoder(CCIP_COMMON_IDL)
115
136
 
116
137
  interface ParsedTokenInfo {
@@ -148,6 +169,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
148
169
 
149
170
  connection: Connection
150
171
  commitment: Commitment = 'confirmed'
172
+ readonly destroy$: Promise<void>
151
173
 
152
174
  /**
153
175
  * Creates a new SolanaChain instance.
@@ -158,6 +180,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
158
180
  super(network, ctx)
159
181
 
160
182
  this.connection = connection
183
+ this.destroy$ = new Promise<void>((resolve) => (this.destroy = resolve))
161
184
 
162
185
  // Memoize expensive operations
163
186
  this.typeAndVersion = memoize(this.typeAndVersion.bind(this), {
@@ -167,7 +190,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
167
190
  this.getBlockTimestamp = memoize(this.getBlockTimestamp.bind(this), {
168
191
  async: true,
169
192
  maxSize: 100,
170
- forceUpdate: (key) => typeof key[key.length - 1] !== 'number',
193
+ forceUpdate: ([k]) => typeof k !== 'number' || k <= 0,
171
194
  })
172
195
  this.getTransaction = memoize(this.getTransaction.bind(this), {
173
196
  maxSize: 100,
@@ -220,7 +243,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
220
243
  static _getConnection(url: string, ctx?: WithLogger): Connection {
221
244
  const { logger = console } = ctx ?? {}
222
245
  if (!url.startsWith('http') && !url.startsWith('ws')) {
223
- throw new Error(
246
+ throw new CCIPDataFormatUnsupportedError(
224
247
  `Invalid Solana RPC URL format (should be https://, http://, wss://, or ws://): ${url}`,
225
248
  )
226
249
  }
@@ -258,19 +281,21 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
258
281
 
259
282
  // cached
260
283
  /** {@inheritDoc Chain.getBlockTimestamp} */
261
- async getBlockTimestamp(block: number | 'finalized'): Promise<number> {
262
- if (block === 'finalized') {
263
- const slot = await this.connection.getSlot('finalized')
284
+ async getBlockTimestamp(block: number | 'latest' | 'finalized'): Promise<number> {
285
+ if (typeof block !== 'number') {
286
+ const slot = await this.connection.getSlot(block === 'latest' ? 'confirmed' : block)
264
287
  const blockTime = await this.connection.getBlockTime(slot)
265
288
  if (blockTime === null) {
266
- throw new Error(`Could not get block time for finalized slot ${slot}`)
289
+ throw new CCIPBlockTimeNotFoundError(`finalized slot ${slot}`)
267
290
  }
268
291
  return blockTime
292
+ } else if (block <= 0) {
293
+ block = (await this.connection.getSlot('confirmed')) + block
269
294
  }
270
295
 
271
296
  const blockTime = await this.connection.getBlockTime(block)
272
297
  if (blockTime === null) {
273
- throw new Error(`Could not get block time for slot ${block}`)
298
+ throw new CCIPBlockTimeNotFoundError(block)
274
299
  }
275
300
  return blockTime
276
301
  }
@@ -281,7 +306,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
281
306
  commitment: 'confirmed',
282
307
  maxSupportedTransactionVersion: 0,
283
308
  })
284
- if (!tx) throw new Error(`Transaction not found: ${hash}`)
309
+ if (!tx) throw new CCIPTransactionNotFoundError(hash)
285
310
  if (tx.blockTime) {
286
311
  ;(
287
312
  this.getBlockTimestamp as Memoized<typeof this.getBlockTimestamp, { async: true }>
@@ -321,69 +346,9 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
321
346
  async *getTransactionsForAddress(
322
347
  opts: Omit<LogFilter, 'topics'>,
323
348
  ): AsyncGenerator<SolanaTransaction> {
324
- if (!opts.address) throw new Error('Program address is required for Solana log filtering')
325
-
326
- let allSignatures
327
- const limit = Math.min(opts?.page || 1000, 1000)
328
- if (opts.startBlock || opts.startTime) {
329
- // forward collect all matching sigs in array
330
- allSignatures = [] as Awaited<ReturnType<typeof this.connection.getSignaturesForAddress>>
331
- let batch: typeof allSignatures
332
- do {
333
- batch = await this.connection.getSignaturesForAddress(
334
- new PublicKey(opts.address),
335
- { limit, before: allSignatures[allSignatures.length - 1]?.signature },
336
- 'confirmed',
337
- )
338
-
339
- while (
340
- batch.length > 0 &&
341
- (batch[batch.length - 1].slot < (opts.startBlock || 0) ||
342
- (batch[batch.length - 1].blockTime || -1) < (opts.startTime || 0))
343
- ) {
344
- batch.length-- // truncate tail of txs which are older than requested start
345
- }
346
-
347
- allSignatures.push(...batch) // concat in descending order
348
- } while (batch.length >= limit)
349
-
350
- allSignatures.reverse()
351
-
352
- while (
353
- opts.endBlock &&
354
- allSignatures.length > 0 &&
355
- allSignatures[allSignatures.length - 1].slot > opts.endBlock
356
- ) {
357
- allSignatures.length-- // truncate head (after reverse) of txs newer than requested end
358
- }
359
- } else {
360
- allSignatures = async function* (this: SolanaChain) {
361
- let batch: Awaited<ReturnType<typeof this.connection.getSignaturesForAddress>> | undefined
362
- do {
363
- batch = await this.connection.getSignaturesForAddress(
364
- new PublicKey(opts.address!),
365
- {
366
- limit,
367
- before: batch?.length
368
- ? batch[batch.length - 1].signature
369
- : opts.endBefore
370
- ? opts.endBefore
371
- : undefined,
372
- },
373
- 'confirmed',
374
- )
375
- for (const sig of batch) {
376
- if (opts.endBlock && sig.slot > opts.endBlock) continue
377
- yield sig
378
- }
379
- } while (batch.length >= limit)
380
- }.call(this) // generate backwards until depleting getSignaturesForAddress
381
- }
382
-
383
- // Process signatures
384
- for await (const signatureInfo of allSignatures) {
385
- yield await this.getTransaction(signatureInfo.signature)
386
- }
349
+ if (opts.watch instanceof Promise)
350
+ opts = { ...opts, watch: Promise.race([opts.watch, this.destroy$]) }
351
+ yield* getTransactionsForAddress(opts, this)
387
352
  }
388
353
 
389
354
  /**
@@ -404,45 +369,46 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
404
369
  * - `startBlock`: Starting slot number (inclusive)
405
370
  * - `startTime`: Starting Unix timestamp (inclusive)
406
371
  * - `endBlock`: Ending slot number (inclusive)
372
+ * - `endBefore`: Fetch signatures before this transaction
407
373
  * - `address`: Program address to filter logs by (required for Solana)
408
374
  * - `topics`: Array of topics to filter logs by (optional); either 0x-8B discriminants or event names
375
+ * - `watch`: Watch for new logs
409
376
  * - `programs`: Special option to allow querying by address of interest, but yielding matching
410
377
  * logs from specific (string address) program or any (true)
411
- * - `commit`: Special param for fetching ExecutionReceipts, to narrow down the search
412
378
  * @returns AsyncIterableIterator of parsed Log_ objects.
413
379
  */
414
380
  async *getLogs(
415
- opts: LogFilter & { sender?: string; programs?: string[] | true; commit?: CommitReport },
381
+ opts: LogFilter & { programs?: string[] | true },
416
382
  ): AsyncGenerator<Log_ & { tx: SolanaTransaction }> {
417
383
  let programs: true | string[]
418
- if (opts.sender && !opts.address) {
419
- // specialization for fetching txs/requests for a given account of interest without a programID
420
- opts.address = opts.sender
421
- programs = true
422
- } else if (!opts.address) {
423
- throw new Error('Program address is required for Solana log filtering')
384
+ if (!opts.address) {
385
+ throw new CCIPLogsAddressRequiredError()
424
386
  } else if (!opts.programs) {
425
387
  programs = [opts.address]
426
388
  } else {
427
389
  programs = opts.programs
428
390
  }
391
+ let topics
429
392
  if (opts.topics?.length) {
430
393
  if (!opts.topics.every((topic) => typeof topic === 'string'))
431
- throw new Error('Topics must be strings')
394
+ throw new CCIPSolanaTopicsInvalidError()
432
395
  // append events discriminants (if not 0x-8B already), but keep OG topics
433
- opts.topics.push(
396
+ topics = [
397
+ ...opts.topics,
434
398
  ...opts.topics.filter((t) => !isHexString(t, 8)).map((t) => hexDiscriminator(t)),
435
- )
399
+ ]
436
400
  }
437
401
 
438
402
  // Process signatures and yield logs
439
403
  for await (const tx of this.getTransactionsForAddress(opts)) {
440
- for (const log of tx.logs) {
404
+ let logs = tx.logs
405
+ if (opts.startBlock == null && opts.startTime == null) logs = logs.toReversed() // backwards
406
+ for (const log of logs) {
441
407
  // Filter and yield logs from the specified program, and which match event discriminant or log prefix
442
408
  if (
443
409
  (programs !== true && !programs.includes(log.address)) ||
444
- (opts.topics?.length &&
445
- !(opts.topics as string[]).some(
410
+ (topics &&
411
+ !topics.some(
446
412
  (t) =>
447
413
  t === log.topics[0] || (typeof log.data === 'string' && log.data.startsWith(t)),
448
414
  ))
@@ -464,7 +430,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
464
430
  onRamp?: string,
465
431
  opts?: { page?: number },
466
432
  ): Promise<CCIPRequest> {
467
- if (!onRamp) throw new Error('onRamp is required')
433
+ if (!onRamp) throw new CCIPOnRampRequiredError()
468
434
  return fetchCCIPRequestById(this, messageId, { address: onRamp, ...opts })
469
435
  }
470
436
 
@@ -472,7 +438,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
472
438
  async fetchAllMessagesInBatch<
473
439
  R extends PickDeep<
474
440
  CCIPRequest,
475
- 'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.header.sequenceNumber'
441
+ 'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
476
442
  >,
477
443
  >(
478
444
  request: R,
@@ -528,8 +494,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
528
494
  offRamp_,
529
495
  )
530
496
  const referenceAddressesPda = await this.connection.getAccountInfo(referenceAddressesAddr)
531
- if (!referenceAddressesPda)
532
- throw new Error(`referenceAddresses account not found for offRamp=${offRamp}`)
497
+ if (!referenceAddressesPda) throw new CCIPSolanaRefAddressesNotFoundError(offRamp)
533
498
 
534
499
  // Decode the config account using the program's coder
535
500
  const { router }: { router: PublicKey } = program.coder.accounts.decode(
@@ -562,7 +527,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
562
527
  })) {
563
528
  return [log.address] // assume single offramp per router/deployment on Solana
564
529
  }
565
- throw new Error(`Could not find OffRamp events in feeQuoter=${feeQuoter.toString()} txs`)
530
+ throw new CCIPSolanaOffRampEventsNotFoundError(feeQuoter.toString())
566
531
  }
567
532
 
568
533
  /** {@inheritDoc Chain.getOnRampForRouter} */
@@ -599,7 +564,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
599
564
  /** {@inheritDoc Chain.getTokenForTokenPool} */
600
565
  async getTokenForTokenPool(tokenPool: string): Promise<string> {
601
566
  const tokenPoolInfo = await this.connection.getAccountInfo(new PublicKey(tokenPool))
602
- if (!tokenPoolInfo) throw new Error(`TokenPool info not found: ${tokenPool}`)
567
+ if (!tokenPoolInfo) throw new CCIPTokenPoolInfoNotFoundError(tokenPool)
603
568
  const { config }: { config: { mint: PublicKey } } = tokenPoolCoder.accounts.decode(
604
569
  'state',
605
570
  tokenPoolInfo.data,
@@ -620,7 +585,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
620
585
  mintInfo.value.data.program !== 'spl-token' &&
621
586
  mintInfo.value.data.program !== 'spl-token-2022')
622
587
  ) {
623
- throw new Error(`Invalid SPL token or Token-2022: ${token}`)
588
+ throw new CCIPSplTokenInvalidError(token)
624
589
  }
625
590
 
626
591
  if (typeof mintInfo.value.data === 'object' && 'parsed' in mintInfo.value.data) {
@@ -653,7 +618,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
653
618
  decimals: data.decimals,
654
619
  }
655
620
  } else {
656
- throw new Error(`Unable to parse token data for ${token}`)
621
+ throw new CCIPTokenDataParseError(token)
657
622
  }
658
623
  }
659
624
 
@@ -747,14 +712,13 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
747
712
  const message = decoded.data.message
748
713
 
749
714
  // Convert BN/number types to bigints
715
+ const messageId = hexlify(new Uint8Array(message.header.messageId))
750
716
  const sourceChainSelector = BigInt(message.header.sourceChainSelector.toString())
751
717
  const destChainSelector = BigInt(message.header.destChainSelector.toString())
752
718
  const sequenceNumber = BigInt(message.header.sequenceNumber.toString())
753
719
  const nonce = BigInt(message.header.nonce.toString())
754
720
  const destNetwork = networkInfo(destChainSelector)
755
721
 
756
- // Convert message fields to expected format
757
- const messageId = hexlify(new Uint8Array(message.header.messageId))
758
722
  const sender = message.sender.toString()
759
723
  const data_ = getDataBytes(message.data)
760
724
  // TODO: extract this into a proper normalize/decode/reencode data utility
@@ -780,17 +744,16 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
780
744
  // Parse gas limit from extraArgs
781
745
  const extraArgs = hexlify(message.extraArgs)
782
746
  const parsed = this.decodeExtraArgs(extraArgs)
783
- if (!parsed) throw new Error('Invalid extraArgs: ' + extraArgs)
747
+ if (!parsed) throw new CCIPExtraArgsInvalidError('SVM', extraArgs)
784
748
  const { _tag, ...rest } = parsed
785
749
 
786
750
  return {
787
- header: {
788
- messageId,
789
- sourceChainSelector,
790
- destChainSelector: destChainSelector,
791
- sequenceNumber: sequenceNumber,
792
- nonce,
793
- },
751
+ // merge header fields to message
752
+ messageId,
753
+ sourceChainSelector,
754
+ destChainSelector: destChainSelector,
755
+ sequenceNumber: sequenceNumber,
756
+ nonce,
794
757
  sender,
795
758
  receiver,
796
759
  data: msgData,
@@ -823,7 +786,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
823
786
  allowOutOfOrderExecution: data[4 + 16] == 1,
824
787
  }
825
788
  }
826
- throw new Error(`Unsupported EVMExtraArgsV2 length: ${dataLength(data)}`)
789
+ throw new CCIPExtraArgsLengthInvalidError(dataLength(data))
827
790
  }
828
791
  default:
829
792
  return
@@ -836,7 +799,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
836
799
  * @returns Encoded extra arguments as hex string.
837
800
  */
838
801
  static encodeExtraArgs(args: ExtraArgs): string {
839
- if ('computeUnits' in args) throw new Error('Solana can only encode EVMExtraArgsV2')
802
+ if ('computeUnits' in args) throw new CCIPSolanaExtraArgsEncodingError()
840
803
  const gasLimitUint128Le = toLeArray(args.gasLimit, 16)
841
804
  return concat([
842
805
  EVMExtraArgsV2Tag,
@@ -857,7 +820,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
857
820
  ): CommitReport[] | undefined {
858
821
  // Check if this is a CommitReportAccepted event by looking at the discriminant
859
822
  if (!log.data || typeof log.data !== 'string') {
860
- throw new Error('Log data is missing or not a string')
823
+ throw new CCIPLogDataMissingError()
861
824
  }
862
825
 
863
826
  try {
@@ -908,7 +871,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
908
871
  static decodeReceipt(log: Pick<Log_, 'data' | 'tx' | 'index'>): ExecutionReceipt | undefined {
909
872
  // Check if this is a ExecutionStateChanged event by looking at the discriminant
910
873
  if (!log.data || typeof log.data !== 'string') {
911
- throw new Error('Log data is missing or not a string')
874
+ throw new CCIPLogDataMissingError()
912
875
  }
913
876
 
914
877
  try {
@@ -935,7 +898,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
935
898
  state = ExecutionState.Success
936
899
  } else if (decoded.data.state.failure) {
937
900
  state = ExecutionState.Failed
938
- } else throw new Error(`Invalid ExecutionState: ${util.inspect(decoded.data.state)}`)
901
+ } else throw new CCIPExecutionStateInvalidError(util.inspect(decoded.data.state))
939
902
 
940
903
  let returnData
941
904
  if (log.tx) {
@@ -980,6 +943,19 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
980
943
  return encodeBase58(getDataBytes(bytes))
981
944
  }
982
945
 
946
+ /**
947
+ * Validates a transaction hash format for Solana
948
+ */
949
+ static isTxHash(v: unknown): v is string {
950
+ if (typeof v !== 'string') return false
951
+ try {
952
+ return bs58.decode(v).length === 64
953
+ } catch (_) {
954
+ // pass
955
+ }
956
+ return false
957
+ }
958
+
983
959
  /**
984
960
  * Gets the leaf hasher for Solana destination chains.
985
961
  * @param lane - Lane configuration.
@@ -992,7 +968,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
992
968
  /** {@inheritDoc Chain.getTokenAdminRegistryFor} */
993
969
  async getTokenAdminRegistryFor(address: string): Promise<string> {
994
970
  const [type] = await this.typeAndVersion(address)
995
- if (!type.includes('Router')) throw new Error(`Not a Router: ${address} is ${type}`)
971
+ if (!type.includes('Router')) throw new CCIPContractNotRouterError(address, type)
996
972
  // Solana implements TokenAdminRegistry in the Router/OnRamp program
997
973
  return address
998
974
  }
@@ -1040,7 +1016,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1040
1016
  opts: { wallet: unknown; approveMax?: boolean },
1041
1017
  ): Promise<CCIPRequest> {
1042
1018
  const wallet = opts.wallet
1043
- if (!isWallet(wallet)) throw new Error(`Expected Wallet, got=${util.inspect(wallet)}`)
1019
+ if (!isWallet(wallet)) throw new CCIPWalletInvalidError(util.inspect(wallet))
1044
1020
  const unsigned = await this.generateUnsignedSendMessage(
1045
1021
  wallet.publicKey.toBase58(),
1046
1022
  router,
@@ -1079,7 +1055,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1079
1055
  opts?: { forceBuffer?: boolean; forceLookupTable?: boolean },
1080
1056
  ): Promise<UnsignedSolanaTx> {
1081
1057
  if (!('computeUnits' in execReport_.message))
1082
- throw new Error("ExecutionReport's message not for Solana")
1058
+ throw new CCIPExecutionReportChainMismatchError('Solana')
1083
1059
  const execReport = execReport_ as ExecutionReport<CCIPMessage_V1_6_Solana>
1084
1060
  const offRamp_ = new PublicKey(offRamp)
1085
1061
  return generateUnsignedExecuteReport(this, new PublicKey(payer), offRamp_, execReport, opts)
@@ -1098,7 +1074,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1098
1074
  },
1099
1075
  ): Promise<ChainTransaction> {
1100
1076
  const wallet = opts.wallet
1101
- if (!isWallet(wallet)) throw new Error(`Expected Wallet, got=${util.inspect(wallet)}`)
1077
+ if (!isWallet(wallet)) throw new CCIPWalletInvalidError(util.inspect(wallet))
1102
1078
 
1103
1079
  let hash
1104
1080
  do {
@@ -1143,8 +1119,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1143
1119
  */
1144
1120
  async cleanUpBuffers(opts: { wallet: unknown; waitDeactivation?: boolean }): Promise<void> {
1145
1121
  const wallet = opts.wallet
1146
- if (!isWallet(wallet)) throw new Error(`Expected Wallet, got=${util.inspect(wallet)}`)
1147
- await cleanUpBuffers(this, wallet, this.getLogs.bind(this), opts)
1122
+ if (!isWallet(wallet)) throw new CCIPWalletInvalidError(util.inspect(wallet))
1123
+ await cleanUpBuffers(this, wallet, opts)
1148
1124
  }
1149
1125
 
1150
1126
  /**
@@ -1181,8 +1157,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1181
1157
  */
1182
1158
  override async fetchCommitReport(
1183
1159
  commitStore: string,
1184
- request: PickDeep<CCIPRequest, 'lane' | 'message.header.sequenceNumber' | 'tx.timestamp'>,
1185
- hints?: { startBlock?: number; page?: number },
1160
+ request: PickDeep<CCIPRequest, 'lane' | 'message.sequenceNumber' | 'tx.timestamp'>,
1161
+ hints?: Pick<LogFilter, 'page' | 'watch'> & { startBlock?: number },
1186
1162
  ): Promise<CCIPCommit> {
1187
1163
  const commitsAroundSeqNum = await this.connection.getProgramAccounts(
1188
1164
  new PublicKey(commitStore),
@@ -1205,7 +1181,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1205
1181
  {
1206
1182
  memcmp: {
1207
1183
  offset: 8 + 1 + 8 + 32 + 8 + 1,
1208
- bytes: encodeBase58(toLeArray(request.message.header.sequenceNumber, 8).slice(1)),
1184
+ bytes: encodeBase58(toLeArray(request.message.sequenceNumber, 8).slice(1)),
1209
1185
  },
1210
1186
  },
1211
1187
  ],
@@ -1215,10 +1191,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1215
1191
  // const merkleRoot = acc.account.data.subarray(8 + 1 + 8, 8 + 1 + 8 + 32)
1216
1192
  const minSeqNr = acc.account.data.readBigUInt64LE(8 + 1 + 8 + 32 + 8)
1217
1193
  const maxSeqNr = acc.account.data.readBigUInt64LE(8 + 1 + 8 + 32 + 8 + 8)
1218
- if (
1219
- minSeqNr > request.message.header.sequenceNumber ||
1220
- maxSeqNr < request.message.header.sequenceNumber
1221
- )
1194
+ if (minSeqNr > request.message.sequenceNumber || maxSeqNr < request.message.sequenceNumber)
1222
1195
  continue
1223
1196
  // we have all the commit report info, but we also need log details (txHash, etc)
1224
1197
  for await (const log of this.getLogs({
@@ -1242,9 +1215,9 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1242
1215
  /** {@inheritDoc Chain.fetchExecutionReceipts} */
1243
1216
  override async *fetchExecutionReceipts(
1244
1217
  offRamp: string,
1245
- request: PickDeep<CCIPRequest, 'lane' | 'message.header.messageId' | 'tx.timestamp'>,
1218
+ request: PickDeep<CCIPRequest, 'lane' | 'message.messageId' | 'tx.timestamp'>,
1246
1219
  commit?: CCIPCommit,
1247
- opts?: { page?: number },
1220
+ opts?: Pick<LogFilter, 'page' | 'watch'>,
1248
1221
  ): AsyncIterableIterator<CCIPExecution> {
1249
1222
  let opts_: Parameters<SolanaChain['getLogs']>[0] | undefined = opts
1250
1223
  if (commit) {
@@ -1284,8 +1257,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1284
1257
  )
1285
1258
 
1286
1259
  const tokenAdminRegistry = await this.connection.getAccountInfo(tokenAdminRegistryAddr)
1287
- if (!tokenAdminRegistry)
1288
- throw new Error(`Token ${token} is not configured in registry ${registry}`)
1260
+ if (!tokenAdminRegistry) throw new CCIPTokenNotConfiguredError(token, registry)
1289
1261
 
1290
1262
  const config: {
1291
1263
  administrator: string
@@ -1331,10 +1303,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1331
1303
  }> {
1332
1304
  // `tokenPool` is actually a State PDA in the tokenPoolProgram
1333
1305
  const tokenPoolState = await this.connection.getAccountInfo(new PublicKey(tokenPool))
1334
- if (!tokenPoolState) throw new Error(`TokenPool State PDA not found at ${tokenPool}`)
1335
-
1336
- const { config }: { config: { mint: PublicKey; router: PublicKey } } =
1337
- tokenPoolCoder.accounts.decode('state', tokenPoolState.data)
1306
+ if (!tokenPoolState || tokenPoolState.data.length < 266 + 32)
1307
+ throw new CCIPTokenPoolStateNotFoundError(tokenPool)
1338
1308
  const tokenPoolProgram = tokenPoolState.owner.toBase58()
1339
1309
 
1340
1310
  let typeAndVersion
@@ -1344,9 +1314,14 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1344
1314
  // TokenPool may not have a typeAndVersion
1345
1315
  }
1346
1316
 
1317
+ // const { config }: { config: IdlTypes<typeof BASE_TOKEN_POOL>['BaseConfig'] } =
1318
+ // tokenPoolCoder.accounts.decode('state', tokenPoolState.data)
1319
+ const mint = new PublicKey(tokenPoolState.data.subarray(41, 41 + 32))
1320
+ const router = new PublicKey(tokenPoolState.data.subarray(266, 266 + 32))
1321
+
1347
1322
  return {
1348
- token: config.mint.toBase58(),
1349
- router: config.router.toBase58(),
1323
+ token: mint.toBase58(),
1324
+ router: router.toBase58(),
1350
1325
  tokenPoolProgram,
1351
1326
  typeAndVersion,
1352
1327
  }
@@ -1359,7 +1334,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1359
1334
  ): Promise<Record<string, TokenPoolRemote>> {
1360
1335
  // `tokenPool` is actually a State PDA in the tokenPoolProgram
1361
1336
  const tokenPoolState = await this.connection.getAccountInfo(new PublicKey(tokenPool))
1362
- if (!tokenPoolState) throw new Error(`TokenPool State PDA not found at ${tokenPool}`)
1337
+ if (!tokenPoolState) throw new CCIPTokenPoolStateNotFoundError(tokenPool)
1363
1338
 
1364
1339
  const tokenPoolProgram = tokenPoolState.owner
1365
1340
 
@@ -1385,8 +1360,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1385
1360
  )
1386
1361
  const chainConfigAcc = await this.connection.getAccountInfo(chainConfigAddr)
1387
1362
  if (!chainConfigAcc)
1388
- throw new Error(
1389
- `ChainConfig not found at ${chainConfigAddr.toBase58()} for tokenPool=${tokenPool} and remoteNetwork=${networkInfo(remoteChainSelector).name}`,
1363
+ throw new CCIPTokenPoolChainConfigNotFoundError(
1364
+ chainConfigAddr.toBase58(),
1365
+ tokenPool,
1366
+ networkInfo(remoteChainSelector).name,
1390
1367
  )
1391
1368
  accounts = [
1392
1369
  {
@@ -1408,31 +1385,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1408
1385
 
1409
1386
  for (const acc of accounts) {
1410
1387
  try {
1411
- let base: {
1412
- remote: {
1413
- poolAddresses: { address: Buffer }[]
1414
- tokenAddress: { address: Buffer }
1415
- decimals: number
1416
- }
1417
- inboundRateLimit: {
1418
- tokens: BN
1419
- lastUpdated: BN
1420
- cfg: {
1421
- enabled: boolean
1422
- capacity: BN
1423
- rate: BN
1424
- }
1425
- }
1426
- outboundRateLimit: {
1427
- tokens: BN
1428
- lastUpdated: BN
1429
- cfg: {
1430
- enabled: boolean
1431
- capacity: BN
1432
- rate: BN
1433
- }
1434
- }
1435
- }
1388
+ let base: IdlTypes<typeof BASE_TOKEN_POOL>['BaseChain']
1436
1389
  try {
1437
1390
  ;({ base } = tokenPoolCoder.accounts.decode('chainConfig', acc.account.data))
1438
1391
  } catch (_) {
@@ -1465,35 +1418,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1465
1418
  decodeAddress(pool.address, remoteNetwork.family),
1466
1419
  )
1467
1420
 
1468
- let inboundRateLimiterState: RateLimiterState = null
1469
- if (base.inboundRateLimit.cfg.enabled) {
1470
- inboundRateLimiterState = {
1471
- tokens: BigInt(base.inboundRateLimit.tokens.toString()),
1472
- capacity: BigInt(base.inboundRateLimit.cfg.capacity.toString()),
1473
- rate: BigInt(base.inboundRateLimit.cfg.rate.toString()),
1474
- }
1475
- const cur =
1476
- inboundRateLimiterState.tokens +
1477
- inboundRateLimiterState.rate *
1478
- BigInt(Math.floor(Date.now() / 1000) - base.inboundRateLimit.lastUpdated.toNumber())
1479
- if (cur < inboundRateLimiterState.capacity) inboundRateLimiterState.tokens = cur
1480
- else inboundRateLimiterState.tokens = inboundRateLimiterState.capacity
1481
- }
1482
-
1483
- let outboundRateLimiterState: RateLimiterState = null
1484
- if (base.outboundRateLimit.cfg.enabled) {
1485
- outboundRateLimiterState = {
1486
- tokens: BigInt(base.outboundRateLimit.tokens.toString()),
1487
- capacity: BigInt(base.outboundRateLimit.cfg.capacity.toString()),
1488
- rate: BigInt(base.outboundRateLimit.cfg.rate.toString()),
1489
- }
1490
- const cur =
1491
- outboundRateLimiterState.tokens +
1492
- outboundRateLimiterState.rate *
1493
- BigInt(Math.floor(Date.now() / 1000) - base.outboundRateLimit.lastUpdated.toNumber())
1494
- if (cur < outboundRateLimiterState.capacity) outboundRateLimiterState.tokens = cur
1495
- else outboundRateLimiterState.tokens = outboundRateLimiterState.capacity
1496
- }
1421
+ const inboundRateLimiterState = convertRateLimiter(base.inboundRateLimit)
1422
+ const outboundRateLimiterState = convertRateLimiter(base.outboundRateLimit)
1497
1423
 
1498
1424
  remotes[remoteNetwork.name] = {
1499
1425
  remoteToken,