@chainlink/ccip-sdk 0.95.0 → 0.97.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 (217) hide show
  1. package/README.md +2 -2
  2. package/dist/all-chains.d.ts +23 -0
  3. package/dist/all-chains.d.ts.map +1 -0
  4. package/dist/all-chains.js +24 -0
  5. package/dist/all-chains.js.map +1 -0
  6. package/dist/api/index.d.ts +31 -19
  7. package/dist/api/index.d.ts.map +1 -1
  8. package/dist/api/index.js +46 -25
  9. package/dist/api/index.js.map +1 -1
  10. package/dist/api/types.d.ts +24 -30
  11. package/dist/api/types.d.ts.map +1 -1
  12. package/dist/aptos/exec.d.ts +2 -2
  13. package/dist/aptos/exec.d.ts.map +1 -1
  14. package/dist/aptos/exec.js.map +1 -1
  15. package/dist/aptos/hasher.d.ts.map +1 -1
  16. package/dist/aptos/hasher.js +1 -1
  17. package/dist/aptos/hasher.js.map +1 -1
  18. package/dist/aptos/index.d.ts +43 -15
  19. package/dist/aptos/index.d.ts.map +1 -1
  20. package/dist/aptos/index.js +112 -105
  21. package/dist/aptos/index.js.map +1 -1
  22. package/dist/aptos/types.d.ts +2 -19
  23. package/dist/aptos/types.d.ts.map +1 -1
  24. package/dist/aptos/types.js +0 -11
  25. package/dist/aptos/types.js.map +1 -1
  26. package/dist/chain.d.ts +734 -174
  27. package/dist/chain.d.ts.map +1 -1
  28. package/dist/chain.js +216 -31
  29. package/dist/chain.js.map +1 -1
  30. package/dist/commits.d.ts +4 -6
  31. package/dist/commits.d.ts.map +1 -1
  32. package/dist/commits.js +4 -4
  33. package/dist/commits.js.map +1 -1
  34. package/dist/errors/CCIPError.d.ts +33 -4
  35. package/dist/errors/CCIPError.d.ts.map +1 -1
  36. package/dist/errors/CCIPError.js +33 -4
  37. package/dist/errors/CCIPError.js.map +1 -1
  38. package/dist/errors/codes.d.ts +5 -0
  39. package/dist/errors/codes.d.ts.map +1 -1
  40. package/dist/errors/codes.js +5 -1
  41. package/dist/errors/codes.js.map +1 -1
  42. package/dist/errors/index.d.ts +2 -2
  43. package/dist/errors/index.d.ts.map +1 -1
  44. package/dist/errors/index.js +2 -2
  45. package/dist/errors/index.js.map +1 -1
  46. package/dist/errors/recovery.d.ts.map +1 -1
  47. package/dist/errors/recovery.js +6 -1
  48. package/dist/errors/recovery.js.map +1 -1
  49. package/dist/errors/specialized.d.ts +1702 -121
  50. package/dist/errors/specialized.d.ts.map +1 -1
  51. package/dist/errors/specialized.js +1729 -125
  52. package/dist/errors/specialized.js.map +1 -1
  53. package/dist/errors/utils.d.ts.map +1 -1
  54. package/dist/errors/utils.js +0 -1
  55. package/dist/errors/utils.js.map +1 -1
  56. package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
  57. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
  58. package/dist/evm/abi/OffRamp_2_0.js +744 -0
  59. package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
  60. package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
  61. package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
  62. package/dist/evm/abi/OnRamp_2_0.js +992 -0
  63. package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
  64. package/dist/evm/const.d.ts +12 -2
  65. package/dist/evm/const.d.ts.map +1 -1
  66. package/dist/evm/const.js +8 -2
  67. package/dist/evm/const.js.map +1 -1
  68. package/dist/evm/errors.d.ts.map +1 -1
  69. package/dist/evm/errors.js +7 -2
  70. package/dist/evm/errors.js.map +1 -1
  71. package/dist/evm/extra-args.d.ts +25 -0
  72. package/dist/evm/extra-args.d.ts.map +1 -0
  73. package/dist/evm/extra-args.js +309 -0
  74. package/dist/evm/extra-args.js.map +1 -0
  75. package/dist/evm/gas.d.ts.map +1 -1
  76. package/dist/evm/gas.js +7 -12
  77. package/dist/evm/gas.js.map +1 -1
  78. package/dist/evm/hasher.d.ts.map +1 -1
  79. package/dist/evm/hasher.js +23 -13
  80. package/dist/evm/hasher.js.map +1 -1
  81. package/dist/evm/index.d.ts +140 -35
  82. package/dist/evm/index.d.ts.map +1 -1
  83. package/dist/evm/index.js +306 -226
  84. package/dist/evm/index.js.map +1 -1
  85. package/dist/evm/messages.d.ts +59 -5
  86. package/dist/evm/messages.d.ts.map +1 -1
  87. package/dist/evm/messages.js +210 -0
  88. package/dist/evm/messages.js.map +1 -1
  89. package/dist/evm/offchain.js.map +1 -1
  90. package/dist/evm/types.d.ts +7 -2
  91. package/dist/evm/types.d.ts.map +1 -1
  92. package/dist/evm/types.js +22 -1
  93. package/dist/evm/types.js.map +1 -1
  94. package/dist/execution.d.ts +62 -22
  95. package/dist/execution.d.ts.map +1 -1
  96. package/dist/execution.js +102 -51
  97. package/dist/execution.js.map +1 -1
  98. package/dist/extra-args.d.ts +113 -4
  99. package/dist/extra-args.d.ts.map +1 -1
  100. package/dist/extra-args.js +38 -3
  101. package/dist/extra-args.js.map +1 -1
  102. package/dist/gas.d.ts +31 -5
  103. package/dist/gas.d.ts.map +1 -1
  104. package/dist/gas.js +43 -9
  105. package/dist/gas.js.map +1 -1
  106. package/dist/index.d.ts +11 -10
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +8 -8
  109. package/dist/index.js.map +1 -1
  110. package/dist/requests.d.ts +101 -22
  111. package/dist/requests.d.ts.map +1 -1
  112. package/dist/requests.js +115 -24
  113. package/dist/requests.js.map +1 -1
  114. package/dist/selectors.d.ts.map +1 -1
  115. package/dist/selectors.js +24 -0
  116. package/dist/selectors.js.map +1 -1
  117. package/dist/shared/bcs-codecs.d.ts +61 -0
  118. package/dist/shared/bcs-codecs.d.ts.map +1 -0
  119. package/dist/shared/bcs-codecs.js +102 -0
  120. package/dist/shared/bcs-codecs.js.map +1 -0
  121. package/dist/shared/constants.d.ts +3 -0
  122. package/dist/shared/constants.d.ts.map +1 -0
  123. package/dist/shared/constants.js +3 -0
  124. package/dist/shared/constants.js.map +1 -0
  125. package/dist/solana/exec.d.ts +2 -2
  126. package/dist/solana/exec.d.ts.map +1 -1
  127. package/dist/solana/exec.js.map +1 -1
  128. package/dist/solana/index.d.ts +148 -30
  129. package/dist/solana/index.d.ts.map +1 -1
  130. package/dist/solana/index.js +137 -44
  131. package/dist/solana/index.js.map +1 -1
  132. package/dist/sui/hasher.d.ts.map +1 -1
  133. package/dist/sui/hasher.js +1 -1
  134. package/dist/sui/hasher.js.map +1 -1
  135. package/dist/sui/index.d.ts +49 -19
  136. package/dist/sui/index.d.ts.map +1 -1
  137. package/dist/sui/index.js +76 -43
  138. package/dist/sui/index.js.map +1 -1
  139. package/dist/sui/manuallyExec/encoder.d.ts +2 -2
  140. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
  141. package/dist/sui/manuallyExec/encoder.js.map +1 -1
  142. package/dist/sui/manuallyExec/index.d.ts +2 -2
  143. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  144. package/dist/ton/exec.d.ts +2 -2
  145. package/dist/ton/exec.d.ts.map +1 -1
  146. package/dist/ton/exec.js.map +1 -1
  147. package/dist/ton/index.d.ts +66 -27
  148. package/dist/ton/index.d.ts.map +1 -1
  149. package/dist/ton/index.js +172 -47
  150. package/dist/ton/index.js.map +1 -1
  151. package/dist/ton/send.d.ts +52 -0
  152. package/dist/ton/send.d.ts.map +1 -0
  153. package/dist/ton/send.js +166 -0
  154. package/dist/ton/send.js.map +1 -0
  155. package/dist/ton/types.d.ts +2 -2
  156. package/dist/ton/types.d.ts.map +1 -1
  157. package/dist/ton/types.js.map +1 -1
  158. package/dist/types.d.ts +148 -12
  159. package/dist/types.d.ts.map +1 -1
  160. package/dist/types.js +6 -1
  161. package/dist/types.js.map +1 -1
  162. package/dist/utils.d.ts +79 -4
  163. package/dist/utils.d.ts.map +1 -1
  164. package/dist/utils.js +92 -7
  165. package/dist/utils.js.map +1 -1
  166. package/package.json +16 -11
  167. package/src/all-chains.ts +26 -0
  168. package/src/api/index.ts +58 -34
  169. package/src/api/types.ts +24 -31
  170. package/src/aptos/exec.ts +2 -2
  171. package/src/aptos/hasher.ts +1 -1
  172. package/src/aptos/index.ts +127 -129
  173. package/src/aptos/types.ts +2 -15
  174. package/src/chain.ts +837 -191
  175. package/src/commits.ts +9 -9
  176. package/src/errors/CCIPError.ts +33 -4
  177. package/src/errors/codes.ts +5 -1
  178. package/src/errors/index.ts +2 -1
  179. package/src/errors/recovery.ts +9 -1
  180. package/src/errors/specialized.ts +1745 -132
  181. package/src/errors/utils.ts +0 -1
  182. package/src/evm/abi/OffRamp_2_0.ts +743 -0
  183. package/src/evm/abi/OnRamp_2_0.ts +991 -0
  184. package/src/evm/const.ts +10 -3
  185. package/src/evm/errors.ts +6 -2
  186. package/src/evm/extra-args.ts +360 -0
  187. package/src/evm/gas.ts +14 -13
  188. package/src/evm/hasher.ts +30 -18
  189. package/src/evm/index.ts +376 -281
  190. package/src/evm/messages.ts +323 -11
  191. package/src/evm/offchain.ts +2 -2
  192. package/src/evm/types.ts +20 -2
  193. package/src/execution.ts +126 -71
  194. package/src/extra-args.ts +118 -4
  195. package/src/gas.ts +44 -11
  196. package/src/index.ts +14 -11
  197. package/src/requests.ts +128 -24
  198. package/src/selectors.ts +24 -0
  199. package/src/shared/bcs-codecs.ts +132 -0
  200. package/src/shared/constants.ts +2 -0
  201. package/src/solana/exec.ts +4 -4
  202. package/src/solana/index.ts +170 -82
  203. package/src/sui/hasher.ts +1 -1
  204. package/src/sui/index.ts +88 -56
  205. package/src/sui/manuallyExec/encoder.ts +2 -2
  206. package/src/sui/manuallyExec/index.ts +2 -2
  207. package/src/ton/exec.ts +2 -2
  208. package/src/ton/index.ts +220 -58
  209. package/src/ton/send.ts +222 -0
  210. package/src/ton/types.ts +2 -2
  211. package/src/types.ts +173 -30
  212. package/src/utils.ts +91 -7
  213. package/dist/aptos/utils.d.ts +0 -12
  214. package/dist/aptos/utils.d.ts.map +0 -1
  215. package/dist/aptos/utils.js +0 -15
  216. package/dist/aptos/utils.js.map +0 -1
  217. package/src/aptos/utils.ts +0 -24
