@chainlink/ccip-sdk 0.96.0 → 1.0.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 (247) hide show
  1. package/README.md +12 -9
  2. package/dist/api/index.d.ts +21 -8
  3. package/dist/api/index.d.ts.map +1 -1
  4. package/dist/api/index.js +42 -13
  5. package/dist/api/index.js.map +1 -1
  6. package/dist/api/types.d.ts +0 -2
  7. package/dist/api/types.d.ts.map +1 -1
  8. package/dist/aptos/exec.d.ts +2 -2
  9. package/dist/aptos/exec.d.ts.map +1 -1
  10. package/dist/aptos/exec.js.map +1 -1
  11. package/dist/aptos/hasher.d.ts.map +1 -1
  12. package/dist/aptos/hasher.js +1 -1
  13. package/dist/aptos/hasher.js.map +1 -1
  14. package/dist/aptos/index.d.ts +17 -16
  15. package/dist/aptos/index.d.ts.map +1 -1
  16. package/dist/aptos/index.js +42 -73
  17. package/dist/aptos/index.js.map +1 -1
  18. package/dist/aptos/logs.d.ts +2 -2
  19. package/dist/aptos/logs.d.ts.map +1 -1
  20. package/dist/aptos/types.d.ts +2 -19
  21. package/dist/aptos/types.d.ts.map +1 -1
  22. package/dist/aptos/types.js +0 -11
  23. package/dist/aptos/types.js.map +1 -1
  24. package/dist/chain.d.ts +538 -158
  25. package/dist/chain.d.ts.map +1 -1
  26. package/dist/chain.js +132 -19
  27. package/dist/chain.js.map +1 -1
  28. package/dist/commits.d.ts +4 -6
  29. package/dist/commits.d.ts.map +1 -1
  30. package/dist/commits.js +4 -4
  31. package/dist/commits.js.map +1 -1
  32. package/dist/errors/CCIPError.d.ts +33 -4
  33. package/dist/errors/CCIPError.d.ts.map +1 -1
  34. package/dist/errors/CCIPError.js +33 -4
  35. package/dist/errors/CCIPError.js.map +1 -1
  36. package/dist/errors/codes.d.ts +3 -0
  37. package/dist/errors/codes.d.ts.map +1 -1
  38. package/dist/errors/codes.js +3 -1
  39. package/dist/errors/codes.js.map +1 -1
  40. package/dist/errors/index.d.ts +4 -4
  41. package/dist/errors/index.d.ts.map +1 -1
  42. package/dist/errors/index.js +4 -4
  43. package/dist/errors/index.js.map +1 -1
  44. package/dist/errors/recovery.d.ts.map +1 -1
  45. package/dist/errors/recovery.js +4 -1
  46. package/dist/errors/recovery.js.map +1 -1
  47. package/dist/errors/specialized.d.ts +1695 -120
  48. package/dist/errors/specialized.d.ts.map +1 -1
  49. package/dist/errors/specialized.js +1715 -123
  50. package/dist/errors/specialized.js.map +1 -1
  51. package/dist/errors/utils.d.ts.map +1 -1
  52. package/dist/errors/utils.js +0 -1
  53. package/dist/errors/utils.js.map +1 -1
  54. package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
  55. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
  56. package/dist/evm/abi/OffRamp_2_0.js +744 -0
  57. package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
  58. package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
  59. package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
  60. package/dist/evm/abi/OnRamp_2_0.js +992 -0
  61. package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
  62. package/dist/evm/const.d.ts +12 -2
  63. package/dist/evm/const.d.ts.map +1 -1
  64. package/dist/evm/const.js +8 -2
  65. package/dist/evm/const.js.map +1 -1
  66. package/dist/evm/errors.d.ts.map +1 -1
  67. package/dist/evm/errors.js +7 -2
  68. package/dist/evm/errors.js.map +1 -1
  69. package/dist/evm/extra-args.d.ts.map +1 -1
  70. package/dist/evm/extra-args.js +5 -24
  71. package/dist/evm/extra-args.js.map +1 -1
  72. package/dist/evm/hasher.d.ts.map +1 -1
  73. package/dist/evm/hasher.js +23 -13
  74. package/dist/evm/hasher.js.map +1 -1
  75. package/dist/evm/index.d.ts +73 -16
  76. package/dist/evm/index.d.ts.map +1 -1
  77. package/dist/evm/index.js +241 -146
  78. package/dist/evm/index.js.map +1 -1
  79. package/dist/evm/logs.d.ts +1 -1
  80. package/dist/evm/logs.js +1 -1
  81. package/dist/evm/messages.d.ts +59 -5
  82. package/dist/evm/messages.d.ts.map +1 -1
  83. package/dist/evm/messages.js +210 -0
  84. package/dist/evm/messages.js.map +1 -1
  85. package/dist/evm/offchain.d.ts +1 -14
  86. package/dist/evm/offchain.d.ts.map +1 -1
  87. package/dist/evm/offchain.js +1 -133
  88. package/dist/evm/offchain.js.map +1 -1
  89. package/dist/evm/types.d.ts +7 -2
  90. package/dist/evm/types.d.ts.map +1 -1
  91. package/dist/evm/types.js +22 -1
  92. package/dist/evm/types.js.map +1 -1
  93. package/dist/execution.d.ts +62 -22
  94. package/dist/execution.d.ts.map +1 -1
  95. package/dist/execution.js +98 -61
  96. package/dist/execution.js.map +1 -1
  97. package/dist/extra-args.d.ts +13 -3
  98. package/dist/extra-args.d.ts.map +1 -1
  99. package/dist/extra-args.js +13 -3
  100. package/dist/extra-args.js.map +1 -1
  101. package/dist/gas.d.ts +25 -2
  102. package/dist/gas.d.ts.map +1 -1
  103. package/dist/gas.js +30 -4
  104. package/dist/gas.js.map +1 -1
  105. package/dist/index.d.ts +3 -2
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +2 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/offchain.d.ts +23 -6
  110. package/dist/offchain.d.ts.map +1 -1
  111. package/dist/offchain.js +92 -17
  112. package/dist/offchain.js.map +1 -1
  113. package/dist/requests.d.ts +85 -14
  114. package/dist/requests.d.ts.map +1 -1
  115. package/dist/requests.js +99 -17
  116. package/dist/requests.js.map +1 -1
  117. package/dist/selectors.d.ts.map +1 -1
  118. package/dist/selectors.js +12 -0
  119. package/dist/selectors.js.map +1 -1
  120. package/dist/shared/bcs-codecs.d.ts +61 -0
  121. package/dist/shared/bcs-codecs.d.ts.map +1 -0
  122. package/dist/shared/bcs-codecs.js +102 -0
  123. package/dist/shared/bcs-codecs.js.map +1 -0
  124. package/dist/shared/constants.d.ts +3 -0
  125. package/dist/shared/constants.d.ts.map +1 -0
  126. package/dist/shared/constants.js +3 -0
  127. package/dist/shared/constants.js.map +1 -0
  128. package/dist/solana/exec.d.ts +2 -2
  129. package/dist/solana/exec.d.ts.map +1 -1
  130. package/dist/solana/exec.js.map +1 -1
  131. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts +1 -1
  132. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js +1 -1
  133. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts +1 -1
  134. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js +1 -1
  135. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts +1 -1
  136. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js +1 -1
  137. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts +16 -1
  138. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts.map +1 -1
  139. package/dist/solana/idl/1.6.0/CCIP_COMMON.js +16 -1
  140. package/dist/solana/idl/1.6.0/CCIP_COMMON.js.map +1 -1
  141. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts +1 -1
  142. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js +1 -1
  143. package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts +1 -1
  144. package/dist/solana/idl/1.6.0/CCIP_ROUTER.js +1 -1
  145. package/dist/solana/index.d.ts +85 -24
  146. package/dist/solana/index.d.ts.map +1 -1
  147. package/dist/solana/index.js +69 -37
  148. package/dist/solana/index.js.map +1 -1
  149. package/dist/solana/offchain.d.ts +1 -13
  150. package/dist/solana/offchain.d.ts.map +1 -1
  151. package/dist/solana/offchain.js +1 -66
  152. package/dist/solana/offchain.js.map +1 -1
  153. package/dist/solana/utils.d.ts +4 -4
  154. package/dist/solana/utils.d.ts.map +1 -1
  155. package/dist/solana/utils.js +1 -1
  156. package/dist/solana/utils.js.map +1 -1
  157. package/dist/sui/hasher.d.ts.map +1 -1
  158. package/dist/sui/hasher.js +1 -1
  159. package/dist/sui/hasher.js.map +1 -1
  160. package/dist/sui/index.d.ts +18 -18
  161. package/dist/sui/index.d.ts.map +1 -1
  162. package/dist/sui/index.js +38 -39
  163. package/dist/sui/index.js.map +1 -1
  164. package/dist/sui/manuallyExec/encoder.d.ts +2 -2
  165. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
  166. package/dist/sui/manuallyExec/encoder.js.map +1 -1
  167. package/dist/sui/manuallyExec/index.d.ts +2 -2
  168. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  169. package/dist/ton/exec.d.ts +3 -3
  170. package/dist/ton/exec.d.ts.map +1 -1
  171. package/dist/ton/exec.js +1 -1
  172. package/dist/ton/exec.js.map +1 -1
  173. package/dist/ton/index.d.ts +14 -22
  174. package/dist/ton/index.d.ts.map +1 -1
  175. package/dist/ton/index.js +26 -35
  176. package/dist/ton/index.js.map +1 -1
  177. package/dist/ton/types.d.ts +3 -5
  178. package/dist/ton/types.d.ts.map +1 -1
  179. package/dist/ton/types.js.map +1 -1
  180. package/dist/types.d.ts +55 -20
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js +6 -1
  183. package/dist/types.js.map +1 -1
  184. package/dist/utils.d.ts +65 -2
  185. package/dist/utils.d.ts.map +1 -1
  186. package/dist/utils.js +74 -2
  187. package/dist/utils.js.map +1 -1
  188. package/package.json +14 -10
  189. package/src/api/index.ts +53 -17
  190. package/src/api/types.ts +0 -2
  191. package/src/aptos/exec.ts +2 -2
  192. package/src/aptos/hasher.ts +1 -1
  193. package/src/aptos/index.ts +55 -100
  194. package/src/aptos/logs.ts +2 -2
  195. package/src/aptos/types.ts +2 -15
  196. package/src/chain.ts +594 -171
  197. package/src/commits.ts +9 -9
  198. package/src/errors/CCIPError.ts +33 -4
  199. package/src/errors/codes.ts +3 -1
  200. package/src/errors/index.ts +4 -0
  201. package/src/errors/recovery.ts +7 -1
  202. package/src/errors/specialized.ts +1726 -130
  203. package/src/errors/utils.ts +0 -1
  204. package/src/evm/abi/OffRamp_2_0.ts +743 -0
  205. package/src/evm/abi/OnRamp_2_0.ts +991 -0
  206. package/src/evm/const.ts +10 -3
  207. package/src/evm/errors.ts +6 -2
  208. package/src/evm/extra-args.ts +4 -21
  209. package/src/evm/hasher.ts +30 -18
  210. package/src/evm/index.ts +314 -176
  211. package/src/evm/logs.ts +1 -1
  212. package/src/evm/messages.ts +323 -11
  213. package/src/evm/offchain.ts +2 -191
  214. package/src/evm/types.ts +20 -2
  215. package/src/execution.ts +125 -86
  216. package/src/extra-args.ts +13 -3
  217. package/src/gas.ts +29 -3
  218. package/src/index.ts +10 -3
  219. package/src/offchain.ts +125 -28
  220. package/src/requests.ts +114 -19
  221. package/src/selectors.ts +12 -0
  222. package/src/shared/bcs-codecs.ts +132 -0
  223. package/src/shared/constants.ts +2 -0
  224. package/src/solana/exec.ts +4 -4
  225. package/src/solana/idl/1.6.0/BASE_TOKEN_POOL.ts +2 -2
  226. package/src/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.ts +2 -2
  227. package/src/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts +2 -2
  228. package/src/solana/idl/1.6.0/CCIP_COMMON.ts +32 -2
  229. package/src/solana/idl/1.6.0/CCIP_OFFRAMP.ts +2 -2
  230. package/src/solana/idl/1.6.0/CCIP_ROUTER.ts +2 -2
  231. package/src/solana/index.ts +110 -85
  232. package/src/solana/offchain.ts +3 -100
  233. package/src/solana/utils.ts +8 -5
  234. package/src/sui/hasher.ts +1 -1
  235. package/src/sui/index.ts +55 -59
  236. package/src/sui/manuallyExec/encoder.ts +2 -2
  237. package/src/sui/manuallyExec/index.ts +2 -2
  238. package/src/ton/exec.ts +4 -7
  239. package/src/ton/index.ts +45 -53
  240. package/src/ton/types.ts +4 -7
  241. package/src/types.ts +81 -37
  242. package/src/utils.ts +73 -2
  243. package/dist/aptos/utils.d.ts +0 -12
  244. package/dist/aptos/utils.d.ts.map +0 -1
  245. package/dist/aptos/utils.js +0 -15
  246. package/dist/aptos/utils.js.map +0 -1
  247. package/src/aptos/utils.ts +0 -24
