@chainlink/ccip-sdk 1.2.1 → 1.3.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 (100) hide show
  1. package/dist/api/index.d.ts +1 -1
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +10 -20
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/aptos/index.d.ts +2 -2
  6. package/dist/aptos/index.d.ts.map +1 -1
  7. package/dist/aptos/index.js +1 -1
  8. package/dist/aptos/index.js.map +1 -1
  9. package/dist/chain.d.ts +75 -2
  10. package/dist/chain.d.ts.map +1 -1
  11. package/dist/chain.js +19 -0
  12. package/dist/chain.js.map +1 -1
  13. package/dist/errors/codes.d.ts +1 -0
  14. package/dist/errors/codes.d.ts.map +1 -1
  15. package/dist/errors/codes.js +1 -0
  16. package/dist/errors/codes.js.map +1 -1
  17. package/dist/errors/index.d.ts +1 -1
  18. package/dist/errors/index.d.ts.map +1 -1
  19. package/dist/errors/index.js +1 -1
  20. package/dist/errors/index.js.map +1 -1
  21. package/dist/errors/recovery.d.ts.map +1 -1
  22. package/dist/errors/recovery.js +1 -0
  23. package/dist/errors/recovery.js.map +1 -1
  24. package/dist/errors/specialized.d.ts +8 -0
  25. package/dist/errors/specialized.d.ts.map +1 -1
  26. package/dist/errors/specialized.js +10 -0
  27. package/dist/errors/specialized.js.map +1 -1
  28. package/dist/evm/abi/CCTPVerifier_2_0.d.ts +1118 -0
  29. package/dist/evm/abi/CCTPVerifier_2_0.d.ts.map +1 -0
  30. package/dist/evm/abi/CCTPVerifier_2_0.js +1147 -0
  31. package/dist/evm/abi/CCTPVerifier_2_0.js.map +1 -0
  32. package/dist/evm/abi/USDCTokenPoolProxy_2_0.d.ts +825 -0
  33. package/dist/evm/abi/USDCTokenPoolProxy_2_0.d.ts.map +1 -0
  34. package/dist/evm/abi/USDCTokenPoolProxy_2_0.js +873 -0
  35. package/dist/evm/abi/USDCTokenPoolProxy_2_0.js.map +1 -0
  36. package/dist/evm/abi/VersionedVerifierResolver_2_0.d.ts +350 -0
  37. package/dist/evm/abi/VersionedVerifierResolver_2_0.d.ts.map +1 -0
  38. package/dist/evm/abi/VersionedVerifierResolver_2_0.js +370 -0
  39. package/dist/evm/abi/VersionedVerifierResolver_2_0.js.map +1 -0
  40. package/dist/evm/const.d.ts +3 -0
  41. package/dist/evm/const.d.ts.map +1 -1
  42. package/dist/evm/const.js +6 -0
  43. package/dist/evm/const.js.map +1 -1
  44. package/dist/evm/index.d.ts +24 -3
  45. package/dist/evm/index.d.ts.map +1 -1
  46. package/dist/evm/index.js +193 -7
  47. package/dist/evm/index.js.map +1 -1
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/offchain.d.ts +27 -0
  53. package/dist/offchain.d.ts.map +1 -1
  54. package/dist/offchain.js +44 -2
  55. package/dist/offchain.js.map +1 -1
  56. package/dist/requests.d.ts +1 -25
  57. package/dist/requests.d.ts.map +1 -1
  58. package/dist/requests.js +0 -57
  59. package/dist/requests.js.map +1 -1
  60. package/dist/solana/index.d.ts +2 -2
  61. package/dist/solana/index.d.ts.map +1 -1
  62. package/dist/solana/index.js +1 -1
  63. package/dist/solana/index.js.map +1 -1
  64. package/dist/sui/index.d.ts +2 -2
  65. package/dist/sui/index.d.ts.map +1 -1
  66. package/dist/sui/index.js +1 -1
  67. package/dist/sui/index.js.map +1 -1
  68. package/dist/ton/index.d.ts +2 -2
  69. package/dist/ton/index.d.ts.map +1 -1
  70. package/dist/ton/index.js +28 -49
  71. package/dist/ton/index.js.map +1 -1
  72. package/dist/ton/send.d.ts +13 -1
  73. package/dist/ton/send.d.ts.map +1 -1
  74. package/dist/ton/send.js +16 -16
  75. package/dist/ton/send.js.map +1 -1
  76. package/dist/utils.d.ts +16 -0
  77. package/dist/utils.d.ts.map +1 -1
  78. package/dist/utils.js +31 -1
  79. package/dist/utils.js.map +1 -1
  80. package/package.json +4 -4
  81. package/src/api/index.ts +9 -23
  82. package/src/aptos/index.ts +5 -1
  83. package/src/chain.ts +85 -2
  84. package/src/errors/codes.ts +1 -0
  85. package/src/errors/index.ts +1 -0
  86. package/src/errors/recovery.ts +2 -0
  87. package/src/errors/specialized.ts +15 -0
  88. package/src/evm/abi/CCTPVerifier_2_0.ts +1146 -0
  89. package/src/evm/abi/USDCTokenPoolProxy_2_0.ts +872 -0
  90. package/src/evm/abi/VersionedVerifierResolver_2_0.ts +369 -0
  91. package/src/evm/const.ts +6 -0
  92. package/src/evm/index.ts +262 -8
  93. package/src/index.ts +6 -2
  94. package/src/offchain.ts +53 -1
  95. package/src/requests.ts +1 -59
  96. package/src/solana/index.ts +5 -1
  97. package/src/sui/index.ts +2 -1
  98. package/src/ton/index.ts +41 -56
  99. package/src/ton/send.ts +20 -21
  100. package/src/utils.ts +42 -0