@@ -73,14 +73,14 @@ import SELECTORS from '../selectors.ts'
73
73
  import { supportedChains } from '../supported-chains.ts'
74
74
  import {
75
75
  type AnyMessage,
76
- type CCIPCommit,
77
76
  type CCIPExecution,
78
77
  type CCIPMessage,
79
78
  type CCIPRequest,
79
+ type CCIPVerifications,
80
80
  type ChainTransaction,
81
81
  type CommitReport,
82
+ type ExecutionInput,
82
83
  type ExecutionReceipt,
83
- type ExecutionReport,
84
84
  type Lane,
85
85
  type Log_,
86
86
  type MergeArrayElements,
@@ -96,6 +96,7 @@ import {
96
96
  createRateLimitedFetch,
97
97
  decodeAddress,
98
98
  decodeOnRampAddress,
99
+ getAddressBytes,
99
100
  getDataBytes,
100
101
  leToBigInt,
101
102
  networkInfo,
@@ -126,7 +127,7 @@ import {
126
127
  } from './utils.ts'
127
128
  import { buildMessageForDest, getMessagesInBatch } from '../requests.ts'
128
129
  import { patchBorsh } from './patchBorsh.ts'
129
- import { DEFAULT_GAS_LIMIT } from '../evm/const.ts'
130
+ import { DEFAULT_GAS_LIMIT } from '../shared/constants.ts'
130
131
  export type { UnsignedSolanaTx }
131
132
 
132
133
  const routerCoder = new BorshCoder(CCIP_ROUTER_IDL)
@@ -171,6 +172,29 @@ export type SolanaTransaction = MergeArrayElements<
171
172
 
172
173
  /**
173
174
  * Solana chain implementation supporting Solana networks.
175
+ *
176
+ * Provides methods for sending CCIP cross-chain messages, querying message
177
+ * status, fetching fee quotes, and manually executing pending messages on
178
+ * Solana networks.
179
+ *
180
+ * @remarks
181
+ * Solana uses CCIP v1.6+ protocol only.
182
+ *
183
+ * @example Create from RPC URL
184
+ * ```typescript
185
+ * import { SolanaChain } from '@chainlink/ccip-sdk'
186
+ *
187
+ * const chain = await SolanaChain.fromUrl('https://api.devnet.solana.com')
188
+ * console.log(`Connected to: ${chain.network.name}`)
189
+ * ```
190
+ *
191
+ * @example Query messages in a transaction
192
+ * ```typescript
193
+ * const requests = await chain.getMessagesInTx('5abc123...')
194
+ * for (const req of requests) {
195
+ * console.log(`Message ID: ${req.message.messageId}`)
196
+ * }
197
+ * ```
174
198
  */
175
199
  export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
176
200
  static {
@@ -252,6 +276,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
252
276
  * @param url - RPC endpoint URL (https://, http://, wss://, or ws://).
253
277
  * @param ctx - context containing logger.
254
278
  * @returns Solana Connection instance.
279
+ * @throws {@link CCIPDataFormatUnsupportedError} if URL format is invalid
255
280
  */
256
281
  static _getConnection(url: string, ctx?: WithLogger): Connection {
257
282
  const { logger = console } = ctx ?? {}
@@ -283,9 +308,20 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
283
308
 
284
309
  /**
285
310
  * Creates a SolanaChain instance from an RPC URL.
286
- * @param url - RPC endpoint URL.
287
- * @param ctx - context containing logger.
288
- * @returns A new SolanaChain instance.
311
+ *
312
+ * @param url - RPC endpoint URL (https://, http://, wss://, or ws://).
313
+ * @param ctx - Optional context containing logger and API client configuration.
314
+ * @returns A new SolanaChain instance connected to the specified network.
315
+ * @throws {@link CCIPChainNotFoundError} if chain cannot be identified from genesis hash
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * // Create from devnet URL
320
+ * const chain = await SolanaChain.fromUrl('https://api.devnet.solana.com')
321
+ *
322
+ * // With custom logger
323
+ * const chain = await SolanaChain.fromUrl(url, { logger: customLogger })
324
+ * ```
289
325
  */
290
326
  static async fromUrl(url: string, ctx?: ChainContext): Promise<SolanaChain> {
291
327
  const connection = this._getConnection(url, ctx)
@@ -293,7 +329,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
293
329
  }
294
330
 
295
331
  // cached
296
- /** {@inheritDoc Chain.getBlockTimestamp} */
332
+ /**
333
+ * {@inheritDoc Chain.getBlockTimestamp}
334
+ * @throws {@link CCIPBlockTimeNotFoundError} if block time cannot be retrieved
335
+ */
297
336
  async getBlockTimestamp(block: number | 'latest' | 'finalized'): Promise<number> {
298
337
  if (typeof block !== 'number') {
299
338
  const slot = await this.connection.getSlot(block === 'latest' ? 'confirmed' : block)
@@ -313,7 +352,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
313
352
  return blockTime
314
353
  }
315
354
 
316
- /** {@inheritDoc Chain.getTransaction} */
355
+ /**
356
+ * {@inheritDoc Chain.getTransaction}
357
+ * @throws {@link CCIPTransactionNotFoundError} if transaction not found
358
+ */
317
359
  async getTransaction(hash: string): Promise<SolanaTransaction> {
318
360
  const tx = await this.connection.getTransaction(hash, {
319
361
  commitment: 'confirmed',
@@ -389,6 +431,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
389
431
  * - `programs`: Special option to allow querying by address of interest, but yielding matching
390
432
  * logs from specific (string address) program or any (true)
391
433
  * @returns AsyncIterableIterator of parsed Log_ objects.
434
+ * @throws {@link CCIPLogsAddressRequiredError} if address is not provided
435
+ * @throws {@link CCIPTopicsInvalidError} if topics contain invalid values
392
436
  */
393
437
  async *getLogs(
394
438
  opts: LogFilter & { programs?: string[] | true },
@@ -433,15 +477,15 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
433
477
  }
434
478
 
435
479
  /** {@inheritDoc Chain.getMessagesInBatch} */
436
- async getMessagesInBatch<
480
+ override async getMessagesInBatch<
437
481
  R extends PickDeep<
438
482
  CCIPRequest,
439
483
  'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
440
484
  >,
441
485
  >(
442
486
  request: R,
443
- commit: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
444
- opts?: { page?: number },
487
+ range: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
488
+ opts?: Pick<LogFilter, 'page'>,
445
489
  ): Promise<R['message'][]> {
446
490
  const [destChainStatePda] = PublicKey.findProgramAddressSync(
447
491
  [Buffer.from('dest_chain_state'), toLeArray(request.lane.destChainSelector, 8)],
@@ -454,7 +498,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
454
498
  programs: [request.log.address],
455
499
  address: destChainStatePda.toBase58(),
456
500
  }
457
- return getMessagesInBatch(this, request, commit, opts_)
501
+ return getMessagesInBatch(this, request, range, opts_)
458
502
  }
459
503
 
460
504
  /** {@inheritDoc Chain.typeAndVersion} */
@@ -480,7 +524,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
480
524
  return Promise.resolve(onRamp) // Solana's router is also the onRamp
481
525
  }
482
526
 
483
- /** {@inheritDoc Chain.getRouterForOffRamp} */
527
+ /**
528
+ * {@inheritDoc Chain.getRouterForOffRamp}
529
+ * @throws {@link CCIPSolanaRefAddressesNotFoundError} if reference addresses PDA not found
530
+ */
484
531
  async getRouterForOffRamp(offRamp: string, _sourceChainSelector: bigint): Promise<string> {
485
532
  const offRamp_ = new PublicKey(offRamp)
486
533
  const program = new Program(CCIP_OFFRAMP_IDL as Idl, offRamp_, {
@@ -507,7 +554,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
507
554
  return Promise.resolve(NATIVE_MINT.toBase58())
508
555
  }
509
556
 
510
- /** {@inheritDoc Chain.getOffRampsForRouter} */
557
+ /**
558
+ * {@inheritDoc Chain.getOffRampsForRouter}
559
+ * @throws {@link CCIPSolanaOffRampEventsNotFoundError} if no OffRamp events found
560
+ */
511
561
  async getOffRampsForRouter(router: string, sourceChainSelector: bigint): Promise<string[]> {
512
562
  // feeQuoter is present in router's config, and has a DestChainState account which is updated by
513
563
  // the offramps, so we can use it to narrow the search for the offramp
@@ -533,8 +583,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
533
583
  return Promise.resolve(router) // solana's Router is also the OnRamp
534
584
  }
535
585
 
536
- /** {@inheritDoc Chain.getOnRampForOffRamp} */
537
- async getOnRampForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
586
+ /** {@inheritDoc Chain.getOnRampsForOffRamp} */
587
+ async getOnRampsForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string[]> {
538
588
  const program = new Program(CCIP_OFFRAMP_IDL, new PublicKey(offRamp), {
539
589
  connection: this.connection,
540
590
  })
@@ -548,18 +598,18 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
548
598
  const {
549
599
  config: { onRamp },
550
600
  } = await program.account.sourceChain.fetch(statePda)
551
- return decodeAddress(
552
- new Uint8Array(onRamp.bytes.slice(0, onRamp.len)),
553
- networkInfo(sourceChainSelector).family,
554
- )
555
- }
556
-
557
- /** {@inheritDoc Chain.getCommitStoreForOffRamp} */
558
- getCommitStoreForOffRamp(offRamp: string): Promise<string> {
559
- return Promise.resolve(offRamp) // Solana supports only CCIP>=1.6, for which OffRamp and CommitStore are the same
601
+ return [
602
+ decodeAddress(
603
+ getAddressBytes(onRamp.bytes).subarray(0, onRamp.len),
604
+ networkInfo(sourceChainSelector).family,
605
+ ),
606
+ ]
560
607
  }
561
608
 
562
- /** {@inheritDoc Chain.getTokenForTokenPool} */
609
+ /**
610
+ * {@inheritDoc Chain.getTokenForTokenPool}
611
+ * @throws {@link CCIPTokenPoolInfoNotFoundError} if token pool info not found
612
+ */
563
613
  async getTokenForTokenPool(tokenPool: string): Promise<string> {
564
614
  const tokenPoolInfo = await this.connection.getAccountInfo(new PublicKey(tokenPool))
565
615
  if (!tokenPoolInfo) throw new CCIPTokenPoolInfoNotFoundError(tokenPool)
@@ -570,7 +620,11 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
570
620
  return config.mint.toString()
571
621
  }
572
622
 
573
- /** {@inheritDoc Chain.getTokenInfo} */
623
+ /**
624
+ * {@inheritDoc Chain.getTokenInfo}
625
+ * @throws {@link CCIPSplTokenInvalidError} if token is not a valid SPL token
626
+ * @throws {@link CCIPTokenDataParseError} if token data cannot be parsed
627
+ */
574
628
  async getTokenInfo(token: string): Promise<TokenInfo> {
575
629
  const mint = new PublicKey(token)
576
630
  const mintInfo = await this.connection.getParsedAccountInfo(mint)
@@ -619,7 +673,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
619
673
  }
620
674
  }
621
675
 
622
- /** {@inheritDoc Chain.getBalance} */
676
+ /**
677
+ * {@inheritDoc Chain.getBalance}
678
+ * @throws {@link CCIPTokenAccountNotFoundError} if token account not found
679
+ */
623
680
  async getBalance(opts: GetBalanceOpts): Promise<bigint> {
624
681
  const { holder, token } = opts
625
682
  const holderPubkey = new PublicKey(holder)
@@ -712,6 +769,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
712
769
  * Decodes a CCIP message from a Solana log event.
713
770
  * @param log - Log with data field.
714
771
  * @returns Decoded CCIPMessage or undefined if not valid.
772
+ * @throws {@link CCIPExtraArgsInvalidError} if extra args cannot be decoded
715
773
  */
716
774
  static decodeMessage({ data }: { data: unknown }): CCIPMessage | undefined {
717
775
  if (!data || typeof data !== 'string') return undefined
@@ -789,6 +847,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
789
847
  * Decodes extra arguments from Solana CCIP messages.
790
848
  * @param extraArgs - Encoded extra arguments bytes.
791
849
  * @returns Decoded EVMExtraArgsV2 or undefined if unknown format.
850
+ * @throws {@link CCIPExtraArgsLengthInvalidError} if extra args length is invalid
792
851
  */
793
852
  static decodeExtraArgs(
794
853
  extraArgs: BytesLike,
@@ -816,6 +875,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
816
875
  * Encodes extra arguments for Solana CCIP messages.
817
876
  * @param args - Extra arguments to encode.
818
877
  * @returns Encoded extra arguments as hex string.
878
+ * @throws {@link CCIPSolanaExtraArgsEncodingError} if SVMExtraArgsV1 encoding is attempted
819
879
  */
820
880
  static encodeExtraArgs(args: ExtraArgs): string {
821
881
  if ('computeUnits' in args) throw new CCIPSolanaExtraArgsEncodingError()
@@ -832,6 +892,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
832
892
  * @param log - Log with data field.
833
893
  * @param lane - Lane info for filtering.
834
894
  * @returns Array of CommitReport or undefined if not valid.
895
+ * @throws {@link CCIPLogDataMissingError} if log data is missing
835
896
  */
836
897
  static decodeCommits(
837
898
  log: Pick<Log_, 'data'>,
@@ -886,6 +947,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
886
947
  * Decodes an execution receipt from a Solana log event.
887
948
  * @param log - Log with data, tx, and index fields.
888
949
  * @returns ExecutionReceipt or undefined if not valid.
950
+ * @throws {@link CCIPLogDataMissingError} if log data is missing
951
+ * @throws {@link CCIPExecutionStateInvalidError} if execution state is invalid
889
952
  */
890
953
  static decodeReceipt(log: Pick<Log_, 'data' | 'tx' | 'index'>): ExecutionReceipt | undefined {
891
954
  // Check if this is a ExecutionStateChanged event by looking at the discriminant
@@ -984,7 +1047,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
984
1047
  return getV16SolanaLeafHasher(lane, ctx)
985
1048
  }
986
1049
 
987
- /** {@inheritDoc Chain.getTokenAdminRegistryFor} */
1050
+ /**
1051
+ * {@inheritDoc Chain.getTokenAdminRegistryFor}
1052
+ * @throws {@link CCIPContractNotRouterError} if address is not a Router
1053
+ */
988
1054
  async getTokenAdminRegistryFor(address: string): Promise<string> {
989
1055
  const [type] = await this.typeAndVersion(address)
990
1056
  if (!type.includes('Router')) throw new CCIPContractNotRouterError(address, type)
@@ -1026,7 +1092,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1026
1092
  )
1027
1093
  }
1028
1094
 
1029
- /** {@inheritDoc Chain.sendMessage} */
1095
+ /**
1096
+ * {@inheritDoc Chain.sendMessage}
1097
+ * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Solana wallet
1098
+ */
1030
1099
  async sendMessage(opts: Parameters<Chain['sendMessage']>[0]): Promise<CCIPRequest> {
1031
1100
  if (!isWallet(opts.wallet)) throw new CCIPWalletInvalidError(util.inspect(opts.wallet))
1032
1101
  const unsigned = await this.generateUnsignedSendMessage({
@@ -1044,22 +1113,22 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1044
1113
  }
1045
1114
 
1046
1115
  /**
1047
- * {@inheritDoc Chain.generateUnsignedExecuteReport}
1116
+ * {@inheritDoc Chain.generateUnsignedExecute}
1048
1117
  * @returns instructions - array of instructions to execute the report
1049
1118
  * lookupTables - array of lookup tables for `manuallyExecute` call
1050
1119
  * mainIndex - index of the `manuallyExecute` instruction in the array; last unless
1051
1120
  * forceLookupTable is set, in which case last is ALT deactivation tx, and manuallyExecute is
1052
1121
  * second to last
1122
+ * @throws {@link CCIPExecutionReportChainMismatchError} if message is not a Solana message
1053
1123
  */
1054
- async generateUnsignedExecuteReport({
1124
+ async generateUnsignedExecute({
1055
1125
  payer,
1056
- offRamp,
1057
- execReport,
1058
1126
  ...opts
1059
- }: Parameters<Chain['generateUnsignedExecuteReport']>[0]): Promise<UnsignedSolanaTx> {
1060
- if (!('computeUnits' in execReport.message))
1127
+ }: Parameters<Chain['generateUnsignedExecute']>[0]): Promise<UnsignedSolanaTx> {
1128
+ if (!('input' in opts) || !('message' in opts.input) || !('computeUnits' in opts.input.message))
1061
1129
  throw new CCIPExecutionReportChainMismatchError('Solana')
1062
- const execReport_ = execReport as ExecutionReport<CCIPMessage_V1_6_Solana>
1130
+ const { offRamp, input } = opts
1131
+ const execReport_ = input as ExecutionInput<CCIPMessage_V1_6_Solana>
1063
1132
  return generateUnsignedExecuteReport(
1064
1133
  this,
1065
1134
  new PublicKey(payer),
@@ -1069,9 +1138,12 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1069
1138
  )
1070
1139
  }
1071
1140
 
1072
- /** {@inheritDoc Chain.executeReport} */
1073
- async executeReport(
1074
- opts: Parameters<Chain['executeReport']>[0] & {
1141
+ /**
1142
+ * {@inheritDoc Chain.execute}
1143
+ * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Solana wallet
1144
+ */
1145
+ async execute(
1146
+ opts: Parameters<Chain['execute']>[0] & {
1075
1147
  // when cleaning leftover LookUp Tables, wait deactivation grace period (~513 slots) then close ALT
1076
1148
  waitDeactivation?: boolean
1077
1149
  },
@@ -1082,7 +1154,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1082
1154
  let hash
1083
1155
  do {
1084
1156
  try {
1085
- const unsigned = await this.generateUnsignedExecuteReport({
1157
+ const unsigned = await this.generateUnsignedExecute({
1086
1158
  ...opts,
1087
1159
  payer: wallet.publicKey.toBase58(),
1088
1160
  })
@@ -1118,6 +1190,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1118
1190
  * - waitDeactivation - Whether to wait for lookup table deactivation cool down period
1119
1191
  * (513 slots) to pass before closing; by default, we deactivate (if needed) and move on, to
1120
1192
  * close other ready ALTs
1193
+ * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Solana wallet
1121
1194
  */
1122
1195
  async cleanUpBuffers(opts: { wallet: unknown; waitDeactivation?: boolean }): Promise<void> {
1123
1196
  const wallet = opts.wallet
@@ -1157,39 +1230,36 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1157
1230
  /**
1158
1231
  * Solana specialization: use getProgramAccounts to fetch commit reports from PDAs
1159
1232
  */
1160
- override async getCommitReport(
1161
- opts: Parameters<Chain['getCommitReport']>[0],
1162
- ): Promise<CCIPCommit> {
1163
- const { commitStore, request } = opts
1164
- const commitsAroundSeqNum = await this.connection.getProgramAccounts(
1165
- new PublicKey(commitStore),
1166
- {
1167
- filters: [
1168
- {
1169
- // commit report account discriminator filter
1170
- memcmp: {
1171
- offset: 0,
1172
- bytes: encodeBase58(BorshAccountsCoder.accountDiscriminator('CommitReport')),
1173
- },
1233
+ override async getVerifications(
1234
+ opts: Parameters<Chain['getVerifications']>[0],
1235
+ ): Promise<CCIPVerifications> {
1236
+ const { offRamp, request } = opts
1237
+ const commitsAroundSeqNum = await this.connection.getProgramAccounts(new PublicKey(offRamp), {
1238
+ filters: [
1239
+ {
1240
+ // commit report account discriminator filter
1241
+ memcmp: {
1242
+ offset: 0,
1243
+ bytes: encodeBase58(BorshAccountsCoder.accountDiscriminator('CommitReport')),
1174
1244
  },
1175
- {
1176
- // sourceChainSelector filter
1177
- memcmp: {
1178
- offset: 8 + 1,
1179
- bytes: encodeBase58(toLeArray(request.lane.sourceChainSelector, 8)),
1180
- },
1245
+ },
1246
+ {
1247
+ // sourceChainSelector filter
1248
+ memcmp: {
1249
+ offset: 8 + 1,
1250
+ bytes: encodeBase58(toLeArray(request.lane.sourceChainSelector, 8)),
1181
1251
  },
1182
- // memcmp report.min with msg.sequenceNumber's without least-significant byte;
1183
- // this should be ~256 around seqNum, i.e. big chance of a match; requires PDAs not to have been closed
1184
- {
1185
- memcmp: {
1186
- offset: 8 + 1 + 8 + 32 + 8 + /*skip byte*/ 1,
1187
- bytes: encodeBase58(toLeArray(request.message.sequenceNumber, 8).slice(1)),
1188
- },
1252
+ },
1253
+ // memcmp report.min with msg.sequenceNumber's without least-significant byte;
1254
+ // this should be ~256 around seqNum, i.e. big chance of a match; requires PDAs not to have been closed
1255
+ {
1256
+ memcmp: {
1257
+ offset: 8 + 1 + 8 + 32 + 8 + /*skip byte*/ 1,
1258
+ bytes: encodeBase58(toLeArray(request.message.sequenceNumber, 8).slice(1)),
1189
1259
  },
1190
- ],
1191
- },
1192
- )
1260
+ },
1261
+ ],
1262
+ })
1193
1263
  for (const acc of commitsAroundSeqNum) {
1194
1264
  // const merkleRoot = acc.account.data.subarray(8 + 1 + 8, 8 + 1 + 8 + 32)
1195
1265
  const minSeqNr = acc.account.data.readBigUInt64LE(8 + 1 + 8 + 32 + 8)
@@ -1199,7 +1269,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1199
1269
  // we have all the commit report info, but we also need log details (txHash, etc)
1200
1270
  for await (const log of this.getLogs({
1201
1271
  startTime: 1, // just to force getting the oldest log first
1202
- programs: [commitStore],
1272
+ programs: [offRamp],
1203
1273
  address: acc.pubkey.toBase58(),
1204
1274
  topics: ['CommitReportAccepted'],
1205
1275
  })) {
@@ -1212,23 +1282,23 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1212
1282
  }
1213
1283
  }
1214
1284
  // in case we can't find it, fallback to generic iterating txs
1215
- return super.getCommitReport(opts)
1285
+ return super.getVerifications(opts)
1216
1286
  }
1217
1287
 
1218
1288
  /** {@inheritDoc Chain.getExecutionReceipts} */
1219
1289
  override async *getExecutionReceipts(
1220
1290
  opts: Parameters<Chain['getExecutionReceipts']>[0],
1221
1291
  ): AsyncIterableIterator<CCIPExecution> {
1222
- const { offRamp, sourceChainSelector, commit } = opts
1292
+ const { offRamp, sourceChainSelector, verifications } = opts
1223
1293
  let opts_: Parameters<Chain['getExecutionReceipts']>[0] &
1224
1294
  Parameters<SolanaChain['getLogs']>[0] = opts
1225
- if (commit && sourceChainSelector) {
1295
+ if (sourceChainSelector && verifications && 'report' in verifications) {
1226
1296
  // if we know of commit, use `commit_report` PDA as more specialized address
1227
1297
  const [commitReportPda] = PublicKey.findProgramAddressSync(
1228
1298
  [
1229
1299
  Buffer.from('commit_report'),
1230
1300
  toLeArray(sourceChainSelector, 8),
1231
- bytesToBuffer(commit.report.merkleRoot),
1301
+ bytesToBuffer(verifications.report.merkleRoot),
1232
1302
  ],
1233
1303
  new PublicKey(offRamp),
1234
1304
  )
@@ -1241,7 +1311,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1241
1311
  yield* super.getExecutionReceipts(opts_)
1242
1312
  }
1243
1313
 
1244
- /** {@inheritDoc Chain.getRegistryTokenConfig} */
1314
+ /**
1315
+ * {@inheritDoc Chain.getRegistryTokenConfig}
1316
+ * @throws {@link CCIPTokenNotConfiguredError} if token is not configured in registry
1317
+ */
1245
1318
  async getRegistryTokenConfig(
1246
1319
  registry: string,
1247
1320
  token: string,
@@ -1295,8 +1368,11 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1295
1368
  return config
1296
1369
  }
1297
1370
 
1298
- /** {@inheritDoc Chain.getTokenPoolConfigs} */
1299
- async getTokenPoolConfigs(tokenPool: string): Promise<{
1371
+ /**
1372
+ * {@inheritDoc Chain.getTokenPoolConfig}
1373
+ * @throws {@link CCIPTokenPoolStateNotFoundError} if token pool state not found
1374
+ */
1375
+ async getTokenPoolConfig(tokenPool: string): Promise<{
1300
1376
  token: string
1301
1377
  router: string
1302
1378
  tokenPoolProgram: string
@@ -1328,7 +1404,11 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1328
1404
  }
1329
1405
  }
1330
1406
 
1331
- /** {@inheritDoc Chain.getTokenPoolRemotes} */
1407
+ /**
1408
+ * {@inheritDoc Chain.getTokenPoolRemotes}
1409
+ * @throws {@link CCIPTokenPoolStateNotFoundError} if token pool state not found
1410
+ * @throws {@link CCIPTokenPoolChainConfigNotFoundError} if chain config not found for specified selector
1411
+ */
1332
1412
  async getTokenPoolRemotes(
1333
1413
  tokenPool: string,
1334
1414
  remoteChainSelector?: bigint,
@@ -1506,7 +1586,14 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1506
1586
  return program.account.config.fetch(configPda)
1507
1587
  }
1508
1588
 
1509
- /** {@inheritDoc ChainStatic.buildMessageForDest} */
1589
+ /**
1590
+ * Returns a copy of a message, populating missing fields like `extraArgs` with defaults.
1591
+ * It's expected to return a message suitable at least for basic token transfers.
1592
+ *
1593
+ * @param message - AnyMessage (from source), containing at least `receiver`
1594
+ * @returns A message suitable for `sendMessage` to this destination chain family
1595
+ * @throws {@link CCIPArgumentInvalidError} if tokenReceiver missing when sending tokens with data
1596
+ */
1510
1597
  static override buildMessageForDest(
1511
1598
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
1512
1599
  ): AnyMessage & { extraArgs: SVMExtraArgsV1 } {
@@ -1544,7 +1631,8 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1544
1631
  const tokenReceiver =
1545
1632
  message.extraArgs &&
1546
1633
  'tokenReceiver' in message.extraArgs &&
1547
- message.extraArgs.tokenReceiver != null
1634
+ message.extraArgs.tokenReceiver != null &&
1635
+ typeof message.extraArgs.tokenReceiver === 'string'
1548
1636
  ? message.extraArgs.tokenReceiver
1549
1637
  : message.tokenAmounts?.length
1550
1638
  ? this.getAddress(message.receiver)
package/src/sui/hasher.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { concat, id, keccak256, zeroPadValue } from 'ethers'
2
2
 
3
- import { encodeNumber, encodeRawBytes } from '../aptos/utils.ts'
4
3
  import { CCIPExtraArgsInvalidError, CCIPSuiHasherVersionUnsupportedError } from '../errors/index.ts'
5
4
  import { decodeExtraArgs } from '../extra-args.ts'
6
5
  import { type LeafHasher, LEAF_DOMAIN_SEPARATOR } from '../hasher/common.ts'
7
6
  import { type CCIPMessage, type CCIPMessage_V1_6, CCIPVersion } from '../types.ts'
8
7
  import type { CCIPMessage_V1_6_Sui } from './types.ts'
8
+ import { encodeNumber, encodeRawBytes } from '../shared/bcs-codecs.ts'
9
9
 
10
10
  /**
11
11
  * Creates a leaf hasher for Sui CCIP messages.