@chainlink/ccip-sdk 0.93.0 → 0.95.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 (164) hide show
  1. package/dist/api/index.d.ts +80 -4
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +262 -6
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/types.d.ts +138 -13
  6. package/dist/api/types.d.ts.map +1 -1
  7. package/dist/aptos/index.d.ts +5 -9
  8. package/dist/aptos/index.d.ts.map +1 -1
  9. package/dist/aptos/index.js +26 -25
  10. package/dist/aptos/index.js.map +1 -1
  11. package/dist/aptos/logs.js +3 -3
  12. package/dist/aptos/logs.js.map +1 -1
  13. package/dist/aptos/send.js +1 -1
  14. package/dist/aptos/send.js.map +1 -1
  15. package/dist/chain.d.ts +96 -10
  16. package/dist/chain.d.ts.map +1 -1
  17. package/dist/chain.js +77 -2
  18. package/dist/chain.js.map +1 -1
  19. package/dist/errors/codes.d.ts +7 -3
  20. package/dist/errors/codes.d.ts.map +1 -1
  21. package/dist/errors/codes.js +8 -3
  22. package/dist/errors/codes.js.map +1 -1
  23. package/dist/errors/index.d.ts +7 -7
  24. package/dist/errors/index.d.ts.map +1 -1
  25. package/dist/errors/index.js +7 -7
  26. package/dist/errors/index.js.map +1 -1
  27. package/dist/errors/recovery.d.ts.map +1 -1
  28. package/dist/errors/recovery.js +8 -4
  29. package/dist/errors/recovery.js.map +1 -1
  30. package/dist/errors/specialized.d.ts +53 -18
  31. package/dist/errors/specialized.d.ts.map +1 -1
  32. package/dist/errors/specialized.js +112 -37
  33. package/dist/errors/specialized.js.map +1 -1
  34. package/dist/evm/gas.d.ts +14 -0
  35. package/dist/evm/gas.d.ts.map +1 -0
  36. package/dist/evm/gas.js +97 -0
  37. package/dist/evm/gas.js.map +1 -0
  38. package/dist/evm/index.d.ts +6 -8
  39. package/dist/evm/index.d.ts.map +1 -1
  40. package/dist/evm/index.js +36 -23
  41. package/dist/evm/index.js.map +1 -1
  42. package/dist/evm/offchain.d.ts.map +1 -1
  43. package/dist/evm/offchain.js +8 -8
  44. package/dist/evm/offchain.js.map +1 -1
  45. package/dist/execution.d.ts.map +1 -1
  46. package/dist/execution.js +8 -1
  47. package/dist/execution.js.map +1 -1
  48. package/dist/gas.d.ts +43 -19
  49. package/dist/gas.d.ts.map +1 -1
  50. package/dist/gas.js +48 -68
  51. package/dist/gas.js.map +1 -1
  52. package/dist/index.d.ts +15 -13
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +6 -5
  55. package/dist/index.js.map +1 -1
  56. package/dist/offchain.d.ts +5 -4
  57. package/dist/offchain.d.ts.map +1 -1
  58. package/dist/offchain.js +7 -6
  59. package/dist/offchain.js.map +1 -1
  60. package/dist/requests.d.ts +21 -13
  61. package/dist/requests.d.ts.map +1 -1
  62. package/dist/requests.js +79 -47
  63. package/dist/requests.js.map +1 -1
  64. package/dist/selectors.d.ts +2 -1
  65. package/dist/selectors.d.ts.map +1 -1
  66. package/dist/selectors.js +629 -274
  67. package/dist/selectors.js.map +1 -1
  68. package/dist/solana/exec.d.ts.map +1 -1
  69. package/dist/solana/exec.js +2 -1
  70. package/dist/solana/exec.js.map +1 -1
  71. package/dist/solana/index.d.ts +10 -10
  72. package/dist/solana/index.d.ts.map +1 -1
  73. package/dist/solana/index.js +82 -18
  74. package/dist/solana/index.js.map +1 -1
  75. package/dist/solana/offchain.js +2 -2
  76. package/dist/solana/offchain.js.map +1 -1
  77. package/dist/solana/send.d.ts.map +1 -1
  78. package/dist/solana/send.js +6 -9
  79. package/dist/solana/send.js.map +1 -1
  80. package/dist/solana/utils.d.ts +29 -1
  81. package/dist/solana/utils.d.ts.map +1 -1
  82. package/dist/solana/utils.js +39 -1
  83. package/dist/solana/utils.js.map +1 -1
  84. package/dist/sui/discovery.d.ts +7 -4
  85. package/dist/sui/discovery.d.ts.map +1 -1
  86. package/dist/sui/discovery.js +66 -19
  87. package/dist/sui/discovery.js.map +1 -1
  88. package/dist/sui/events.d.ts +23 -12
  89. package/dist/sui/events.d.ts.map +1 -1
  90. package/dist/sui/events.js +267 -128
  91. package/dist/sui/events.js.map +1 -1
  92. package/dist/sui/index.d.ts +32 -39
  93. package/dist/sui/index.d.ts.map +1 -1
  94. package/dist/sui/index.js +289 -163
  95. package/dist/sui/index.js.map +1 -1
  96. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
  97. package/dist/sui/manuallyExec/encoder.js +1 -0
  98. package/dist/sui/manuallyExec/encoder.js.map +1 -1
  99. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  100. package/dist/sui/manuallyExec/index.js +1 -0
  101. package/dist/sui/manuallyExec/index.js.map +1 -1
  102. package/dist/sui/objects.d.ts +14 -4
  103. package/dist/sui/objects.d.ts.map +1 -1
  104. package/dist/sui/objects.js +63 -69
  105. package/dist/sui/objects.js.map +1 -1
  106. package/dist/sui/types.d.ts +33 -0
  107. package/dist/sui/types.d.ts.map +1 -1
  108. package/dist/sui/types.js.map +1 -1
  109. package/dist/ton/hasher.d.ts.map +1 -1
  110. package/dist/ton/hasher.js +1 -0
  111. package/dist/ton/hasher.js.map +1 -1
  112. package/dist/ton/index.d.ts +4 -4
  113. package/dist/ton/index.d.ts.map +1 -1
  114. package/dist/ton/index.js +8 -8
  115. package/dist/ton/index.js.map +1 -1
  116. package/dist/ton/utils.d.ts +3 -3
  117. package/dist/ton/utils.d.ts.map +1 -1
  118. package/dist/ton/utils.js +6 -5
  119. package/dist/ton/utils.js.map +1 -1
  120. package/dist/types.d.ts +34 -10
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/types.js +19 -5
  123. package/dist/types.js.map +1 -1
  124. package/dist/utils.d.ts +53 -1
  125. package/dist/utils.d.ts.map +1 -1
  126. package/dist/utils.js +109 -12
  127. package/dist/utils.js.map +1 -1
  128. package/package.json +17 -11
  129. package/src/api/index.ts +343 -9
  130. package/src/api/types.ts +165 -13
  131. package/src/aptos/index.ts +32 -32
  132. package/src/aptos/logs.ts +3 -3
  133. package/src/aptos/send.ts +1 -1
  134. package/src/chain.ts +165 -12
  135. package/src/errors/codes.ts +8 -3
  136. package/src/errors/index.ts +7 -4
  137. package/src/errors/recovery.ts +16 -5
  138. package/src/errors/specialized.ts +147 -45
  139. package/src/evm/gas.ts +149 -0
  140. package/src/evm/index.ts +66 -33
  141. package/src/evm/offchain.ts +15 -9
  142. package/src/execution.ts +8 -1
  143. package/src/gas.ts +95 -116
  144. package/src/index.ts +16 -6
  145. package/src/offchain.ts +12 -6
  146. package/src/requests.ts +113 -59
  147. package/src/selectors.ts +636 -276
  148. package/src/solana/exec.ts +3 -1
  149. package/src/solana/index.ts +119 -23
  150. package/src/solana/offchain.ts +2 -2
  151. package/src/solana/send.ts +5 -23
  152. package/src/solana/utils.ts +66 -0
  153. package/src/sui/discovery.ts +92 -31
  154. package/src/sui/events.ts +346 -239
  155. package/src/sui/index.ts +381 -224
  156. package/src/sui/manuallyExec/encoder.ts +2 -0
  157. package/src/sui/manuallyExec/index.ts +2 -0
  158. package/src/sui/objects.ts +77 -99
  159. package/src/sui/types.ts +35 -0
  160. package/src/ton/hasher.ts +2 -0
  161. package/src/ton/index.ts +12 -11
  162. package/src/ton/utils.ts +7 -6
  163. package/src/types.ts +36 -10
  164. package/src/utils.ts +153 -16