package/src/ton/index.ts CHANGED
@@ -1,26 +1,38 @@
1
1
  import { Buffer } from 'buffer'
2
2
 
3
- import { type Transaction, Address, Cell, beginCell, toNano } from '@ton/core'
3
+ import {
4
+ type Transaction,
5
+ Address,
6
+ BitReader,
7
+ BitString,
8
+ Cell,
9
+ Slice,
10
+ beginCell,
11
+ toNano,
12
+ } from '@ton/core'
4
13
  import { TonClient } from '@ton/ton'
5
14
  import { type AxiosAdapter, getAdapter } from 'axios'
6
15
  import {
7
16
  type BytesLike,
8
- concat,
9
- dataLength,
10
17
  dataSlice,
11
18
  hexlify,
12
19
  isBytesLike,
13
20
  isHexString,
14
21
  toBeArray,
15
22
  toBeHex,
16
- toBigInt,
17
23
  } from 'ethers'
18
24
  import { type Memoized, memoize } from 'micro-memoize'
19
25
  import type { PickDeep } from 'type-fest'
20
26
 
21
27
  import { streamTransactionsForAddress } from './logs.ts'
22
- import { generateUnsignedCcipSend, getFee as getFeeImpl } from './send.ts'
23
- import { type ChainContext, type GetBalanceOpts, type LogFilter, Chain } from '../chain.ts'
28
+ import { encodeExtraArgsCell, generateUnsignedCcipSend, getFee as getFeeImpl } from './send.ts'
29
+ import {
30
+ type ChainContext,
31
+ type GetBalanceOpts,
32
+ type LogFilter,
33
+ type TokenTransferFeeOpts,
34
+ Chain,
35
+ } from '../chain.ts'
24
36
  import {
25
37
  CCIPArgumentInvalidError,
26
38
  CCIPExecutionReportChainMismatchError,
@@ -56,7 +68,6 @@ import {
56
68
  bytesToBuffer,
57
69
  createRateLimitedFetch,
58
70
  decodeAddress,
59
- getDataBytes,
60
71
  networkInfo,
61
72
  parseTypeAndVersion,
62
73
  sleep,
@@ -76,16 +87,6 @@ function isTvmError(error: unknown): error is Error & { exitCode: number } {
76
87
  return error instanceof Error && 'exitCode' in error && typeof error.exitCode === 'number'
77
88
  }
78
89
 
79
- function bitsToBytes(bits: string): Uint8Array {
80
- return Uint8Array.from(bits.match(/.{1,8}/g)!.map((byte) => parseInt(byte.padEnd(8, '0'), 2)))
81
- }
82
-
83
- function bytesToBits(bytes: Uint8Array): string {
84
- return Array.from(bytes)
85
- .map((B) => B.toString(2).padStart(8, '0'))
86
- .join('')
87
- }
88
-
89
90
  /**
90
91
  * TON chain implementation supporting TON networks.
91
92
  *
@@ -668,24 +669,14 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
668
669
 
669
670
  // Load extraArgs from ref 2
670
671
  const extraArgsCell = bodySlice.loadRef()
671
- const extraArgsSlice = extraArgsCell.beginParse()
672
-
673
- // Read tag (32 bits)
674
- const extraArgsTag = extraArgsSlice.loadUint(32)
675
- if (extraArgsTag !== Number(EVMExtraArgsV2Tag)) return undefined
676
-
677
- // Read gasLimit (maybe uint256): 1 bit flag + 256 bits if present
678
- const hasGasLimit = extraArgsSlice.loadBit()
679
- const gasLimit = hasGasLimit ? extraArgsSlice.loadUintBig(256) : 0n
680
-
681
- // Read allowOutOfOrderExecution (1 bit)
682
- const allowOutOfOrderExecution = extraArgsSlice.loadBit()
683
672
 
684
673
  // Build extraArgs as raw hex matching reference format
685
- const extraArgs = '0x' + extraArgsCell.toBoc().toString('hex')
674
+ const extraArgs = '0x' + extraArgsCell.bits.toString().toLowerCase().replace('_', '0')
675
+ const parsed = this.decodeExtraArgs(extraArgs)
676
+ if (!parsed) return
677
+ const { _tag, ...extraArgsObj } = parsed
686
678
 
687
679
  // Load tokenAmounts from ref 3
688
- const _tokenAmountsCell = bodySlice.loadRef()
689
680
  const tokenAmounts: CCIPMessage_V1_6_EVM['tokenAmounts'] = [] // TODO: FIXME: parse when implemented
690
681
 
691
682
  // Load feeToken (inline address in body)
@@ -704,8 +695,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
704
695
  feeTokenAmount,
705
696
  feeValueJuels,
706
697
  extraArgs,
707
- gasLimit,
708
- allowOutOfOrderExecution,
698
+ ...extraArgsObj,
709
699
  }
710
700
  } catch {
711
701
  return undefined
@@ -723,17 +713,8 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
723
713
  * @returns Hex string of BOC-encoded extra args (0x-prefixed)
724
714
  */
725
715
  static encodeExtraArgs(args: ExtraArgs): string {
726
- if ('gasLimit' in args && 'allowOutOfOrderExecution' in args) {
727
- return concat([
728
- EVMExtraArgsV2Tag,
729
- bitsToBytes(
730
- '1' +
731
- bytesToBits(toBeArray(args.gasLimit, 32)) +
732
- (args.allowOutOfOrderExecution ? '1' : '0'),
733
- ),
734
- ])
735
- }
736
- return '0x'
716
+ const cell = encodeExtraArgsCell(args)
717
+ return '0x' + cell.bits.toString().toLowerCase().replace('_', '0')
737
718
  }
738
719
 
739
720
  /**
@@ -751,19 +732,23 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
751
732
  static decodeExtraArgs(
752
733
  extraArgs: BytesLike,
753
734
  ): (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' }) | undefined {
754
- if (dataSlice(extraArgs, 0, 4) !== EVMExtraArgsV2Tag || dataLength(extraArgs) < 5) return
755
- const data = getDataBytes(extraArgs).subarray(4)
756
- let bits = bytesToBits(data)
757
- let gasLimit = 0n
758
- if (bits[0] === '1') {
759
- if (bits.length < 1 + 32 * 8) return
760
- gasLimit = toBigInt(bitsToBytes(bits.substring(1, 1 + 32 * 8)))
761
- bits = bits.substring(1 + 32 * 8)
762
- } else {
763
- bits = bits.substring(1)
735
+ let bytes
736
+ try {
737
+ bytes = bytesToBuffer(extraArgs)
738
+
739
+ // If the data is BOC-wrapped (starts with TON BOC magic 0xb5ee9c72), extract bits
740
+ if (dataSlice(bytes, 0, 4) !== EVMExtraArgsV2Tag) {
741
+ const cell = Cell.fromBoc(bytes)[0]!
742
+ bytes = bytesToBuffer('0x' + cell.bits.toString().toLowerCase().replace('_', '0'))
743
+ }
744
+ if (dataSlice(bytes, 0, 4) !== EVMExtraArgsV2Tag) return
745
+ } catch {
746
+ return
764
747
  }
765
748
 
766
- const allowOutOfOrderExecution = bits[0] === '1'
749
+ const slice = new Slice(new BitReader(new BitString(bytes, 32, bytes.length * 8)), [])
750
+ const gasLimit = slice.loadMaybeUintBig(256) ?? 0n
751
+ const allowOutOfOrderExecution = slice.loadBit()
767
752
 
768
753
  return {
769
754
  _tag: 'EVMExtraArgsV2',
@@ -1226,7 +1211,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
1226
1211
  * {@inheritDoc Chain.getTokenPoolConfig}
1227
1212
  * @throws {@link CCIPNotImplementedError} always (not implemented for TON)
1228
1213
  */
1229
- async getTokenPoolConfig(_tokenPool: string): Promise<never> {
1214
+ async getTokenPoolConfig(_tokenPool: string, _feeOpts?: TokenTransferFeeOpts): Promise<never> {
1230
1215
  return Promise.reject(new CCIPNotImplementedError('getTokenPoolConfig'))
1231
1216
  }
1232
1217
 
package/src/ton/send.ts CHANGED
@@ -3,10 +3,10 @@ import { type TonClient, Address } from '@ton/ton'
3
3
  import { zeroPadValue } from 'ethers'
4
4
 
5
5
  import type { UnsignedTONTx } from './types.ts'
6
- import { CCIPError, CCIPErrorCode } from '../errors/index.ts'
7
- import { EVMExtraArgsV2Tag } from '../extra-args.ts'
8
- import type { AnyMessage, WithLogger } from '../types.ts'
9
- import { bytesToBuffer, getDataBytes } from '../utils.ts'
6
+ import { CCIPError, CCIPErrorCode, CCIPExtraArgsInvalidError } from '../errors/index.ts'
7
+ import { type ExtraArgs, EVMExtraArgsV2Tag } from '../extra-args.ts'
8
+ import { type AnyMessage, type WithLogger, ChainFamily } from '../types.ts'
9
+ import { bigIntReplacer, bytesToBuffer, getDataBytes } from '../utils.ts'
10
10
 
11
11
  /** Opcode for Router ccipSend operation */
12
12
  export const CCIP_SEND_OPCODE = 0x31768d95
@@ -51,28 +51,27 @@ function encodeTokenAmounts(
51
51
  * Format per chainlink-ton TL-B:
52
52
  * - tag: 32-bit opcode (0x181dcf10)
53
53
  * - gasLimit: Maybe<uint256> (1 bit flag + 256 bits if present)
54
- * - allowOutOfOrderExecution: 1 bit (must be true)
54
+ * - allowOutOfOrderExecution: 1 bit
55
+ * @param extraArgs - Extra arguments for CCIP message
56
+ * @returns Cell encoding the extra arguments
55
57
  */
56
- function encodeExtraArgsCell(extraArgs: AnyMessage['extraArgs']): Cell {
57
- const allowOutOfOrderExecution = true
58
-
59
- let gasLimit = 0n
60
- let hasGasLimit = false
61
-
62
- if ('gasLimit' in extraArgs && extraArgs.gasLimit > 0n) {
63
- hasGasLimit = true
58
+ export function encodeExtraArgsCell(extraArgs: ExtraArgs): Cell {
59
+ if (
60
+ Object.keys(extraArgs).filter((k) => k !== '_tag').length !== 2 ||
61
+ !('gasLimit' in extraArgs && 'allowOutOfOrderExecution' in extraArgs)
62
+ )
63
+ throw new CCIPExtraArgsInvalidError(ChainFamily.TON, JSON.stringify(extraArgs, bigIntReplacer))
64
+
65
+ let gasLimit: bigint | null = null
66
+ if (extraArgs.gasLimit > 0n) {
64
67
  gasLimit = extraArgs.gasLimit
65
68
  }
66
69
 
67
- const builder = beginCell()
68
- .storeUint(Number(EVMExtraArgsV2Tag), 32) // 0x181dcf10
69
- .storeBit(hasGasLimit)
70
-
71
- if (hasGasLimit) {
72
- builder.storeUint(gasLimit, 256)
73
- }
70
+ const builder = beginCell().storeUint(Number(EVMExtraArgsV2Tag), 32) // 0x181dcf10
71
+ builder.storeMaybeUint(gasLimit, 256)
72
+ builder.storeBit(extraArgs.allowOutOfOrderExecution)
74
73
 
75
- return builder.storeBit(allowOutOfOrderExecution).endCell()
74
+ return builder.endCell()
76
75
  }
77
76
 
78
77
  /**
package/src/utils.ts CHANGED
@@ -16,12 +16,14 @@ import yaml from 'yaml'
16
16
 
17
17
  import type { Chain, ChainStatic } from './chain.ts'
18
18
  import {
19
+ CCIPAbortError,
19
20
  CCIPBlockBeforeTimestampNotFoundError,
20
21
  CCIPChainFamilyUnsupportedError,
21
22
  CCIPChainNotFoundError,
22
23
  CCIPDataFormatUnsupportedError,
23
24
  CCIPError,
24
25
  CCIPHttpError,
26
+ CCIPTimeoutError,
25
27
  CCIPTypeVersionInvalidError,
26
28
  HttpStatus,
27
29
  } from './errors/index.ts'
@@ -815,6 +817,46 @@ export function createRateLimitedFetch(
815
817
  }
816
818
  }
817
819
 
820
+ /**
821
+ * Performs a fetch request with timeout and abort signal support.
822
+ *
823
+ * @param url - URL to fetch
824
+ * @param operation - Operation name for error context
825
+ * @param opts - Optional timeout, abort signal, fetch function, and extra RequestInit fields
826
+ * @returns Promise resolving to Response
827
+ * @throws CCIPTimeoutError if request times out
828
+ * @throws CCIPAbortError if request is aborted via signal
829
+ */
830
+ export async function fetchWithTimeout(
831
+ url: string,
832
+ operation: string,
833
+ opts?: {
834
+ timeoutMs?: number
835
+ signal?: AbortSignal
836
+ fetch?: typeof globalThis.fetch
837
+ init?: RequestInit
838
+ },
839
+ ): Promise<Response> {
840
+ const timeoutMs = opts?.timeoutMs ?? 30_000
841
+ const fetchFn = opts?.fetch ?? globalThis.fetch.bind(globalThis)
842
+ const timeoutSignal = AbortSignal.timeout(timeoutMs)
843
+ const combinedSignal = opts?.signal
844
+ ? AbortSignal.any([timeoutSignal, opts.signal])
845
+ : timeoutSignal
846
+
847
+ try {
848
+ return await fetchFn(url, { ...opts?.init, signal: combinedSignal })
849
+ } catch (error) {
850
+ if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
851
+ if (opts?.signal?.aborted) {
852
+ throw new CCIPAbortError(operation)
853
+ }
854
+ throw new CCIPTimeoutError(operation, timeoutMs)
855
+ }
856
+ throw error
857
+ }
858
+ }
859
+
818
860
  // barebones `node:util` backfill, if needed
819
861
  const util =
820
862
  'util' in globalThis