@chainlink/ccip-sdk 0.96.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 (199) hide show
  1. package/dist/api/index.d.ts +17 -8
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +27 -10
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/types.d.ts +0 -2
  6. package/dist/api/types.d.ts.map +1 -1
  7. package/dist/aptos/exec.d.ts +2 -2
  8. package/dist/aptos/exec.d.ts.map +1 -1
  9. package/dist/aptos/exec.js.map +1 -1
  10. package/dist/aptos/hasher.d.ts.map +1 -1
  11. package/dist/aptos/hasher.js +1 -1
  12. package/dist/aptos/hasher.js.map +1 -1
  13. package/dist/aptos/index.d.ts +13 -10
  14. package/dist/aptos/index.d.ts.map +1 -1
  15. package/dist/aptos/index.js +42 -68
  16. package/dist/aptos/index.js.map +1 -1
  17. package/dist/aptos/types.d.ts +2 -19
  18. package/dist/aptos/types.d.ts.map +1 -1
  19. package/dist/aptos/types.js +0 -11
  20. package/dist/aptos/types.js.map +1 -1
  21. package/dist/chain.d.ts +532 -151
  22. package/dist/chain.d.ts.map +1 -1
  23. package/dist/chain.js +113 -18
  24. package/dist/chain.js.map +1 -1
  25. package/dist/commits.d.ts +4 -6
  26. package/dist/commits.d.ts.map +1 -1
  27. package/dist/commits.js +4 -4
  28. package/dist/commits.js.map +1 -1
  29. package/dist/errors/CCIPError.d.ts +33 -4
  30. package/dist/errors/CCIPError.d.ts.map +1 -1
  31. package/dist/errors/CCIPError.js +33 -4
  32. package/dist/errors/CCIPError.js.map +1 -1
  33. package/dist/errors/codes.d.ts +3 -0
  34. package/dist/errors/codes.d.ts.map +1 -1
  35. package/dist/errors/codes.js +3 -1
  36. package/dist/errors/codes.js.map +1 -1
  37. package/dist/errors/index.d.ts +1 -1
  38. package/dist/errors/index.d.ts.map +1 -1
  39. package/dist/errors/index.js +1 -1
  40. package/dist/errors/index.js.map +1 -1
  41. package/dist/errors/recovery.d.ts.map +1 -1
  42. package/dist/errors/recovery.js +4 -1
  43. package/dist/errors/recovery.js.map +1 -1
  44. package/dist/errors/specialized.d.ts +1695 -120
  45. package/dist/errors/specialized.d.ts.map +1 -1
  46. package/dist/errors/specialized.js +1715 -123
  47. package/dist/errors/specialized.js.map +1 -1
  48. package/dist/errors/utils.d.ts.map +1 -1
  49. package/dist/errors/utils.js +0 -1
  50. package/dist/errors/utils.js.map +1 -1
  51. package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
  52. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
  53. package/dist/evm/abi/OffRamp_2_0.js +744 -0
  54. package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
  55. package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
  56. package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
  57. package/dist/evm/abi/OnRamp_2_0.js +992 -0
  58. package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
  59. package/dist/evm/const.d.ts +12 -2
  60. package/dist/evm/const.d.ts.map +1 -1
  61. package/dist/evm/const.js +8 -2
  62. package/dist/evm/const.js.map +1 -1
  63. package/dist/evm/errors.d.ts.map +1 -1
  64. package/dist/evm/errors.js +7 -2
  65. package/dist/evm/errors.js.map +1 -1
  66. package/dist/evm/extra-args.d.ts.map +1 -1
  67. package/dist/evm/extra-args.js +5 -24
  68. package/dist/evm/extra-args.js.map +1 -1
  69. package/dist/evm/hasher.d.ts.map +1 -1
  70. package/dist/evm/hasher.js +23 -13
  71. package/dist/evm/hasher.js.map +1 -1
  72. package/dist/evm/index.d.ts +73 -14
  73. package/dist/evm/index.d.ts.map +1 -1
  74. package/dist/evm/index.js +240 -141
  75. package/dist/evm/index.js.map +1 -1
  76. package/dist/evm/messages.d.ts +59 -5
  77. package/dist/evm/messages.d.ts.map +1 -1
  78. package/dist/evm/messages.js +210 -0
  79. package/dist/evm/messages.js.map +1 -1
  80. package/dist/evm/offchain.js.map +1 -1
  81. package/dist/evm/types.d.ts +7 -2
  82. package/dist/evm/types.d.ts.map +1 -1
  83. package/dist/evm/types.js +22 -1
  84. package/dist/evm/types.js.map +1 -1
  85. package/dist/execution.d.ts +62 -22
  86. package/dist/execution.d.ts.map +1 -1
  87. package/dist/execution.js +98 -61
  88. package/dist/execution.js.map +1 -1
  89. package/dist/extra-args.d.ts +13 -3
  90. package/dist/extra-args.d.ts.map +1 -1
  91. package/dist/extra-args.js +13 -3
  92. package/dist/extra-args.js.map +1 -1
  93. package/dist/gas.d.ts +25 -2
  94. package/dist/gas.d.ts.map +1 -1
  95. package/dist/gas.js +30 -4
  96. package/dist/gas.js.map +1 -1
  97. package/dist/index.d.ts +1 -1
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/requests.d.ts +85 -14
  100. package/dist/requests.d.ts.map +1 -1
  101. package/dist/requests.js +99 -16
  102. package/dist/requests.js.map +1 -1
  103. package/dist/selectors.d.ts.map +1 -1
  104. package/dist/selectors.js +12 -0
  105. package/dist/selectors.js.map +1 -1
  106. package/dist/shared/bcs-codecs.d.ts +61 -0
  107. package/dist/shared/bcs-codecs.d.ts.map +1 -0
  108. package/dist/shared/bcs-codecs.js +102 -0
  109. package/dist/shared/bcs-codecs.js.map +1 -0
  110. package/dist/shared/constants.d.ts +3 -0
  111. package/dist/shared/constants.d.ts.map +1 -0
  112. package/dist/shared/constants.js +3 -0
  113. package/dist/shared/constants.js.map +1 -0
  114. package/dist/solana/exec.d.ts +2 -2
  115. package/dist/solana/exec.d.ts.map +1 -1
  116. package/dist/solana/exec.js.map +1 -1
  117. package/dist/solana/index.d.ts +80 -17
  118. package/dist/solana/index.d.ts.map +1 -1
  119. package/dist/solana/index.js +67 -30
  120. package/dist/solana/index.js.map +1 -1
  121. package/dist/sui/hasher.d.ts.map +1 -1
  122. package/dist/sui/hasher.js +1 -1
  123. package/dist/sui/hasher.js.map +1 -1
  124. package/dist/sui/index.d.ts +14 -12
  125. package/dist/sui/index.d.ts.map +1 -1
  126. package/dist/sui/index.js +38 -34
  127. package/dist/sui/index.js.map +1 -1
  128. package/dist/sui/manuallyExec/encoder.d.ts +2 -2
  129. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
  130. package/dist/sui/manuallyExec/encoder.js.map +1 -1
  131. package/dist/sui/manuallyExec/index.d.ts +2 -2
  132. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  133. package/dist/ton/exec.d.ts +2 -2
  134. package/dist/ton/exec.d.ts.map +1 -1
  135. package/dist/ton/exec.js.map +1 -1
  136. package/dist/ton/index.d.ts +9 -16
  137. package/dist/ton/index.d.ts.map +1 -1
  138. package/dist/ton/index.js +26 -31
  139. package/dist/ton/index.js.map +1 -1
  140. package/dist/ton/types.d.ts +2 -2
  141. package/dist/ton/types.d.ts.map +1 -1
  142. package/dist/ton/types.js.map +1 -1
  143. package/dist/types.d.ts +46 -11
  144. package/dist/types.d.ts.map +1 -1
  145. package/dist/types.js +6 -1
  146. package/dist/types.js.map +1 -1
  147. package/dist/utils.d.ts +65 -2
  148. package/dist/utils.d.ts.map +1 -1
  149. package/dist/utils.js +74 -2
  150. package/dist/utils.js.map +1 -1
  151. package/package.json +9 -9
  152. package/src/api/index.ts +33 -10
  153. package/src/api/types.ts +0 -2
  154. package/src/aptos/exec.ts +2 -2
  155. package/src/aptos/hasher.ts +1 -1
  156. package/src/aptos/index.ts +51 -89
  157. package/src/aptos/types.ts +2 -15
  158. package/src/chain.ts +581 -163
  159. package/src/commits.ts +9 -9
  160. package/src/errors/CCIPError.ts +33 -4
  161. package/src/errors/codes.ts +3 -1
  162. package/src/errors/index.ts +1 -0
  163. package/src/errors/recovery.ts +7 -1
  164. package/src/errors/specialized.ts +1726 -130
  165. package/src/errors/utils.ts +0 -1
  166. package/src/evm/abi/OffRamp_2_0.ts +743 -0
  167. package/src/evm/abi/OnRamp_2_0.ts +991 -0
  168. package/src/evm/const.ts +10 -3
  169. package/src/evm/errors.ts +6 -2
  170. package/src/evm/extra-args.ts +4 -21
  171. package/src/evm/hasher.ts +30 -18
  172. package/src/evm/index.ts +310 -166
  173. package/src/evm/messages.ts +323 -11
  174. package/src/evm/offchain.ts +2 -2
  175. package/src/evm/types.ts +20 -2
  176. package/src/execution.ts +125 -86
  177. package/src/extra-args.ts +13 -3
  178. package/src/gas.ts +29 -3
  179. package/src/index.ts +2 -2
  180. package/src/requests.ts +112 -16
  181. package/src/selectors.ts +12 -0
  182. package/src/shared/bcs-codecs.ts +132 -0
  183. package/src/shared/constants.ts +2 -0
  184. package/src/solana/exec.ts +4 -4
  185. package/src/solana/index.ts +100 -68
  186. package/src/sui/hasher.ts +1 -1
  187. package/src/sui/index.ts +50 -47
  188. package/src/sui/manuallyExec/encoder.ts +2 -2
  189. package/src/sui/manuallyExec/index.ts +2 -2
  190. package/src/ton/exec.ts +2 -2
  191. package/src/ton/index.ts +37 -40
  192. package/src/ton/types.ts +2 -2
  193. package/src/types.ts +70 -29
  194. package/src/utils.ts +73 -2
  195. package/dist/aptos/utils.d.ts +0 -12
  196. package/dist/aptos/utils.d.ts.map +0 -1
  197. package/dist/aptos/utils.js +0 -15
  198. package/dist/aptos/utils.js.map +0 -1
  199. package/src/aptos/utils.ts +0 -24