package/src/utils.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Buffer } from 'buffer'
2
+
1
3
  import bs58 from 'bs58'
2
4
  import {
3
5
  type BigNumberish,
@@ -10,6 +12,7 @@ import {
10
12
  toBigInt,
11
13
  } from 'ethers'
12
14
  import { memoize } from 'micro-memoize'
15
+ import yaml from 'yaml'
13
16
 
14
17
  import type { Chain, ChainStatic } from './chain.ts'
15
18
  import {
@@ -22,6 +25,7 @@ import {
22
25
  CCIPTypeVersionInvalidError,
23
26
  HttpStatus,
24
27
  } from './errors/index.ts'
28
+ import { getRetryDelay, shouldRetry } from './errors/utils.ts'
25
29
  import SELECTORS from './selectors.ts'
26
30
  import { supportedChains } from './supported-chains.ts'
27
31
  import { type NetworkInfo, type WithLogger, ChainFamily } from './types.ts'
@@ -101,6 +105,9 @@ export async function getSomeBlockNumberBefore(
101
105
  return beforeBlockNumber
102
106
  }
103
107
 
108
+ /**
109
+ * Checks if a chain is a testnet
110
+ */
104
111
  // memoized so we always output the same object for a given chainId
105
112
  const networkInfoFromChainId = memoize((chainId: NetworkInfo['chainId']): NetworkInfo => {
106
113
  const sel = SELECTORS[chainId]
@@ -110,7 +117,7 @@ const networkInfoFromChainId = memoize((chainId: NetworkInfo['chainId']): Networ
110
117
  chainSelector: sel.selector,
111
118
  name: sel.name,
112
119
  family: sel.family,
113
- isTestnet: !sel.name.includes('-mainnet'),
120
+ networkType: sel.network_type,
114
121
  } as NetworkInfo
115
122
  })
116
123
 
@@ -218,13 +225,23 @@ export function bigIntReviver(_key: string, value: unknown): unknown {
218
225
  return value
219
226
  }
220
227
 
228
+ /**
229
+ * Parses JSON text with BigInt support for large integers.
230
+ * Uses yaml parser which handles integers as BigInt when they exceed safe integer range.
231
+ * @param text - JSON string to parse
232
+ * @returns Parsed object with large integers as BigInt
233
+ */
234
+ export function parseJson<T = unknown>(text: string): T {
235
+ return yaml.parse(text, { intAsBigInt: true }) as T
236
+ }
237
+
221
238
  /**
222
239
  * Decode address from a 32-byte hex string
223
240
  **/
224
241
  export function decodeAddress(address: BytesLike, family: ChainFamily = ChainFamily.EVM): string {
225
242
  const chain = supportedChains[family]
226
243
  if (!chain) throw new CCIPChainFamilyUnsupportedError(family)
227
- return chain.getAddress(getAddressBytes(address))
244
+ return chain.getAddress(address)
228
245
  }
229
246
 
230
247
  /**
@@ -253,7 +270,7 @@ export function decodeOnRampAddress(
253
270
  family: ChainFamily = ChainFamily.EVM,
254
271
  ): string {
255
272
  let decoded = decodeAddress(address, family)
256
- if (family === ChainFamily.Aptos) decoded += '::onramp'
273
+ if (family === ChainFamily.Aptos || family === ChainFamily.Sui) decoded += '::onramp'
257
274
  return decoded
258
275
  }
259
276
 
@@ -297,6 +314,8 @@ export function getDataBytes(data: BytesLike | readonly number[]): Uint8Array {
297
314
  if (Array.isArray(data)) return new Uint8Array(data)
298
315
  if (typeof data === 'string' && data.match(/^[0-9a-f]+[a-f][0-9a-f]+$/i)) data = '0x' + data
299
316
  else if (typeof data === 'string' && data.match(/^0X[0-9a-fA-F]+$/)) data = data.toLowerCase()
317
+ if (typeof data === 'string' && data.startsWith('0x') && data.length % 2)
318
+ data = '0x0' + data.slice(2)
300
319
  if (isBytesLike(data)) {
301
320
  return getBytes(data)
302
321
  } else if (isBase64(data)) {
@@ -320,20 +339,33 @@ export function bytesToBuffer(bytes: BytesLike | readonly number[]): Buffer {
320
339
  * @param address - Address in hex or Base58 format.
321
340
  * @returns Address bytes as Uint8Array.
322
341
  */
323
- export function getAddressBytes(address: BytesLike): Uint8Array {
324
- let bytes: Uint8Array
325
- if (isBytesLike(address)) {
326
- bytes = getBytes(address)
342
+ export function getAddressBytes(address: BytesLike | readonly number[]): Uint8Array {
343
+ let bytes
344
+ if (address instanceof Uint8Array) {
345
+ bytes = address
346
+ } else if (Array.isArray(address)) {
347
+ bytes = new Uint8Array(address)
348
+ } else if (
349
+ typeof address === 'string' &&
350
+ address.match(/^((0x[0-9a-f]*)|[0-9a-f]{40,})(::.*)?$/i)
351
+ ) {
352
+ address = address.split('::')[0]! // discard possible Aptos/Sui module suffix
353
+ // supports with or without (long>=20B) 0x-prefix, odd or even length
354
+ bytes = getBytes(
355
+ address.length % 2
356
+ ? '0x0' + (address.toLowerCase().startsWith('0x') ? address.slice(2) : address)
357
+ : !address.toLowerCase().startsWith('0x')
358
+ ? '0x' + address
359
+ : address,
360
+ )
327
361
  } else {
328
- bytes = bs58.decode(address)
329
- }
330
- if (bytes.length > 20) {
331
- if (
332
- bytes.slice(0, bytes.length - 20).every((b) => b === 0) &&
333
- bytes.slice(-20).some((b) => b !== 0)
334
- ) {
335
- bytes = bytes.slice(-20)
362
+ try {
363
+ const bytes_ = bs58.decode(address as string)
364
+ if (bytes_.length % 32 === 0) bytes = bytes_
365
+ } catch (_) {
366
+ // pass
336
367
  }
368
+ if (!bytes) bytes = decodeBase64(address as string)
337
369
  }
338
370
  return bytes
339
371
  }
@@ -354,7 +386,9 @@ export function convertKeysToCamelCase(
354
386
  mapValues?: (value: unknown, key?: string) => unknown,
355
387
  key?: string,
356
388
  ): unknown {
357
- if (Array.isArray(obj)) {
389
+ if (Array.isArray(obj) && obj.every((v) => typeof v === 'number')) {
390
+ return mapValues ? mapValues(obj, key) : obj
391
+ } else if (Array.isArray(obj)) {
358
392
  return obj.map((v) => convertKeysToCamelCase(v, mapValues, key))
359
393
  }
360
394
 
@@ -377,6 +411,109 @@ export function convertKeysToCamelCase(
377
411
  */
378
412
  export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms).unref())
379
413
 
414
+ /**
415
+ * Configuration for the withRetry utility.
416
+ */
417
+ export type WithRetryConfig = {
418
+ /** Maximum number of retry attempts */
419
+ maxRetries: number
420
+ /** Initial delay in milliseconds before the first retry */
421
+ initialDelayMs: number
422
+ /** Multiplier applied to delay after each retry */
423
+ backoffMultiplier: number
424
+ /** Maximum delay in milliseconds between retries */
425
+ maxDelayMs: number
426
+ /** Whether to respect the error's retryAfterMs hint */
427
+ respectRetryAfterHint: boolean
428
+ /** Optional logger for retry attempts */
429
+ logger?: { debug: (...args: unknown[]) => void; warn: (...args: unknown[]) => void }
430
+ }
431
+
432
+ /**
433
+ * Executes an async operation with retry logic and exponential backoff.
434
+ * Only retries on transient errors (as determined by shouldRetry from errors/utils).
435
+ *
436
+ * @param operation - Async function to execute
437
+ * @param config - Retry configuration
438
+ * @returns Promise resolving to the operation result
439
+ * @throws The last error encountered after all retries are exhausted
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * const result = await withRetry(
444
+ * () => apiClient.getMessageById(id),
445
+ * {
446
+ * maxRetries: 3,
447
+ * initialDelayMs: 1000,
448
+ * backoffMultiplier: 2,
449
+ * maxDelayMs: 30000,
450
+ * respectRetryAfterHint: true,
451
+ * }
452
+ * )
453
+ * ```
454
+ */
455
+ export async function withRetry<T>(
456
+ operation: () => Promise<T>,
457
+ config: WithRetryConfig,
458
+ ): Promise<T> {
459
+ const {
460
+ maxRetries,
461
+ initialDelayMs,
462
+ backoffMultiplier,
463
+ maxDelayMs,
464
+ respectRetryAfterHint,
465
+ logger,
466
+ } = config
467
+
468
+ let lastError: CCIPError | undefined
469
+ let delay = initialDelayMs
470
+
471
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
472
+ try {
473
+ return await operation()
474
+ } catch (err) {
475
+ lastError = CCIPError.isCCIPError(err) ? err : CCIPError.from(err, 'UNKNOWN')
476
+
477
+ // Only retry on transient errors
478
+ if (!shouldRetry(lastError)) {
479
+ throw lastError
480
+ }
481
+
482
+ // Don't sleep after the last attempt
483
+ if (attempt >= maxRetries) {
484
+ logger?.warn(`All ${maxRetries} retries exhausted:`, lastError.message)
485
+ break
486
+ }
487
+
488
+ // Calculate delay for next retry
489
+ let nextDelay = delay
490
+
491
+ // Respect error's retryAfterMs hint if configured
492
+ if (respectRetryAfterHint) {
493
+ const hintDelay = getRetryDelay(lastError)
494
+ if (hintDelay !== null) {
495
+ nextDelay = Math.max(delay, hintDelay)
496
+ }
497
+ }
498
+
499
+ // Cap at maxDelayMs
500
+ nextDelay = Math.min(nextDelay, maxDelayMs)
501
+
502
+ logger?.debug(
503
+ `Retry attempt ${attempt + 1}/${maxRetries} after ${nextDelay}ms:`,
504
+ lastError.message,
505
+ )
506
+
507
+ await sleep(nextDelay)
508
+
509
+ // Apply exponential backoff for next iteration
510
+ delay = Math.min(delay * backoffMultiplier, maxDelayMs)
511
+ }
512
+ }
513
+
514
+ throw lastError!
515
+ }
516
+
380
517
  /**
381
518
  * Parses a typeAndVersion string into its components.
382
519
  * @param typeAndVersion - String in format "TypeName vX.Y.Z".