package/src/chain.ts CHANGED
@@ -3,7 +3,7 @@ import type { PickDeep, SetOptional } from 'type-fest'
3
3
 
4
4
  import { type LaneLatencyResponse, CCIPAPIClient } from './api/index.ts'
5
5
  import type { UnsignedAptosTx } from './aptos/types.ts'
6
- import { getCommitReport } from './commits.ts'
6
+ import { getOnchainCommitReport } from './commits.ts'
7
7
  import {
8
8
  CCIPApiClientNotAvailableError,
9
9
  CCIPChainFamilyMismatchError,
@@ -11,8 +11,8 @@ import {
11
11
  CCIPTokenPoolChainConfigNotFoundError,
12
12
  CCIPTransactionNotFinalizedError,
13
13
  } from './errors/index.ts'
14
- import { DEFAULT_GAS_LIMIT } from './evm/const.ts'
15
14
  import type { UnsignedEVMTx } from './evm/types.ts'
15
+ import { calculateManualExecProof } from './execution.ts'
16
16
  import type {
17
17
  EVMExtraArgsV1,
18
18
  EVMExtraArgsV2,
@@ -22,22 +22,25 @@ import type {
22
22
  SuiExtraArgsV1,
23
23
  } from './extra-args.ts'
24
24
  import type { LeafHasher } from './hasher/common.ts'
25
+ import { getOffchainTokenData } from './offchain.ts'
25
26
  import { getMessagesInTx } from './requests.ts'
27
+ import { DEFAULT_GAS_LIMIT } from './shared/constants.ts'
26
28
  import type { UnsignedSolanaTx } from './solana/types.ts'
27
29
  import type { UnsignedTONTx } from './ton/types.ts'
28
30
  import {
29
31
  type AnyMessage,
30
- type CCIPCommit,
31
32
  type CCIPExecution,
32
33
  type CCIPMessage,
33
34
  type CCIPRequest,
35
+ type CCIPVerifications,
36
+ type CCIPVersion,
34
37
  type ChainFamily,
38
+ type ChainLog,
35
39
  type ChainTransaction,
36
40
  type CommitReport,
41
+ type ExecutionInput,
37
42
  type ExecutionReceipt,
38
- type ExecutionReport,
39
43
  type Lane,
40
- type Log_,
41
44
  type Logger,
42
45
  type MessageInput,
43
46
  type NetworkInfo,
@@ -76,7 +79,7 @@ function hasV3ExtraArgs(extraArgs: Partial<ExtraArgs> | undefined): boolean {
76
79
  *
77
80
  * @example Custom API endpoint
78
81
  * ```typescript
79
- * const api = new CCIPAPIClient('https://staging-api.example.com', { logger })
82
+ * const api = CCIPAPIClient.fromUrl('https://staging-api.example.com', { logger })
80
83
  * const chain = await EVMChain.fromUrl(rpcUrl, { apiClient: api, logger })
81
84
  * ```
82
85
  *
@@ -298,13 +301,23 @@ export type SendMessageOpts = {
298
301
  }
299
302
 
300
303
  /**
301
- * Common options for {@link Chain.generateUnsignedExecuteReport} and {@link Chain.executeReport} methods.
304
+ * Common options for {@link Chain.generateUnsignedExecute} and {@link Chain.execute} methods.
302
305
  */
303
- export type ExecuteReportOpts = {
304
- /** address of the OffRamp contract */
305
- offRamp: string
306
- /** execution report */
307
- execReport: ExecutionReport
306
+ export type ExecuteOpts = (
307
+ | {
308
+ /** address of the OffRamp contract */
309
+ offRamp: string
310
+ /** input payload to execute message; contains proofs for v1 and verifications for v2 */
311
+ input: ExecutionInput
312
+ }
313
+ | {
314
+ /**
315
+ * messageId of message to execute; requires `apiClient`.
316
+ * @remarks Currently throws CCIPNotImplementedError - API endpoint pending.
317
+ */
318
+ messageId: string
319
+ }
320
+ ) & {
308
321
  /** gasLimit or computeUnits limit override for the ccipReceive call */
309
322
  gasLimit?: number
310
323
  /** For EVM, overrides gasLimit on tokenPool call */
@@ -353,7 +366,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
353
366
  this.apiClient = apiClient // Use provided instance
354
367
  this.apiRetryConfig = { ...DEFAULT_API_RETRY_CONFIG, ...apiRetryConfig }
355
368
  } else {
356
- this.apiClient = new CCIPAPIClient(undefined, { logger }) // Default
369
+ this.apiClient = CCIPAPIClient.fromUrl(undefined, { logger }) // Default
357
370
  this.apiRetryConfig = { ...DEFAULT_API_RETRY_CONFIG, ...apiRetryConfig }
358
371
  }
359
372
  }
@@ -367,24 +380,63 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
367
380
  }
368
381
 
369
382
  /**
370
- * Fetch the timestamp of a given block
371
- * @param block - positive block number, negative finality depth or 'finalized' tag
372
- * @returns timestamp of the block, in seconds
383
+ * Fetch the timestamp of a given block.
384
+ *
385
+ * @param block - Positive block number, negative finality depth, or 'finalized' tag
386
+ * @returns Promise resolving to timestamp of the block, in seconds
387
+ *
373
388
  * @throws {@link CCIPBlockNotFoundError} if block does not exist
389
+ *
390
+ * @example Get finalized block timestamp
391
+ * ```typescript
392
+ * const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
393
+ * const timestamp = await chain.getBlockTimestamp('finalized')
394
+ * console.log(`Finalized at: ${new Date(timestamp * 1000).toISOString()}`)
395
+ * ```
374
396
  */
375
397
  abstract getBlockTimestamp(block: number | 'finalized'): Promise<number>
376
398
  /**
377
- * Fetch a transaction by its hash
378
- * @param hash - transaction hash
379
- * @returns generic transaction details
380
- * @throws {@link CCIPTransactionNotFoundError} if transaction not found
399
+ * Fetch a transaction by its hash.
400
+ *
401
+ * @param hash - Transaction hash
402
+ * @returns Promise resolving to generic transaction details
403
+ *
404
+ * @throws {@link CCIPTransactionNotFoundError} if transaction does not exist (transient)
405
+ *
406
+ * @example Fetch transaction details
407
+ * ```typescript
408
+ * const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
409
+ * try {
410
+ * const tx = await chain.getTransaction('0xabc123...')
411
+ * console.log(`Block: ${tx.blockNumber}, Timestamp: ${tx.timestamp}`)
412
+ * } catch (err) {
413
+ * if (err instanceof CCIPTransactionNotFoundError && err.isTransient) {
414
+ * // Transaction may be pending
415
+ * }
416
+ * }
417
+ * ```
381
418
  */
382
419
  abstract getTransaction(hash: string): Promise<ChainTransaction>
383
420
  /**
384
421
  * Confirm a log tx is finalized or wait for it to be finalized.
422
+ *
385
423
  * @param opts - Options containing the request, finality level, and optional cancel promise
386
424
  * @returns true when the transaction is finalized
425
+ *
387
426
  * @throws {@link CCIPTransactionNotFinalizedError} if the transaction is not included (e.g., due to a reorg)
427
+ *
428
+ * @example Wait for message finality
429
+ * ```typescript
430
+ * const request = await source.getMessagesInTx(txHash)
431
+ * try {
432
+ * await source.waitFinalized({ request: request[0] })
433
+ * console.log('Transaction finalized')
434
+ * } catch (err) {
435
+ * if (err instanceof CCIPTransactionNotFinalizedError) {
436
+ * console.log('Transaction not yet finalized')
437
+ * }
438
+ * }
439
+ * ```
388
440
  */
389
441
  async waitFinalized({
390
442
  request: { log, tx },
@@ -450,13 +502,25 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
450
502
  * @throws {@link CCIPLogsWatchRequiresStartError} if watch mode is used without startBlock or startTime
451
503
  * @throws {@link CCIPLogsAddressRequiredError} if address is required but not provided (chain-specific)
452
504
  */
453
- abstract getLogs(opts: LogFilter): AsyncIterableIterator<Log_>
505
+ abstract getLogs(opts: LogFilter): AsyncIterableIterator<ChainLog>
454
506
 
455
507
  /**
456
- * Fetch all CCIP requests in a transaction
508
+ * Fetch all CCIP requests in a transaction.
509
+ *
457
510
  * @param tx - ChainTransaction or txHash to fetch requests from
458
- * @returns CCIP messages in the transaction (at least one)
459
- * @throws {@link CCIPMessageNotFoundInTxError} if no CCIP messages found in transaction
511
+ * @returns Promise resolving to CCIP messages in the transaction (at least one)
512
+ *
513
+ * @throws {@link CCIPTransactionNotFoundError} if transaction does not exist
514
+ * @throws {@link CCIPMessageNotFoundInTxError} if no CCIPSendRequested events in tx
515
+ *
516
+ * @example Get messages from transaction
517
+ * ```typescript
518
+ * const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
519
+ * const requests = await chain.getMessagesInTx('0xabc123...')
520
+ * for (const req of requests) {
521
+ * console.log(`Message ID: ${req.message.messageId}`)
522
+ * }
523
+ * ```
460
524
  */
461
525
  async getMessagesInTx(tx: string | ChainTransaction): Promise<CCIPRequest[]> {
462
526
  const txHash = typeof tx === 'string' ? tx : tx.hash
@@ -511,8 +575,9 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
511
575
  * @returns CCIPRequest with `metadata` populated from API
512
576
  * @throws {@link CCIPApiClientNotAvailableError} if API disabled
513
577
  * @throws {@link CCIPMessageIdNotFoundError} if message not found
578
+ * @throws {@link CCIPOnRampRequiredError} if onRamp is required but not provided
514
579
  * @throws {@link CCIPHttpError} if API request fails
515
- **/
580
+ */
516
581
  async getMessageById(
517
582
  messageId: string,
518
583
  _opts?: { page?: number; onRamp?: string },
@@ -527,96 +592,213 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
527
592
 
528
593
  /**
529
594
  * Fetches all CCIP messages contained in a given commit batch.
530
- * @param request - CCIPRequest to fetch batch for.
531
- * @param commit - CommitReport range (min, max).
532
- * @param opts - Optional parameters (e.g., `page` for pagination width).
533
- * @returns Array of messages in the batch.
595
+ * To be implemented for chains supporting CCIPVersion &lt;= v1.6.0
596
+ *
597
+ * @param request - CCIPRequest to fetch batch for
598
+ * @param range - batch range \{ minSeqnr, maxSeqNr \}, e.g. from [[CommitReport]]
599
+ * @param opts - Optional parameters (e.g., `page` for pagination width)
600
+ * @returns Array of messages in the batch
601
+ *
534
602
  * @throws {@link CCIPMessageBatchIncompleteError} if not all messages in range could be fetched
603
+ *
604
+ * @example Get all messages in a batch
605
+ * ```typescript
606
+ * const verifications = await dest.getVerifications({ offRamp, request })
607
+ * const messages = await source.getMessagesInBatch(request, verifications.report)
608
+ * console.log(`Found ${messages.length} messages in batch`)
609
+ * ```
535
610
  */
536
- abstract getMessagesInBatch<
611
+ getMessagesInBatch?<
537
612
  R extends PickDeep<
538
613
  CCIPRequest,
539
614
  'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
540
615
  >,
541
616
  >(
542
617
  request: R,
543
- commit: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
618
+ range: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
544
619
  opts?: { page?: number },
545
620
  ): Promise<R['message'][]>
621
+
546
622
  /**
547
- * Fetch typeAndVersion for a given CCIP contract address
623
+ * Fetch input data needed for executing messages
624
+ * Should be called on the *source* instance
625
+ * @param opts - getExecutionInput options containing request and verifications
626
+ * @returns `input` payload to be passed to [[execute]]
627
+ * @see {@link execute} - method to execute a message
628
+ */
629
+ async getExecutionInput({
630
+ request,
631
+ verifications,
632
+ ...opts
633
+ }: {
634
+ request: CCIPRequest
635
+ verifications: CCIPVerifications
636
+ } & Pick<LogFilter, 'page'>): Promise<ExecutionInput> {
637
+ if ('verifications' in verifications) {
638
+ // >=v2 verifications is enough for execution
639
+ return {
640
+ encodedMessage: (request.message as CCIPMessage<typeof CCIPVersion.V2_0>).encodedMessage,
641
+ ...verifications,
642
+ }
643
+ }
644
+ // other messages in same batch are available from `source` side;
645
+ // not needed for chain families supporting only >=v2
646
+ const messagesInBatch = await this.getMessagesInBatch!(request, verifications.report, opts)
647
+ const execReportProof = calculateManualExecProof(
648
+ messagesInBatch,
649
+ request.lane,
650
+ request.message.messageId,
651
+ verifications.report.merkleRoot,
652
+ this,
653
+ )
654
+ const offchainTokenData = await this.getOffchainTokenData(request)
655
+ return {
656
+ ...execReportProof,
657
+ message: request.message,
658
+ offchainTokenData,
659
+ } as ExecutionInput
660
+ }
661
+ /**
662
+ * Fetch typeAndVersion for a given CCIP contract address.
663
+ *
548
664
  * @param address - CCIP contract address
549
- * @returns type - parsed type of the contract, e.g. `OnRamp`
550
- * @returns version - parsed version of the contract, e.g. `1.6.0`
551
- * @returns typeAndVersion - original (unparsed) typeAndVersion() string
552
- * @returns suffix - suffix of the version, if any (e.g. `-dev`)
553
- * @throws {@link CCIPTypeVersionInvalidError} if contract doesn't have valid typeAndVersion
665
+ * @returns Promise resolving to tuple:
666
+ * - `type` - Parsed type of the contract, e.g. `OnRamp`
667
+ * - `version` - Parsed version of the contract, e.g. `1.6.0`
668
+ * - `typeAndVersion` - Original (unparsed) typeAndVersion() string
669
+ * - `suffix` - Suffix of the version, if any (e.g. `-dev`)
670
+ *
671
+ * @throws {@link CCIPTypeVersionInvalidError} if typeAndVersion string cannot be parsed
672
+ *
673
+ * @example Check contract version
674
+ * ```typescript
675
+ * const [type, version] = await chain.typeAndVersion(contractAddress)
676
+ * console.log(`Contract: ${type} v${version}`)
677
+ * if (version < '1.6.0') {
678
+ * console.log('Legacy contract detected')
679
+ * }
680
+ * ```
554
681
  */
555
682
  abstract typeAndVersion(
556
683
  address: string,
557
684
  ): Promise<[type: string, version: string, typeAndVersion: string, suffix?: string]>
558
685
 
559
686
  /**
560
- * Fetch the Router address set in OnRamp config
561
- * Used to discover OffRamp connected to OnRamp
687
+ * Fetch the Router address set in OnRamp config.
688
+ * Used to discover OffRamp connected to OnRamp.
689
+ *
562
690
  * @param onRamp - OnRamp contract address
563
- * @param destChainSelector - destination chain selector
564
- * @returns Router address
691
+ * @param destChainSelector - Destination chain selector
692
+ * @returns Promise resolving to Router address
693
+ *
694
+ * @throws {@link CCIPContractTypeInvalidError} if address is not an OnRamp
695
+ *
696
+ * @example Get router from onRamp
697
+ * ```typescript
698
+ * const router = await chain.getRouterForOnRamp(onRampAddress, destSelector)
699
+ * console.log(`Router: ${router}`)
700
+ * ```
565
701
  */
566
702
  abstract getRouterForOnRamp(onRamp: string, destChainSelector: bigint): Promise<string>
567
703
  /**
568
- * Fetch the Router address set in OffRamp config
704
+ * Fetch the Router address set in OffRamp config.
705
+ *
569
706
  * @param offRamp - OffRamp contract address
570
- * @param sourceChainSelector - source chain selector
571
- * @returns Router address
707
+ * @param sourceChainSelector - Source chain selector
708
+ * @returns Promise resolving to Router address
709
+ *
710
+ * @throws {@link CCIPContractTypeInvalidError} if address is not an OffRamp
711
+ *
712
+ * @example Get router from offRamp
713
+ * ```typescript
714
+ * const router = await chain.getRouterForOffRamp(offRampAddress, sourceSelector)
715
+ * console.log(`Router: ${router}`)
716
+ * ```
572
717
  */
573
718
  abstract getRouterForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string>
574
719
  /**
575
- * Get the native token address for a Router
576
- * @param router - router contract address
577
- * @returns native token address (usually wrapped)
720
+ * Get the native token address for a Router.
721
+ *
722
+ * @param router - Router contract address
723
+ * @returns Promise resolving to native token address (usually wrapped)
724
+ *
725
+ * @example Get wrapped native token
726
+ * ```typescript
727
+ * const weth = await chain.getNativeTokenForRouter(routerAddress)
728
+ * console.log(`Wrapped native: ${weth}`)
729
+ * ```
578
730
  */
579
731
  abstract getNativeTokenForRouter(router: string): Promise<string>
580
732
  /**
581
- * Fetch the OffRamps allowlisted in a Router
582
- * Used to discover OffRamp connected to an OnRamp
733
+ * Fetch the OffRamps allowlisted in a Router.
734
+ * Used to discover OffRamp connected to an OnRamp.
735
+ *
583
736
  * @param router - Router contract address
584
- * @param sourceChainSelector - source chain selector
585
- * @returns array of OffRamp addresses
737
+ * @param sourceChainSelector - Source chain selector
738
+ * @returns Promise resolving to array of OffRamp addresses
739
+ *
740
+ * @example Get offRamps for a source chain
741
+ * ```typescript
742
+ * const offRamps = await dest.getOffRampsForRouter(routerAddress, sourceSelector)
743
+ * console.log(`Found ${offRamps.length} offRamp(s)`)
744
+ * ```
586
745
  */
587
746
  abstract getOffRampsForRouter(router: string, sourceChainSelector: bigint): Promise<string[]>
588
747
  /**
589
- * Fetch the OnRamp registered in a Router for a destination chain
748
+ * Fetch the OnRamp registered in a Router for a destination chain.
749
+ *
590
750
  * @param router - Router contract address
591
- * @param destChainSelector - destination chain selector
592
- * @returns OnRamp addresses
751
+ * @param destChainSelector - Destination chain selector
752
+ * @returns Promise resolving to OnRamp address
753
+ *
754
+ * @throws {@link CCIPLaneNotFoundError} if no lane exists to destination
755
+ *
756
+ * @example Get onRamp for destination
757
+ * ```typescript
758
+ * const onRamp = await source.getOnRampForRouter(routerAddress, destSelector)
759
+ * console.log(`OnRamp: ${onRamp}`)
760
+ * ```
593
761
  */
594
762
  abstract getOnRampForRouter(router: string, destChainSelector: bigint): Promise<string>
595
763
  /**
596
- * Fetch the OnRamp address set in OffRamp config
597
- * Used to discover OffRamp connected to an OnRamp
764
+ * Fetch the OnRamps addresses set in OffRamp config.
765
+ * Used to discover OffRamp connected to an OnRamp.
766
+ *
598
767
  * @param offRamp - OffRamp contract address
599
- * @param sourceChainSelector - source chain selector
600
- * @returns OnRamp address
601
- */
602
- abstract getOnRampForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string>
603
- /**
604
- * Fetch the CommitStore set in OffRamp config (CCIP v1.5 and earlier).
605
- * For CCIP v1.6 and later, it should return the offRamp address.
606
- * @param offRamp - OffRamp contract address.
607
- * @returns CommitStore address.
768
+ * @param sourceChainSelector - Source chain selector
769
+ * @returns Promise resolving to OnRamps addresses
770
+ *
771
+ * @example Get onRamp from offRamp config
772
+ * ```typescript
773
+ * const [onRamp] = await dest.getOnRampsForOffRamp(offRampAddress, sourceSelector)
774
+ * console.log(`OnRamp: ${onRamp}`)
775
+ * ```
608
776
  */
609
- abstract getCommitStoreForOffRamp(offRamp: string): Promise<string>
777
+ abstract getOnRampsForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string[]>
610
778
  /**
611
- * Fetch the TokenPool's token/mint
779
+ * Fetch the TokenPool's token/mint.
780
+ *
612
781
  * @param tokenPool - TokenPool address
613
- * @returns Token or mint address
782
+ * @returns Promise resolving to token or mint address
783
+ *
784
+ * @example Get token for pool
785
+ * ```typescript
786
+ * const token = await chain.getTokenForTokenPool(tokenPoolAddress)
787
+ * console.log(`Token: ${token}`)
788
+ * ```
614
789
  */
615
790
  abstract getTokenForTokenPool(tokenPool: string): Promise<string>
616
791
  /**
617
- * Fetch token metadata
792
+ * Fetch token metadata.
793
+ *
618
794
  * @param token - Token address
619
- * @returns Token symbol and decimals, and optionally name
795
+ * @returns Promise resolving to token symbol, decimals, and optionally name
796
+ *
797
+ * @example Get token info
798
+ * ```typescript
799
+ * const info = await chain.getTokenInfo(tokenAddress)
800
+ * console.log(`${info.symbol}: ${info.decimals} decimals`)
801
+ * ```
620
802
  */
621
803
  abstract getTokenInfo(token: string): Promise<TokenInfo>
622
804
  /**
@@ -628,14 +810,14 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
628
810
  *
629
811
  * @example Query native token balance
630
812
  * ```typescript
631
- * const balance = await chain.getBalance({ address: '0x123...' })
813
+ * const balance = await chain.getBalance({ holder: '0x123...' })
632
814
  * console.log(`Native balance: ${balance}`) // balance in wei
633
815
  * ```
634
816
  *
635
817
  * @example Query ERC20 token balance
636
818
  * ```typescript
637
819
  * const balance = await chain.getBalance({
638
- * address: '0x123...',
820
+ * holder: '0x123...',
639
821
  * token: '0xLINK...'
640
822
  * })
641
823
  * console.log(`LINK balance: ${balance}`) // balance in smallest units
@@ -643,22 +825,52 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
643
825
  */
644
826
  abstract getBalance(opts: GetBalanceOpts): Promise<bigint>
645
827
  /**
646
- * Fetch TokenAdminRegistry configured in a given OnRamp, Router, etc
647
- * Needed to map a source token to its dest counterparts
648
- * @param address - Some contract for which we can fetch a TokenAdminRegistry (OnRamp, Router, etc.)
649
- * @returns TokenAdminRegistry address
828
+ * Fetch TokenAdminRegistry configured in a given OnRamp, Router, etc.
829
+ * Needed to map a source token to its dest counterparts.
830
+ *
831
+ * @param address - Contract address (OnRamp, Router, etc.)
832
+ * @returns Promise resolving to TokenAdminRegistry address
833
+ *
834
+ * @example Get token registry
835
+ * ```typescript
836
+ * const registry = await chain.getTokenAdminRegistryFor(onRampAddress)
837
+ * console.log(`Registry: ${registry}`)
838
+ * ```
650
839
  */
651
840
  abstract getTokenAdminRegistryFor(address: string): Promise<string>
652
841
  /**
653
- * Fetch the current fee for a given intended message
842
+ * Fetch the current fee for a given intended message.
843
+ *
654
844
  * @param opts - {@link SendMessageOpts} without approveMax
655
845
  * @returns Fee amount in the feeToken's smallest units
846
+ *
847
+ * @example Calculate message fee
848
+ * ```typescript
849
+ * const fee = await chain.getFee({
850
+ * router: routerAddress,
851
+ * destChainSelector: destSelector,
852
+ * message: { receiver: '0x...', data: '0x' },
853
+ * })
854
+ * console.log(`Fee: ${fee} wei`)
855
+ * ```
656
856
  */
657
857
  abstract getFee(opts: Omit<SendMessageOpts, 'approveMax'>): Promise<bigint>
658
858
  /**
659
- * Generate unsigned txs for ccipSend'ing a message
859
+ * Generate unsigned txs for ccipSend'ing a message.
860
+ *
660
861
  * @param opts - {@link SendMessageOpts} with sender address
661
- * @returns chain-family specific unsigned txs
862
+ * @returns Promise resolving to chain-family specific unsigned txs
863
+ *
864
+ * @example Generate unsigned transaction
865
+ * ```typescript
866
+ * const unsignedTx = await chain.generateUnsignedSendMessage({
867
+ * router: routerAddress,
868
+ * destChainSelector: destSelector,
869
+ * message: { receiver: '0x...', data: '0x1337' },
870
+ * sender: walletAddress,
871
+ * })
872
+ * // Sign and send with external wallet
873
+ * ```
662
874
  */
663
875
  abstract generateUnsignedSendMessage(
664
876
  opts: SendMessageOpts & {
@@ -668,11 +880,14 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
668
880
  ): Promise<UnsignedTx[F]>
669
881
  /**
670
882
  * Send a CCIP message through a router using provided wallet.
883
+ *
671
884
  * @param opts - {@link SendMessageOpts} with chain-specific wallet for signing
672
- * @returns CCIP request
673
- * @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
885
+ * @returns Promise resolving to CCIP request with message details
674
886
  *
675
- * @example
887
+ * @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer
888
+ * @throws {@link CCIPLaneNotFoundError} if no lane exists to destination
889
+ *
890
+ * @example Send cross-chain message
676
891
  * ```typescript
677
892
  * const request = await chain.sendMessage({
678
893
  * router: '0x...',
@@ -695,75 +910,105 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
695
910
  },
696
911
  ): Promise<CCIPRequest>
697
912
  /**
698
- * Fetch supported offchain token data for a request from this network
699
- * @param request - CCIP request, with tx, logs and message
700
- * @returns array with one offchain token data for each token transfer in request
913
+ * Fetch supported offchain token data for a request from this network.
914
+ * It logs but doesn't throw in case it can't fetch attestation, as the transfers may not be
915
+ * from the expected attestation providers. It returns default offchainData=undefined for those.
916
+ *
917
+ * @param request - CCIP request, with tx.hash and message
918
+ * @returns Promise resolving to array with one offchain token data for each token transfer
919
+ *
920
+ * @example Get offchain token data for USDC transfer
921
+ * ```typescript
922
+ * const offchainData = await source.getOffchainTokenData(request)
923
+ * // Use in execution report
924
+ * ```
701
925
  */
702
- abstract getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]>
926
+ async getOffchainTokenData(
927
+ request: PickDeep<CCIPRequest, 'tx.hash' | `message`>,
928
+ ): Promise<OffchainTokenData[]> {
929
+ return getOffchainTokenData(request, this)
930
+ }
931
+
703
932
  /**
704
- * Generate unsigned tx to manuallyExecute a message
705
- * @param opts - {@link ExecuteReportOpts} with payer address which will send the exec tx
706
- * @returns chain-family specific unsigned txs
933
+ * Generate unsigned tx to manuallyExecute a message.
934
+ *
935
+ * @param opts - {@link ExecuteOpts} with payer address which will send the exec tx
936
+ * @returns Promise resolving to chain-family specific unsigned txs
937
+ *
938
+ * @example Generate unsigned execution tx
939
+ * ```typescript
940
+ * const unsignedTx = await dest.generateUnsignedExecute({
941
+ * offRamp: offRampAddress,
942
+ * input,
943
+ * payer: walletAddress,
944
+ * })
945
+ * // Sign and send with external wallet
946
+ * ```
707
947
  */
708
- abstract generateUnsignedExecuteReport(
709
- opts: ExecuteReportOpts & {
948
+ abstract generateUnsignedExecute(
949
+ opts: ExecuteOpts & {
710
950
  /** address which will be used to send the report tx */
711
951
  payer: string
712
952
  },
713
953
  ): Promise<UnsignedTx[F]>
714
954
  /**
715
- * Execute messages in report in an offRamp
716
- * @param opts - {@link ExecuteReportOpts} with chain-specific wallet to sign and send tx
717
- * @returns transaction of the execution
955
+ * Execute messages in report in an offRamp.
718
956
  *
719
- * @example
957
+ * @param opts - {@link ExecuteOpts} with chain-specific wallet to sign and send tx
958
+ * @returns Promise resolving to transaction of the execution
959
+ *
960
+ * @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer
961
+ * @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
962
+ * @throws {@link CCIPMerkleRootMismatchError} if merkle proof is invalid
963
+ *
964
+ * @example Manual execution of pending message
720
965
  * ```typescript
721
- * const execReportProof = calculateManualExecProof(
722
- * messagesInBatch: await source.getMessagesInBatch(request, commit.report),
723
- * request.lane,
724
- * request.message.messageId,
725
- * commit.report.merkleRoot,
726
- * dest,
727
- * )
728
- * const receipt = await dest.executeReport({
729
- * offRamp,
730
- * execReport: {
731
- * ...execReportProof,
732
- * message: request.message,
733
- * offchainTokenData: await source.getOffchainTokenData(request),
734
- * },
735
- * wallet,
736
- * })
737
- * console.log(`Message ID: ${request.message.messageId}`)
966
+ * const input = await source.getExecutionInput({ request, verifications })
967
+ * const receipt = await dest.execute({ offRamp, input, wallet })
968
+ * console.log(`Executed: ${receipt.log.transactionHash}`)
738
969
  * ```
739
970
  * @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
740
971
  * @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
741
972
  */
742
- abstract executeReport(
743
- opts: ExecuteReportOpts & {
973
+ abstract execute(
974
+ opts: ExecuteOpts & {
744
975
  // Signer instance (chain-dependent)
745
976
  wallet: unknown
746
977
  },
747
978
  ): Promise<CCIPExecution>
748
979
 
749
980
  /**
750
- * Look for a CommitReport at dest for given CCIP request
751
- * May be specialized by some subclasses
752
- * @param opts - getCommitReport options
753
- * @returns CCIPCommit info
754
- * @throws {@link CCIPCommitNotFoundError} if no commit found for the request
981
+ * Look for a CommitReport at dest for given CCIP request.
982
+ * May be specialized by some subclasses.
983
+ *
984
+ * @param opts - getVerifications options
985
+ * @returns CCIPVerifications
986
+ *
987
+ * @throws {@link CCIPCommitNotFoundError} if no commit found for the request (transient)
988
+ *
989
+ * @example Get commit for a request
990
+ * ```typescript
991
+ * const verifications = await dest.getVerifications({
992
+ * offRamp: offRampAddress,
993
+ * request,
994
+ * })
995
+ * console.log(`Committed at block: ${verifications.log.blockNumber}`)
996
+ * ```
755
997
  */
756
- async getCommitReport({
757
- commitStore,
998
+ async getVerifications({
999
+ offRamp,
758
1000
  request,
759
1001
  ...hints
760
1002
  }: {
761
- /** address of commitStore (OffRamp in \>=v1.6) */
762
- commitStore: string
1003
+ /** address of offRamp or commitStore contract */
1004
+ offRamp: string
763
1005
  /** CCIPRequest subset object */
764
- request: PickDeep<CCIPRequest, 'lane' | 'message.sequenceNumber' | 'tx.timestamp'>
765
- } & Pick<LogFilter, 'page' | 'watch' | 'startBlock'>): Promise<CCIPCommit> {
766
- return getCommitReport(this, commitStore, request, hints)
1006
+ request: PickDeep<
1007
+ CCIPRequest,
1008
+ 'lane' | `message.${'sequenceNumber' | 'messageId'}` | 'tx.timestamp'
1009
+ >
1010
+ } & Pick<LogFilter, 'page' | 'watch' | 'startBlock'>): Promise<CCIPVerifications> {
1011
+ return getOnchainCommitReport(this, offRamp, request, hints)
767
1012
  }
768
1013
 
769
1014
  /**
@@ -806,15 +1051,29 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
806
1051
  }
807
1052
 
808
1053
  /**
809
- * Default/generic implementation of getExecutionReceipts
1054
+ * Default/generic implementation of getExecutionReceipts.
1055
+ * Yields execution receipts for a given offRamp.
1056
+ *
810
1057
  * @param opts - getExecutionReceipts options
811
1058
  * @returns Async generator of CCIPExecution receipts
1059
+ *
1060
+ * @example Watch for execution receipts
1061
+ * ```typescript
1062
+ * for await (const exec of dest.getExecutionReceipts({
1063
+ * offRamp: offRampAddress,
1064
+ * messageId: request.message.messageId,
1065
+ * startBlock: commit.log.blockNumber,
1066
+ * })) {
1067
+ * console.log(`State: ${exec.receipt.state}`)
1068
+ * if (exec.receipt.state === ExecutionState.Success) break
1069
+ * }
1070
+ * ```
812
1071
  */
813
1072
  async *getExecutionReceipts({
814
1073
  offRamp,
815
1074
  messageId,
816
1075
  sourceChainSelector,
817
- commit,
1076
+ verifications,
818
1077
  ...hints
819
1078
  }: {
820
1079
  /** address of OffRamp contract */
@@ -824,12 +1083,12 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
824
1083
  /** filter: yield only executions for this source chain */
825
1084
  sourceChainSelector?: bigint
826
1085
  /** optional commit associated with the request, can be used for optimizations in some families */
827
- commit?: CCIPCommit
1086
+ verifications?: CCIPVerifications
828
1087
  } & Pick<
829
1088
  LogFilter,
830
1089
  'page' | 'watch' | 'startBlock' | 'startTime'
831
1090
  >): AsyncIterableIterator<CCIPExecution> {
832
- hints.startBlock ??= commit?.log.blockNumber
1091
+ if (verifications && 'log' in verifications) hints.startBlock ??= verifications.log.blockNumber
833
1092
  const onlyLast = !hints.startTime && !hints.startBlock // backwards
834
1093
  for await (const log of this.getLogs({
835
1094
  address: offRamp,
@@ -855,10 +1114,18 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
855
1114
 
856
1115
  /**
857
1116
  * Fetch first execution receipt inside a transaction.
1117
+ *
858
1118
  * @internal
859
- * @param tx - transaction hash or transaction object
1119
+ * @param tx - Transaction hash or transaction object
860
1120
  * @returns CCIP execution object
1121
+ *
861
1122
  * @throws {@link CCIPExecTxRevertedError} if no execution receipt found in transaction
1123
+ *
1124
+ * @example Get receipt from execution tx
1125
+ * ```typescript
1126
+ * const exec = await dest.getExecutionReceiptInTx(execTxHash)
1127
+ * console.log(`State: ${exec.receipt.state}`)
1128
+ * ```
862
1129
  */
863
1130
  async getExecutionReceiptInTx(tx: string | ChainTransaction): Promise<CCIPExecution> {
864
1131
  if (typeof tx === 'string') tx = await this.getTransaction(tx)
@@ -874,9 +1141,16 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
874
1141
 
875
1142
  /**
876
1143
  * List tokens supported by given TokenAdminRegistry contract.
1144
+ *
877
1145
  * @param address - Usually TokenAdminRegistry, but chain may support receiving Router, OnRamp, etc.
878
- * @param opts - Optional parameters (e.g., `page` for pagination range).
879
- * @returns Array of supported token addresses.
1146
+ * @param opts - Optional parameters (e.g., `page` for pagination range)
1147
+ * @returns Promise resolving to array of supported token addresses
1148
+ *
1149
+ * @example Get all supported tokens
1150
+ * ```typescript
1151
+ * const tokens = await chain.getSupportedTokens(registryAddress)
1152
+ * console.log(`${tokens.length} tokens supported`)
1153
+ * ```
880
1154
  */
881
1155
  abstract getSupportedTokens(address: string, opts?: { page?: number }): Promise<string[]>
882
1156
 
@@ -907,21 +1181,27 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
907
1181
  * Fetch configuration of a token pool.
908
1182
  *
909
1183
  * @remarks
910
- * Returns the core configuration of a token pool including which token it manages
911
- * and which router it's registered with.
1184
+ * Return type varies by chain:
1185
+ * - **EVM**: `typeAndVersion` is always present (required)
1186
+ * - **Solana**: Includes extra `tokenPoolProgram` field
1187
+ * - **Aptos**: Standard fields only
1188
+ * - **Sui/TON**: Throws {@link CCIPNotImplementedError}
912
1189
  *
913
- * @example Query pool configuration
1190
+ * @example Type-safe access to chain-specific fields
914
1191
  * ```typescript
915
- * const config = await chain.getTokenPoolConfig(poolAddress)
916
- * console.log(`Manages token: ${config.token}`)
917
- * console.log(`Router: ${config.router}`)
918
- * if (config.typeAndVersion) {
919
- * console.log(`Version: ${config.typeAndVersion}`)
1192
+ * // Use instanceof to narrow the chain type
1193
+ * if (chain instanceof SolanaChain) {
1194
+ * const config = await chain.getTokenPoolConfig(poolAddress)
1195
+ * console.log(config.tokenPoolProgram) // TypeScript knows this exists!
1196
+ * } else if (chain instanceof EVMChain) {
1197
+ * const config = await chain.getTokenPoolConfig(poolAddress)
1198
+ * console.log(config.typeAndVersion) // TypeScript knows this is required!
920
1199
  * }
921
1200
  * ```
922
1201
  *
923
1202
  * @param tokenPool - Token pool contract address.
924
1203
  * @returns {@link TokenPoolConfig} containing token, router, and version info.
1204
+ * @throws {@link CCIPNotImplementedError} on Sui or TON chains
925
1205
  */
926
1206
  abstract getTokenPoolConfig(tokenPool: string): Promise<TokenPoolConfig>
927
1207
 
@@ -1003,12 +1283,27 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
1003
1283
 
1004
1284
  /**
1005
1285
  * Fetch list and info of supported feeTokens.
1006
- * @param router - Router address on this chain.
1007
- * @returns Mapping of token addresses to respective TokenInfo objects.
1286
+ *
1287
+ * @param router - Router address on this chain
1288
+ * @returns Promise resolving to mapping of token addresses to TokenInfo objects
1289
+ *
1290
+ * @example Get available fee tokens
1291
+ * ```typescript
1292
+ * const feeTokens = await chain.getFeeTokens(routerAddress)
1293
+ * for (const [addr, info] of Object.entries(feeTokens)) {
1294
+ * console.log(`${info.symbol}: ${addr}`)
1295
+ * }
1296
+ * ```
1008
1297
  */
1009
1298
  abstract getFeeTokens(router: string): Promise<Record<string, TokenInfo>>
1010
1299
 
1011
- /** {@inheritDoc ChainStatic.buildMessageForDest} */
1300
+ /**
1301
+ * Returns a copy of a message, populating missing fields like `extraArgs` with defaults.
1302
+ * It's expected to return a message suitable at least for basic token transfers.
1303
+ *
1304
+ * @param message - AnyMessage (from source), containing at least `receiver`
1305
+ * @returns A message suitable for `sendMessage` to this destination chain family
1306
+ */
1012
1307
  static buildMessageForDest(
1013
1308
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
1014
1309
  ): AnyMessage {
@@ -1065,30 +1360,72 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
1065
1360
  }): Promise<number>
1066
1361
  }
1067
1362
 
1068
- /** Static methods and properties available on Chain class constructors. */
1363
+ /**
1364
+ * Static methods and properties available on Chain class constructors.
1365
+ *
1366
+ * @example Using static methods
1367
+ * ```typescript
1368
+ * // Create chain from URL
1369
+ * const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
1370
+ *
1371
+ * // Decode message from log
1372
+ * const message = EVMChain.decodeMessage(log)
1373
+ *
1374
+ * // Validate address format
1375
+ * const normalized = EVMChain.getAddress('0xABC...')
1376
+ * ```
1377
+ */
1069
1378
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
1070
1379
  export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
1071
1380
  readonly family: F
1072
1381
  readonly decimals: number
1073
1382
  /**
1074
- * async constructor: builds a Chain from a rpc endpoint url
1075
- * @param url - rpc endpoint url
1076
- * @param ctx - optional context with logger and API client configuration
1383
+ * Async constructor: builds a Chain from an RPC endpoint URL.
1384
+ *
1385
+ * @param url - RPC endpoint URL
1386
+ * @param ctx - Optional context with logger and API client configuration
1387
+ * @returns Promise resolving to Chain instance
1388
+ *
1389
+ * @throws {@link CCIPChainNotFoundError} if chain cannot be identified
1390
+ *
1391
+ * @example Create chain from RPC
1392
+ * ```typescript
1393
+ * const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
1394
+ * console.log(`Connected to: ${chain.network.name}`)
1395
+ * ```
1077
1396
  */
1078
1397
  fromUrl(url: string, ctx?: ChainContext): Promise<Chain<F>>
1079
1398
  /**
1080
- * Try to decode a CCIP message *from* a log/event *originated* from this *source* chain,
1081
- * but which may *target* other dest chain families
1082
- * iow: the parsing is specific to this chain family, but content may be intended to alien chains
1083
- * e.g: EVM-born (abi.encoded) bytearray may output message.computeUnits for Solana
1399
+ * Try to decode a CCIP message from a log/event originated from this source chain.
1400
+ * The parsing is specific to this chain family, but content may target other chains.
1401
+ *
1084
1402
  * @param log - Chain generic log
1085
- * @returns decoded CCIP message with merged extraArgs
1403
+ * @returns Decoded CCIP message with merged extraArgs, or undefined if not a CCIP message
1404
+ *
1405
+ * @example Decode message from log
1406
+ * ```typescript
1407
+ * const message = EVMChain.decodeMessage(log)
1408
+ * if (message) {
1409
+ * console.log(`Message ID: ${message.messageId}`)
1410
+ * }
1411
+ * ```
1086
1412
  */
1087
- decodeMessage(log: Pick<Log_, 'data'>): CCIPMessage | undefined
1413
+ decodeMessage(log: Pick<ChainLog, 'data'>): CCIPMessage | undefined
1088
1414
  /**
1089
- * Try to decode an extraArgs array serialized for this chain family
1090
- * @param extraArgs - extra args bytes (Uint8Array, HexString or base64)
1091
- * @returns object containing decoded extraArgs and their tags
1415
+ * Try to decode an extraArgs array serialized for this chain family.
1416
+ *
1417
+ * @param extraArgs - Extra args bytes (Uint8Array, HexString or base64)
1418
+ * @returns Object containing decoded extraArgs and their tag, or undefined
1419
+ *
1420
+ * @throws {@link CCIPExtraArgsParseError} if bytes cannot be decoded
1421
+ *
1422
+ * @example Decode extra args
1423
+ * ```typescript
1424
+ * const decoded = EVMChain.decodeExtraArgs(message.extraArgs)
1425
+ * if (decoded?._tag === 'EVMExtraArgsV2') {
1426
+ * console.log(`Gas limit: ${decoded.gasLimit}`)
1427
+ * }
1428
+ * ```
1092
1429
  */
1093
1430
  decodeExtraArgs(
1094
1431
  extraArgs: BytesLike,
@@ -1099,54 +1436,140 @@ export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
1099
1436
  | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
1100
1437
  | (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
1101
1438
  | undefined
1439
+ /**
1440
+ * Encode extraArgs for this chain family.
1441
+ *
1442
+ * @param extraArgs - Extra args object to encode
1443
+ * @returns Encoded hex string
1444
+ *
1445
+ * @example Encode extra args
1446
+ * ```typescript
1447
+ * const encoded = EVMChain.encodeExtraArgs({
1448
+ * gasLimit: 200000n,
1449
+ * strict: false,
1450
+ * })
1451
+ * ```
1452
+ */
1102
1453
  encodeExtraArgs(extraArgs: ExtraArgs): string
1103
1454
  /**
1104
- * Decode a commit (CommitReportAccepted) event
1455
+ * Decode a commit (CommitReportAccepted) event.
1456
+ *
1105
1457
  * @param log - Chain generic log
1106
- * @param lane - if passed, filter or validate reports by lane
1107
- * @returns Array of commit reports contained in the log
1458
+ * @param lane - If passed, filter or validate reports by lane
1459
+ * @returns Array of commit reports contained in the log, or undefined
1460
+ *
1461
+ * @example Decode commit from log
1462
+ * ```typescript
1463
+ * const commits = EVMChain.decodeCommits(log, lane)
1464
+ * if (commits) {
1465
+ * console.log(`Found ${commits.length} commit(s)`)
1466
+ * }
1467
+ * ```
1108
1468
  */
1109
- decodeCommits(log: Pick<Log_, 'data'>, lane?: Lane): CommitReport[] | undefined
1469
+ decodeCommits(log: Pick<ChainLog, 'data'>, lane?: Lane): CommitReport[] | undefined
1110
1470
  /**
1111
- * Decode a receipt (ExecutionStateChanged) event
1471
+ * Decode a receipt (ExecutionStateChanged) event.
1472
+ *
1112
1473
  * @param log - Chain generic log
1113
1474
  * @returns ExecutionReceipt or undefined if not a recognized receipt
1475
+ *
1476
+ * @example Decode execution receipt
1477
+ * ```typescript
1478
+ * const receipt = EVMChain.decodeReceipt(log)
1479
+ * if (receipt) {
1480
+ * console.log(`State: ${receipt.state}, Message: ${receipt.messageId}`)
1481
+ * }
1482
+ * ```
1114
1483
  */
1115
- decodeReceipt(log: Pick<Log_, 'data'>): ExecutionReceipt | undefined
1484
+ decodeReceipt(log: Pick<ChainLog, 'data'>): ExecutionReceipt | undefined
1116
1485
  /**
1117
- * Receive a bytes array and try to decode and normalize it as an address of this chain family
1486
+ * Receive a bytes array and try to decode and normalize it as an address of this chain family.
1487
+ *
1118
1488
  * @param bytes - Bytes array (Uint8Array, HexString or Base64)
1119
1489
  * @returns Address in this chain family's format
1490
+ *
1491
+ * @throws {@link CCIPAddressInvalidEvmError} if invalid EVM address
1492
+ * @throws {@link CCIPDataFormatUnsupportedError} if invalid Aptos/Sui address
1493
+ *
1494
+ * @example Normalize address
1495
+ * ```typescript
1496
+ * const normalized = EVMChain.getAddress('0xABC123...')
1497
+ * console.log(normalized) // checksummed address
1498
+ * ```
1120
1499
  */
1121
1500
  getAddress(bytes: BytesLike): string
1122
1501
  /**
1123
- * Validates a transaction hash format for this chain family
1502
+ * Validates a transaction hash format for this chain family.
1503
+ *
1504
+ * @param v - Value to validate
1505
+ * @returns True if value is a valid transaction hash format
1506
+ *
1507
+ * @example Validate transaction hash
1508
+ * ```typescript
1509
+ * if (EVMChain.isTxHash(userInput)) {
1510
+ * const tx = await chain.getTransaction(userInput)
1511
+ * }
1512
+ * ```
1124
1513
  */
1125
1514
  isTxHash(v: unknown): v is string
1126
1515
  /**
1127
1516
  * Format an address for human-friendly display.
1128
1517
  * Defaults to getAddress if not overridden.
1518
+ *
1129
1519
  * @param address - Address string in any recognized format
1130
1520
  * @returns Human-friendly address string for display
1521
+ *
1522
+ * @example Format address for display
1523
+ * ```typescript
1524
+ * const display = EVMChain.formatAddress?.(rawAddress) ?? rawAddress
1525
+ * console.log(display)
1526
+ * ```
1131
1527
  */
1132
1528
  formatAddress?(address: string): string
1133
1529
  /**
1134
1530
  * Format a transaction hash for human-friendly display.
1531
+ *
1135
1532
  * @param hash - Transaction hash string
1136
1533
  * @returns Human-friendly hash string for display
1534
+ *
1535
+ * @example Format tx hash for display
1536
+ * ```typescript
1537
+ * const display = EVMChain.formatTxHash?.(rawHash) ?? rawHash
1538
+ * console.log(display)
1539
+ * ```
1137
1540
  */
1138
1541
  formatTxHash?(hash: string): string
1139
1542
  /**
1140
- * Create a leaf hasher for this dest chain and lane
1141
- * @param lane - source, dest and onramp lane info
1142
- * @param ctx - context object containing logger
1143
- * @returns LeafHasher is a function that takes a message and returns a hash of it
1543
+ * Create a leaf hasher for this dest chain and lane.
1544
+ *
1545
+ * @param lane - Source, dest and onramp lane info
1546
+ * @param ctx - Context object containing logger
1547
+ * @returns LeafHasher function that takes a message and returns its hash
1548
+ *
1549
+ * @throws {@link CCIPHasherVersionUnsupportedError} if hasher version unsupported
1550
+ *
1551
+ * @example Create leaf hasher
1552
+ * ```typescript
1553
+ * const hasher = EVMChain.getDestLeafHasher(lane, { logger })
1554
+ * const leafHash = hasher(message)
1555
+ * ```
1144
1556
  */
1145
1557
  getDestLeafHasher(lane: Lane, ctx?: WithLogger): LeafHasher
1146
1558
  /**
1147
- * Try to parse an error or bytearray generated by this chain family
1559
+ * Try to parse an error or bytearray generated by this chain family.
1560
+ *
1148
1561
  * @param data - Caught object, string or bytearray
1149
- * @returns Ordered record with messages/properties, or undefined if not a recognized error
1562
+ * @returns Ordered record with messages/properties, or undefined/null if not recognized
1563
+ *
1564
+ * @example Parse contract error
1565
+ * ```typescript
1566
+ * try {
1567
+ * await chain.sendMessage(opts)
1568
+ * } catch (err) {
1569
+ * const parsed = EVMChain.parse?.(err)
1570
+ * if (parsed) console.log('Contract error:', parsed)
1571
+ * }
1572
+ * ```
1150
1573
  */
1151
1574
  parse?(data: unknown): Record<string, unknown> | undefined | null
1152
1575
  /**