package/src/extra-args.ts CHANGED
@@ -9,7 +9,7 @@ export const EVMExtraArgsV1Tag = id('CCIP EVMExtraArgsV1').substring(0, 10) as '
9
9
  /** Tag identifier for EVMExtraArgsV2 encoding. */
10
10
  export const EVMExtraArgsV2Tag = id('CCIP EVMExtraArgsV2').substring(0, 10) as '0x181dcf10'
11
11
  /** Tag identifier for GenericExtraArgsV3 encoding (tightly packed binary format). */
12
- export const GenericExtraArgsV3Tag = '0x302326cb' as const
12
+ export const GenericExtraArgsV3Tag = id('CCIP GenericExtraArgsV3').substring(0, 10) as '0xa69dd4aa'
13
13
  /** Tag identifier for SVMExtraArgsV1 encoding. */
14
14
  export const SVMExtraArgsV1Tag = id('CCIP SVMExtraArgsV1').substring(0, 10) as '0x1f3b3aba'
15
15
  /** Tag identifier for SuiExtraArgsV1 encoding. */
@@ -145,6 +145,7 @@ export type ExtraArgs =
145
145
  * Encodes extra arguments for CCIP messages.
146
146
  * The args are *to* a dest network, but are encoded as a message *from* this source chain.
147
147
  * E.g. Solana uses Borsh to encode extraArgs in its produced requests, even those targeting EVM.
148
+ *
148
149
  * @param args - Extra arguments to encode
149
150
  * @param from - Source chain family for encoding format (defaults to EVM)
150
151
  * @returns Encoded extra arguments as hex string
@@ -152,12 +153,16 @@ export type ExtraArgs =
152
153
  *
153
154
  * @example
154
155
  * ```typescript
156
+ * import { encodeExtraArgs } from '@chainlink/ccip-sdk'
157
+ *
155
158
  * const encoded = encodeExtraArgs({
156
159
  * gasLimit: 200_000n,
157
160
  * allowOutOfOrderExecution: true,
158
161
  * })
159
- * // Returns: '0x181dcf10...'
162
+ * console.log('Encoded:', encoded) // '0x181dcf10...'
160
163
  * ```
164
+ *
165
+ * @see {@link decodeExtraArgs} - Decode extra arguments from bytes
161
166
  */
162
167
  export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily.EVM): string {
163
168
  const chain = supportedChains[from]
@@ -175,11 +180,16 @@ export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily
175
180
  *
176
181
  * @example
177
182
  * ```typescript
183
+ * import { decodeExtraArgs } from '@chainlink/ccip-sdk'
184
+ *
178
185
  * const decoded = decodeExtraArgs('0x181dcf10...')
179
186
  * if (decoded?._tag === 'EVMExtraArgsV2') {
180
- * console.log(decoded.gasLimit, decoded.allowOutOfOrderExecution)
187
+ * console.log('Gas limit:', decoded.gasLimit)
188
+ * console.log('Out of order:', decoded.allowOutOfOrderExecution)
181
189
  * }
182
190
  * ```
191
+ *
192
+ * @see {@link encodeExtraArgs} - Encode extra arguments to bytes
183
193
  */
184
194
  export function decodeExtraArgs(
185
195
  data: BytesLike,
package/src/gas.ts CHANGED
@@ -4,6 +4,7 @@ import type { Chain } from './chain.ts'
4
4
  import {
5
5
  CCIPContractTypeInvalidError,
6
6
  CCIPMethodUnsupportedError,
7
+ CCIPOnRampRequiredError,
7
8
  CCIPTokenDecimalsInsufficientError,
8
9
  } from './errors/index.ts'
9
10
  import { discoverOffRamp } from './execution.ts'
@@ -50,11 +51,34 @@ export type EstimateReceiveExecutionOpts = {
50
51
 
51
52
  /**
52
53
  * Estimate CCIP gasLimit needed to execute a request on a contract receiver.
53
- * @param opts - Options for estimation: source and dest chains, router or ramp address, and message
54
- * @returns Estimated gasLimit.
54
+ *
55
+ * @param opts - {@link EstimateReceiveExecutionOpts} for estimation
56
+ * @returns Estimated gasLimit
57
+ *
55
58
  * @throws {@link CCIPMethodUnsupportedError} if dest chain doesn't support estimation
56
59
  * @throws {@link CCIPContractTypeInvalidError} if routerOrRamp is not a valid contract type
57
60
  * @throws {@link CCIPTokenDecimalsInsufficientError} if dest token has insufficient decimals
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { estimateReceiveExecution, EVMChain } from '@chainlink/ccip-sdk'
65
+ *
66
+ * const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
67
+ * const dest = await EVMChain.fromUrl('https://rpc.fuji.avax.network')
68
+ *
69
+ * const gasLimit = await estimateReceiveExecution({
70
+ * source,
71
+ * dest,
72
+ * routerOrRamp: '0xRouter...',
73
+ * message: {
74
+ * sender: '0x...',
75
+ * receiver: '0x...',
76
+ * data: '0x...',
77
+ * tokenAmounts: [],
78
+ * },
79
+ * })
80
+ * console.log('Estimated gas:', gasLimit)
81
+ * ```
58
82
  */
59
83
  export async function estimateReceiveExecution({
60
84
  source,
@@ -78,7 +102,9 @@ export async function estimateReceiveExecution({
78
102
  if (!tnv[0].includes('OffRamp'))
79
103
  throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
80
104
  offRamp = routerOrRamp
81
- onRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
105
+ const onRamps = await dest.getOnRampsForOffRamp(offRamp, source.network.chainSelector)
106
+ if (!onRamps.length) throw new CCIPOnRampRequiredError()
107
+ onRamp = onRamps[onRamps.length - 1]!
82
108
  } catch {
83
109
  throw sourceErr // re-throw original error
84
110
  }
package/src/index.ts CHANGED
@@ -43,14 +43,14 @@ export {
43
43
  export { estimateReceiveExecution } from './gas.ts'
44
44
  export { decodeMessage, getMessagesForSender, sourceToDestTokenAddresses } from './requests.ts'
45
45
  export {
46
- type CCIPCommit,
47
46
  type CCIPExecution,
48
47
  type CCIPMessage,
49
48
  type CCIPRequest,
49
+ type CCIPVerifications,
50
50
  type ChainTransaction,
51
51
  type CommitReport,
52
+ type ExecutionInput,
52
53
  type ExecutionReceipt,
53
- type ExecutionReport,
54
54
  type Lane,
55
55
  type Logger,
56
56
  type MessageInput,
package/src/requests.ts CHANGED
@@ -46,6 +46,14 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
46
46
  source_chain_selector?: string
47
47
  sourceChainSelector?: string
48
48
  extraArgs?: string | Record<string, unknown>
49
+ sequenceNumber?: bigint
50
+ messageNumber?: bigint
51
+ tokenTransfer?: {
52
+ destExecData: string
53
+ destGasAmount?: bigint
54
+ token?: string
55
+ sourceTokenAddress?: string
56
+ }[]
49
57
  tokenAmounts: {
50
58
  destExecData: string
51
59
  destGasAmount?: bigint
@@ -60,6 +68,7 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
60
68
  totalAmount: bigint
61
69
  }
62
70
  }
71
+ receipts?: { feeTokenAmount: bigint }[]
63
72
  sourceNetworkInfo?: { chainSelector: string }
64
73
  destNetworkInfo?: { chainSelector: string }
65
74
  }
@@ -82,7 +91,7 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
82
91
  ? BigInt(v as string | number | bigint)
83
92
  : k?.match(/(^dest.*address)|(receiver|offramp|accounts)/i)
84
93
  ? decodeAddress(v as BytesLike, destFamily)
85
- : k?.match(/((source.*address)|sender|origin|onramp|(feetoken$)|(token.*address$))/i)
94
+ : k?.match(/((source.*address)|sender|issuer|origin|onramp|(feetoken$)|(token.*address$))/i)
86
95
  ? decodeAddress(v as BytesLike, sourceFamily)
87
96
  : v instanceof Uint8Array ||
88
97
  (Array.isArray(v) && v.length >= 4 && v.every((e) => typeof e === 'number'))
@@ -90,6 +99,10 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
90
99
  : v,
91
100
  ) as typeof data_
92
101
 
102
+ if (data_.tokenTransfer) {
103
+ data_.tokenAmounts = data_.tokenTransfer
104
+ delete data_.tokenTransfer
105
+ }
93
106
  for (const ta of data_.tokenAmounts) {
94
107
  if (ta.token && !ta.sourceTokenAddress) ta.sourceTokenAddress = ta.token
95
108
  if (!ta.token && ta.sourceTokenAddress) ta.token = ta.sourceTokenAddress
@@ -121,6 +134,15 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
121
134
  data_.feeToken = data_.fees.fixedFeesDetails.tokenAddress
122
135
  data_.feeTokenAmount = data_.fees.fixedFeesDetails.totalAmount
123
136
  }
137
+ if (data_.sequenceNumber == null && data_.messageNumber != null) {
138
+ data_.sequenceNumber = data_.messageNumber
139
+ }
140
+ if (!data_.feeTokenAmount && data_.receipts) {
141
+ data_.feeTokenAmount = data_.receipts.reduce(
142
+ (acc, receipt) => acc + receipt.feeTokenAmount,
143
+ BigInt(0),
144
+ )
145
+ }
124
146
 
125
147
  return data_ as unknown as CCIPMessage
126
148
  }
@@ -128,9 +150,24 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
128
150
  /**
129
151
  * Decodes hex strings, bytearrays, JSON strings and raw objects as CCIPMessages.
130
152
  * Does minimal validation, but converts objects in the format expected by ccip-tools-ts.
153
+ *
131
154
  * @param data - Data to decode (hex string, Uint8Array, JSON string, or object)
132
155
  * @returns Decoded CCIPMessage
133
156
  * @throws {@link CCIPMessageDecodeError} if data cannot be decoded as a valid message
157
+ * @throws {@link CCIPMessageInvalidError} if message structure is invalid or missing required fields
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * import { decodeMessage } from '@chainlink/ccip-sdk'
162
+ *
163
+ * // Decode from JSON string
164
+ * const message = decodeMessage('{"header":{"sourceChainSelector":"123",...}')
165
+ *
166
+ * // Decode from hex-encoded bytes
167
+ * const message = decodeMessage('0x...')
168
+ *
169
+ * console.log('Message ID:', message.messageId)
170
+ * ```
134
171
  */
135
172
  export function decodeMessage(data: string | Uint8Array | Record<string, unknown>): CCIPMessage {
136
173
  if (
@@ -171,6 +208,8 @@ export function buildMessageForDest(message: MessageInput, dest: ChainFamily): A
171
208
  * @returns CCIP requests (messages) in the transaction (at least one)
172
209
  * @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported for legacy messages
173
210
  * @throws {@link CCIPMessageNotFoundInTxError} if no CCIP messages found in transaction
211
+ *
212
+ * @see {@link getMessageById} - Search by messageId when tx hash unknown
174
213
  */
175
214
  export async function getMessagesInTx(source: Chain, tx: ChainTransaction): Promise<CCIPRequest[]> {
176
215
  // RPC fallback
@@ -194,17 +233,36 @@ export async function getMessagesInTx(source: Chain, tx: ChainTransaction): Prom
194
233
  }
195
234
  requests.push({ lane, message, log, tx })
196
235
  }
197
- if (!requests.length) throw new CCIPMessageNotFoundInTxError(tx.hash)
236
+ if (!requests.length)
237
+ throw new CCIPMessageNotFoundInTxError(tx.hash, { context: { network: source.network.name } })
198
238
  return requests
199
239
  }
200
240
 
201
241
  /**
202
- * Fetch a CCIP message by its messageId from RPC (slow).
203
- * Should be called *after* generic Chain implementation, which fetches from API if available.
204
- * @param source - Provider to fetch logs from.
205
- * @param messageId - MessageId to search for.
206
- * @param opts - Optional hints for pagination (e.g., `address` for onRamp, `page` for pagination size).
207
- * @returns CCIPRequest with given messageId.
242
+ * Fetch a CCIP message by messageId from RPC logs (slow scan).
243
+ *
244
+ * This is the fallback implementation called by {@link Chain.getMessageById}
245
+ * when the API client is unavailable or fails.
246
+ *
247
+ * @param source - Source chain to scan logs from
248
+ * @param messageId - Message ID to search for
249
+ * @param opts - Optional hints (onRamp address narrows search, page controls batch size)
250
+ * @returns CCIPRequest matching the messageId
251
+ *
252
+ * @throws {@link CCIPMessageIdNotFoundError} if message not found after scanning all logs
253
+ *
254
+ * @example
255
+ *
256
+ * ```typescript
257
+ * import { getMessageById, EVMChain } from '@chainlink/ccip-sdk'
258
+ *
259
+ * const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
260
+ * const request = await getMessageById(source, '0xabc123...', {
261
+ * onRamp: '0xOnRampAddress...',
262
+ * })
263
+ * console.log(`Found: seqNr=${request.message.sequenceNumber}`)
264
+ * ```
265
+ *
208
266
  * @internal
209
267
  */
210
268
  export async function getMessageById(
@@ -249,9 +307,10 @@ const BLOCK_LOG_WINDOW_SIZE = 5000
249
307
  * Fetches all CCIP messages contained in a given commit batch.
250
308
  * @param source - The source chain.
251
309
  * @param request - The CCIP request containing lane and message info.
252
- * @param seqNrRange - Object containing minSeqNr and maxSeqNr for the batch range.
310
+ * @param range - Object containing minSeqNr and maxSeqNr for the batch range.
253
311
  * @param opts - Optional log filtering parameters.
254
312
  * @returns Array of messages in the batch.
313
+ * @see {@link getVerifications} - Get commit report to determine batch range
255
314
  */
256
315
  export async function getMessagesInBatch<
257
316
  C extends Chain,
@@ -293,6 +352,7 @@ export async function getMessagesInBatch<
293
352
  const message = (source.constructor as ChainStatic).decodeMessage(log)
294
353
  if (
295
354
  !message ||
355
+ !('sequenceNumber' in message) ||
296
356
  ('destChainSelector' in message &&
297
357
  message.destChainSelector !== request.lane.destChainSelector)
298
358
  )
@@ -314,6 +374,7 @@ export async function getMessagesInBatch<
314
374
  const message = (source.constructor as ChainStatic).decodeMessage(log)
315
375
  if (
316
376
  !message ||
377
+ !('sequenceNumber' in message) ||
317
378
  ('destChainSelector' in message &&
318
379
  message.destChainSelector !== request.lane.destChainSelector)
319
380
  )
@@ -339,6 +400,21 @@ export async function getMessagesInBatch<
339
400
  * @param filter - Log filter options.
340
401
  * @returns Async generator of CCIP requests.
341
402
  * @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported for legacy messages
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * import { getMessagesForSender, EVMChain } from '@chainlink/ccip-sdk'
407
+ *
408
+ * const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
409
+ *
410
+ * for await (const request of getMessagesForSender(chain, '0xSenderAddress', {})) {
411
+ * console.log('Message ID:', request.message.messageId)
412
+ * console.log('Destination:', request.lane.destChainSelector)
413
+ * }
414
+ * ```
415
+ *
416
+ * @see {@link getMessagesInTx} - Fetch from specific transaction
417
+ * @see {@link getMessageById} - Search by messageId
342
418
  */
343
419
  export async function* getMessagesForSender(
344
420
  source: Chain,
@@ -376,13 +452,33 @@ export async function* getMessagesForSender(
376
452
  }
377
453
 
378
454
  /**
379
- * Map source `token` to `sourcePoolAddress + destTokenAddress`.
380
- * @param source - Source chain.
381
- * @param destChainSelector - Destination network selector.
382
- * @param onRamp - Contract address.
383
- * @param sourceTokenAmount - tokenAmount object, usually containing `token` and `amount` properties.
384
- * @returns tokenAmount object with `sourcePoolAddress`, `sourceTokenAddress`, `destTokenAddress`, and remaining properties.
385
- * @throws {@link CCIPTokenNotInRegistryError} if token not found in registry
455
+ * Map source token to its pool address and destination token address.
456
+ *
457
+ * Resolves token routing by querying the TokenAdminRegistry and TokenPool
458
+ * to find the corresponding destination chain token.
459
+ *
460
+ * @param source - Source chain instance
461
+ * @param destChainSelector - Destination chain selector
462
+ * @param onRamp - OnRamp contract address
463
+ * @param sourceTokenAmount - Token amount object containing `token` and `amount`
464
+ * @returns Extended token amount with `sourcePoolAddress`, `sourceTokenAddress`, and `destTokenAddress`
465
+ *
466
+ * @throws {@link CCIPTokenNotInRegistryError} if token is not registered in TokenAdminRegistry
467
+ *
468
+ * @example
469
+ * ```typescript
470
+ * import { sourceToDestTokenAddresses, EVMChain } from '@chainlink/ccip-sdk'
471
+ *
472
+ * const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
473
+ * const tokenAmount = await sourceToDestTokenAddresses(
474
+ * source,
475
+ * destChainSelector,
476
+ * '0xOnRamp...',
477
+ * { token: '0xLINK...', amount: 1000000000000000000n }
478
+ * )
479
+ * console.log(`Pool: ${tokenAmount.sourcePoolAddress}`)
480
+ * console.log(`Dest token: ${tokenAmount.destTokenAddress}`)
481
+ * ```
386
482
  */
387
483
  export async function sourceToDestTokenAddresses<S extends { token: string }>(
388
484
  source: Chain,
package/src/selectors.ts CHANGED
@@ -1099,6 +1099,12 @@ const selectors: Selectors = {
1099
1099
  network_type: 'TESTNET',
1100
1100
  family: 'EVM',
1101
1101
  },
1102
+ '46630': {
1103
+ selector: 2032988798112970440n,
1104
+ name: 'robinhood-testnet',
1105
+ network_type: 'TESTNET',
1106
+ family: 'EVM',
1107
+ },
1102
1108
  '47763': {
1103
1109
  selector: 7222032299962346917n,
1104
1110
  name: 'neox-mainnet',
@@ -1349,6 +1355,12 @@ const selectors: Selectors = {
1349
1355
  network_type: 'MAINNET',
1350
1356
  family: 'EVM',
1351
1357
  },
1358
+ '202601': {
1359
+ selector: 1091131740251125869n,
1360
+ name: 'ethereum-testnet-sepolia-ronin-1',
1361
+ network_type: 'TESTNET',
1362
+ family: 'EVM',
1363
+ },
1352
1364
  '421613': {
1353
1365
  selector: 6101244977088475029n,
1354
1366
  name: 'ethereum-testnet-goerli-arbitrum-1',
@@ -0,0 +1,132 @@
1
+ /**
2
+ * BCS (Binary Canonical Serialization) codecs for Move-based chains (Aptos, Sui).
3
+ * These chains share similar BCS encoding and 32-byte address formats.
4
+ */
5
+ import { bcs } from '@mysten/bcs'
6
+ import {
7
+ type BigNumberish,
8
+ type BytesLike,
9
+ concat,
10
+ dataLength,
11
+ dataSlice,
12
+ getBytes,
13
+ hexlify,
14
+ toBeHex,
15
+ zeroPadBytes,
16
+ zeroPadValue,
17
+ } from 'ethers'
18
+
19
+ import { CCIPDataFormatUnsupportedError } from '../errors/index.ts'
20
+ import {
21
+ type EVMExtraArgsV2,
22
+ type SVMExtraArgsV1,
23
+ EVMExtraArgsV2Tag,
24
+ SVMExtraArgsV1Tag,
25
+ } from '../extra-args.ts'
26
+ import { ChainFamily } from '../types.ts'
27
+ import { decodeAddress, getDataBytes } from '../utils.ts'
28
+
29
+ /**
30
+ * BCS codec for decoding EVM extra args on Move chains (Aptos/Sui).
31
+ * Used when receiving cross-chain messages from EVM source chains.
32
+ */
33
+ export const BcsEVMExtraArgsV2Codec = bcs.struct('EVMExtraArgsV2', {
34
+ gasLimit: bcs.u256(),
35
+ allowOutOfOrderExecution: bcs.bool(),
36
+ })
37
+
38
+ /**
39
+ * BCS codec for decoding SVM (Solana) extra args on Move chains (Aptos/Sui).
40
+ * Used when receiving cross-chain messages from Solana source chains.
41
+ */
42
+ export const BcsSVMExtraArgsV1Codec = bcs.struct('SVMExtraArgsV1', {
43
+ computeUnits: bcs.u32(),
44
+ accountIsWritableBitmap: bcs.u64(),
45
+ allowOutOfOrderExecution: bcs.bool(),
46
+ tokenReceiver: bcs.vector(bcs.u8()),
47
+ accounts: bcs.vector(bcs.vector(bcs.u8())),
48
+ })
49
+
50
+ /**
51
+ * Decodes extra arguments from Move-based chain CCIP messages.
52
+ * Works for both Aptos and Sui since they share the same BCS encoding.
53
+ * @param extraArgs - Encoded extra arguments bytes.
54
+ * @returns Decoded extra arguments or undefined if unknown format.
55
+ */
56
+ export function decodeMoveExtraArgs(
57
+ extraArgs: BytesLike,
58
+ ):
59
+ | (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
60
+ | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
61
+ | undefined {
62
+ const data = getDataBytes(extraArgs),
63
+ tag = dataSlice(data, 0, 4)
64
+ switch (tag) {
65
+ case EVMExtraArgsV2Tag: {
66
+ const parsed = BcsEVMExtraArgsV2Codec.parse(getBytes(dataSlice(data, 4)))
67
+ // Move serialization of EVMExtraArgsV2: 37 bytes total: 4 tag + 32 LE gasLimit + 1 allowOOOE
68
+ return {
69
+ _tag: 'EVMExtraArgsV2',
70
+ ...parsed,
71
+ gasLimit: BigInt(parsed.gasLimit),
72
+ }
73
+ }
74
+ case SVMExtraArgsV1Tag: {
75
+ const parsed = BcsSVMExtraArgsV1Codec.parse(getBytes(dataSlice(data, 4)))
76
+ // Move serialization of SVMExtraArgsV1: 13 bytes total: 4 tag + 8 LE computeUnits
77
+ return {
78
+ _tag: 'SVMExtraArgsV1',
79
+ ...parsed,
80
+ computeUnits: BigInt(parsed.computeUnits),
81
+ accountIsWritableBitmap: BigInt(parsed.accountIsWritableBitmap),
82
+ tokenReceiver: decodeAddress(new Uint8Array(parsed.tokenReceiver), ChainFamily.Solana),
83
+ accounts: parsed.accounts.map((account) =>
84
+ decodeAddress(new Uint8Array(account), ChainFamily.Solana),
85
+ ),
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Converts bytes to a Move-chain address (32-byte zero-padded).
93
+ * Works for both Aptos and Sui since they share the same address format.
94
+ * @param bytes - Bytes to convert.
95
+ * @returns Address as 0x-prefixed hex string, 32 bytes padded.
96
+ * @throws {@link CCIPDataFormatUnsupportedError} if bytes length exceeds 32
97
+ */
98
+ export function getMoveAddress(bytes: BytesLike | readonly number[]): string {
99
+ let suffix = ''
100
+ if (Array.isArray(bytes)) bytes = new Uint8Array(bytes)
101
+ if (typeof bytes === 'string' && bytes.startsWith('0x')) {
102
+ const idx = bytes.indexOf('::')
103
+ if (idx > 0) {
104
+ suffix = bytes.slice(idx)
105
+ bytes = bytes.slice(0, idx)
106
+ }
107
+ }
108
+ bytes = getDataBytes(bytes)
109
+ if (bytes.length > 32)
110
+ throw new CCIPDataFormatUnsupportedError(`Move address exceeds 32 bytes: ${hexlify(bytes)}`)
111
+ return zeroPadValue(bytes, 32) + suffix
112
+ }
113
+
114
+ /**
115
+ * Encodes a numeric value as a 32-byte hex string.
116
+ * Used for BCS encoding on Move chains (Aptos/Sui).
117
+ * @param value - Numeric value to encode.
118
+ * @returns 32-byte hex string representation of the value.
119
+ */
120
+ export const encodeNumber = (value: BigNumberish): string => toBeHex(value, 32)
121
+
122
+ /**
123
+ * Encodes dynamic bytes with length prefix for BCS serialization.
124
+ * Used for BCS encoding on Move chains (Aptos/Sui).
125
+ * @param value - Bytes to encode.
126
+ * @returns Encoded bytes with 32-byte aligned padding.
127
+ */
128
+ export const encodeRawBytes = (value: BytesLike): string =>
129
+ concat([
130
+ encodeNumber(dataLength(value)),
131
+ zeroPadBytes(value, Math.ceil(dataLength(value) / 32) * 32),
132
+ ])
@@ -0,0 +1,2 @@
1
+ /** Default gas limit for cross-chain message execution (200,000 units). */
2
+ export const DEFAULT_GAS_LIMIT = 200_000n
@@ -14,7 +14,7 @@ import BN from 'bn.js'
14
14
  import { hexlify } from 'ethers'
15
15
 
16
16
  import { CCIPSolanaLookupTableNotFoundError } from '../errors/index.ts'
17
- import { type ExecutionReport, type WithLogger, ChainFamily } from '../types.ts'
17
+ import { type ExecutionInput, type WithLogger, ChainFamily } from '../types.ts'
18
18
  import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
19
19
  import { encodeSolanaOffchainTokenData } from './offchain.ts'
20
20
  import type { CCIPMessage_V1_6_Solana, UnsignedSolanaTx } from './types.ts'
@@ -43,7 +43,7 @@ export async function generateUnsignedExecuteReport(
43
43
  ctx: { connection: Connection } & WithLogger,
44
44
  payer: PublicKey,
45
45
  offramp: PublicKey,
46
- execReport: ExecutionReport<CCIPMessage_V1_6_Solana>,
46
+ execReport: ExecutionInput<CCIPMessage_V1_6_Solana>,
47
47
  opts?: { forceLookupTable?: boolean; forceBuffer?: boolean; clearLeftoverAccounts?: boolean },
48
48
  ): Promise<UnsignedSolanaTx> {
49
49
  const { connection, logger = console } = ctx
@@ -274,7 +274,7 @@ async function getManuallyExecuteInputs({
274
274
  }: {
275
275
  payer: PublicKey
276
276
  offramp: Program<typeof CCIP_OFFRAMP_IDL>
277
- execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
277
+ execReport: ExecutionInput<CCIPMessage_V1_6_Solana>
278
278
  bufferId?: Buffer
279
279
  } & WithLogger) {
280
280
  const executionReport = prepareExecutionReport(execReport)
@@ -346,7 +346,7 @@ function prepareExecutionReport({
346
346
  message,
347
347
  offchainTokenData,
348
348
  proofs,
349
- }: ExecutionReport<CCIPMessage_V1_6_Solana>): IdlTypes<
349
+ }: ExecutionInput<CCIPMessage_V1_6_Solana>): IdlTypes<
350
350
  typeof CCIP_OFFRAMP_IDL
351
351
  >['ExecutionReportSingleChain'] {
352
352
  return {