@chainlink/ccip-sdk 0.91.1 → 0.92.1

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 (273) hide show
  1. package/README.md +127 -80
  2. package/dist/aptos/hasher.d.ts.map +1 -1
  3. package/dist/aptos/hasher.js +7 -6
  4. package/dist/aptos/hasher.js.map +1 -1
  5. package/dist/aptos/index.d.ts +7 -2
  6. package/dist/aptos/index.d.ts.map +1 -1
  7. package/dist/aptos/index.js +29 -20
  8. package/dist/aptos/index.js.map +1 -1
  9. package/dist/aptos/logs.d.ts +5 -3
  10. package/dist/aptos/logs.d.ts.map +1 -1
  11. package/dist/aptos/logs.js +64 -27
  12. package/dist/aptos/logs.js.map +1 -1
  13. package/dist/aptos/token.d.ts.map +1 -1
  14. package/dist/aptos/token.js +2 -1
  15. package/dist/aptos/token.js.map +1 -1
  16. package/dist/aptos/types.js +6 -6
  17. package/dist/aptos/types.js.map +1 -1
  18. package/dist/chain.d.ts +36 -11
  19. package/dist/chain.d.ts.map +1 -1
  20. package/dist/chain.js +34 -2
  21. package/dist/chain.js.map +1 -1
  22. package/dist/commits.d.ts +2 -3
  23. package/dist/commits.d.ts.map +1 -1
  24. package/dist/commits.js +19 -8
  25. package/dist/commits.js.map +1 -1
  26. package/dist/errors/CCIPError.d.ts +48 -0
  27. package/dist/errors/CCIPError.d.ts.map +1 -0
  28. package/dist/errors/CCIPError.js +65 -0
  29. package/dist/errors/CCIPError.js.map +1 -0
  30. package/dist/errors/codes.d.ts +120 -0
  31. package/dist/errors/codes.d.ts.map +1 -0
  32. package/dist/errors/codes.js +156 -0
  33. package/dist/errors/codes.js.map +1 -0
  34. package/dist/errors/index.d.ts +26 -0
  35. package/dist/errors/index.d.ts.map +1 -0
  36. package/dist/errors/index.js +51 -0
  37. package/dist/errors/index.js.map +1 -0
  38. package/dist/errors/recovery.d.ts +6 -0
  39. package/dist/errors/recovery.d.ts.map +1 -0
  40. package/dist/errors/recovery.js +118 -0
  41. package/dist/errors/recovery.js.map +1 -0
  42. package/dist/errors/specialized.d.ts +637 -0
  43. package/dist/errors/specialized.d.ts.map +1 -0
  44. package/dist/errors/specialized.js +1298 -0
  45. package/dist/errors/specialized.js.map +1 -0
  46. package/dist/errors/utils.d.ts +11 -0
  47. package/dist/errors/utils.d.ts.map +1 -0
  48. package/dist/errors/utils.js +61 -0
  49. package/dist/errors/utils.js.map +1 -0
  50. package/dist/evm/abi/CommitStore_1_5.js +1 -1
  51. package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1 -1
  52. package/dist/evm/abi/OffRamp_1_5.js +1 -1
  53. package/dist/evm/abi/OnRamp_1_5.js +1 -1
  54. package/dist/evm/abi/PriceRegistry_1_2.d.ts +443 -0
  55. package/dist/evm/abi/PriceRegistry_1_2.d.ts.map +1 -0
  56. package/dist/evm/abi/PriceRegistry_1_2.js +439 -0
  57. package/dist/evm/abi/PriceRegistry_1_2.js.map +1 -0
  58. package/dist/evm/const.d.ts +1 -0
  59. package/dist/evm/const.d.ts.map +1 -1
  60. package/dist/evm/const.js +2 -0
  61. package/dist/evm/const.js.map +1 -1
  62. package/dist/evm/hasher.d.ts.map +1 -1
  63. package/dist/evm/hasher.js +7 -6
  64. package/dist/evm/hasher.js.map +1 -1
  65. package/dist/evm/index.d.ts +9 -13
  66. package/dist/evm/index.d.ts.map +1 -1
  67. package/dist/evm/index.js +85 -68
  68. package/dist/evm/index.js.map +1 -1
  69. package/dist/evm/logs.d.ts.map +1 -1
  70. package/dist/evm/logs.js +47 -16
  71. package/dist/evm/logs.js.map +1 -1
  72. package/dist/evm/messages.d.ts +7 -6
  73. package/dist/evm/messages.d.ts.map +1 -1
  74. package/dist/evm/offchain.js +1 -1
  75. package/dist/evm/offchain.js.map +1 -1
  76. package/dist/evm/types.d.ts +10 -0
  77. package/dist/evm/types.d.ts.map +1 -0
  78. package/dist/evm/types.js +2 -0
  79. package/dist/evm/types.js.map +1 -0
  80. package/dist/execution.d.ts.map +1 -1
  81. package/dist/execution.js +9 -5
  82. package/dist/execution.js.map +1 -1
  83. package/dist/extra-args.d.ts.map +1 -1
  84. package/dist/extra-args.js +4 -3
  85. package/dist/extra-args.js.map +1 -1
  86. package/dist/gas.d.ts.map +1 -1
  87. package/dist/gas.js +3 -2
  88. package/dist/gas.js.map +1 -1
  89. package/dist/hasher/hasher.d.ts.map +1 -1
  90. package/dist/hasher/hasher.js +2 -1
  91. package/dist/hasher/hasher.js.map +1 -1
  92. package/dist/hasher/merklemulti.d.ts.map +1 -1
  93. package/dist/hasher/merklemulti.js +9 -8
  94. package/dist/hasher/merklemulti.js.map +1 -1
  95. package/dist/index.d.ts +5 -2
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +6 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/offchain.d.ts.map +1 -1
  100. package/dist/offchain.js +5 -8
  101. package/dist/offchain.js.map +1 -1
  102. package/dist/requests.d.ts +1 -1
  103. package/dist/requests.d.ts.map +1 -1
  104. package/dist/requests.js +37 -43
  105. package/dist/requests.js.map +1 -1
  106. package/dist/selectors.d.ts.map +1 -1
  107. package/dist/selectors.js +22 -0
  108. package/dist/selectors.js.map +1 -1
  109. package/dist/solana/cleanup.d.ts +2 -2
  110. package/dist/solana/cleanup.d.ts.map +1 -1
  111. package/dist/solana/cleanup.js +2 -3
  112. package/dist/solana/cleanup.js.map +1 -1
  113. package/dist/solana/exec.d.ts.map +1 -1
  114. package/dist/solana/exec.js +12 -12
  115. package/dist/solana/exec.js.map +1 -1
  116. package/dist/solana/hasher.d.ts.map +1 -1
  117. package/dist/solana/hasher.js +6 -5
  118. package/dist/solana/hasher.js.map +1 -1
  119. package/dist/solana/index.d.ts +30 -13
  120. package/dist/solana/index.d.ts.map +1 -1
  121. package/dist/solana/index.js +96 -143
  122. package/dist/solana/index.js.map +1 -1
  123. package/dist/solana/logs.d.ts +15 -0
  124. package/dist/solana/logs.d.ts.map +1 -0
  125. package/dist/solana/logs.js +106 -0
  126. package/dist/solana/logs.js.map +1 -0
  127. package/dist/solana/offchain.d.ts.map +1 -1
  128. package/dist/solana/offchain.js +6 -5
  129. package/dist/solana/offchain.js.map +1 -1
  130. package/dist/solana/patchBorsh.d.ts.map +1 -1
  131. package/dist/solana/patchBorsh.js +3 -2
  132. package/dist/solana/patchBorsh.js.map +1 -1
  133. package/dist/solana/send.d.ts.map +1 -1
  134. package/dist/solana/send.js +8 -7
  135. package/dist/solana/send.js.map +1 -1
  136. package/dist/solana/utils.d.ts +7 -8
  137. package/dist/solana/utils.d.ts.map +1 -1
  138. package/dist/solana/utils.js +23 -11
  139. package/dist/solana/utils.js.map +1 -1
  140. package/dist/sui/discovery.d.ts +18 -0
  141. package/dist/sui/discovery.d.ts.map +1 -0
  142. package/dist/sui/discovery.js +116 -0
  143. package/dist/sui/discovery.js.map +1 -0
  144. package/dist/sui/events.d.ts +36 -0
  145. package/dist/sui/events.d.ts.map +1 -0
  146. package/dist/sui/events.js +176 -0
  147. package/dist/sui/events.js.map +1 -0
  148. package/dist/sui/hasher.d.ts.map +1 -1
  149. package/dist/sui/hasher.js +6 -5
  150. package/dist/sui/hasher.js.map +1 -1
  151. package/dist/sui/index.d.ts +69 -41
  152. package/dist/sui/index.d.ts.map +1 -1
  153. package/dist/sui/index.js +402 -65
  154. package/dist/sui/index.js.map +1 -1
  155. package/dist/sui/manuallyExec/encoder.d.ts +8 -0
  156. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -0
  157. package/dist/sui/manuallyExec/encoder.js +76 -0
  158. package/dist/sui/manuallyExec/encoder.js.map +1 -0
  159. package/dist/sui/manuallyExec/index.d.ts +37 -0
  160. package/dist/sui/manuallyExec/index.d.ts.map +1 -0
  161. package/dist/sui/manuallyExec/index.js +81 -0
  162. package/dist/sui/manuallyExec/index.js.map +1 -0
  163. package/dist/sui/objects.d.ts +46 -0
  164. package/dist/sui/objects.d.ts.map +1 -0
  165. package/dist/sui/objects.js +259 -0
  166. package/dist/sui/objects.js.map +1 -0
  167. package/dist/ton/bindings/offramp.d.ts +48 -0
  168. package/dist/ton/bindings/offramp.d.ts.map +1 -0
  169. package/dist/ton/bindings/offramp.js +63 -0
  170. package/dist/ton/bindings/offramp.js.map +1 -0
  171. package/dist/ton/bindings/onramp.d.ts +40 -0
  172. package/dist/ton/bindings/onramp.d.ts.map +1 -0
  173. package/dist/ton/bindings/onramp.js +51 -0
  174. package/dist/ton/bindings/onramp.js.map +1 -0
  175. package/dist/ton/bindings/router.d.ts +47 -0
  176. package/dist/ton/bindings/router.d.ts.map +1 -0
  177. package/dist/ton/bindings/router.js +51 -0
  178. package/dist/ton/bindings/router.js.map +1 -0
  179. package/dist/ton/exec.d.ts +18 -0
  180. package/dist/ton/exec.d.ts.map +1 -0
  181. package/dist/ton/exec.js +28 -0
  182. package/dist/ton/exec.js.map +1 -0
  183. package/dist/ton/hasher.d.ts +27 -0
  184. package/dist/ton/hasher.d.ts.map +1 -0
  185. package/dist/ton/hasher.js +134 -0
  186. package/dist/ton/hasher.js.map +1 -0
  187. package/dist/ton/index.d.ts +247 -0
  188. package/dist/ton/index.d.ts.map +1 -0
  189. package/dist/ton/index.js +781 -0
  190. package/dist/ton/index.js.map +1 -0
  191. package/dist/ton/logs.d.ts +26 -0
  192. package/dist/ton/logs.d.ts.map +1 -0
  193. package/dist/ton/logs.js +126 -0
  194. package/dist/ton/logs.js.map +1 -0
  195. package/dist/ton/types.d.ts +37 -0
  196. package/dist/ton/types.d.ts.map +1 -0
  197. package/dist/ton/types.js +92 -0
  198. package/dist/ton/types.js.map +1 -0
  199. package/dist/ton/utils.d.ts +67 -0
  200. package/dist/ton/utils.d.ts.map +1 -0
  201. package/dist/ton/utils.js +425 -0
  202. package/dist/ton/utils.js.map +1 -0
  203. package/dist/types.d.ts +4 -2
  204. package/dist/types.d.ts.map +1 -1
  205. package/dist/types.js +1 -0
  206. package/dist/types.js.map +1 -1
  207. package/dist/utils.d.ts +10 -0
  208. package/dist/utils.d.ts.map +1 -1
  209. package/dist/utils.js +52 -17
  210. package/dist/utils.js.map +1 -1
  211. package/package.json +11 -9
  212. package/src/aptos/hasher.ts +10 -6
  213. package/src/aptos/index.ts +50 -31
  214. package/src/aptos/logs.ts +85 -29
  215. package/src/aptos/token.ts +5 -1
  216. package/src/aptos/types.ts +6 -6
  217. package/src/chain.ts +83 -12
  218. package/src/commits.ts +23 -11
  219. package/src/errors/CCIPError.ts +86 -0
  220. package/src/errors/codes.ts +179 -0
  221. package/src/errors/index.ts +175 -0
  222. package/src/errors/recovery.ts +170 -0
  223. package/src/errors/specialized.ts +1655 -0
  224. package/src/errors/utils.ts +73 -0
  225. package/src/evm/abi/CommitStore_1_5.ts +1 -1
  226. package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1 -1
  227. package/src/evm/abi/OffRamp_1_5.ts +1 -1
  228. package/src/evm/abi/OnRamp_1_5.ts +1 -1
  229. package/src/evm/abi/PriceRegistry_1_2.ts +438 -0
  230. package/src/evm/const.ts +2 -0
  231. package/src/evm/hasher.ts +7 -6
  232. package/src/evm/index.ts +104 -86
  233. package/src/evm/logs.ts +64 -16
  234. package/src/evm/messages.ts +14 -14
  235. package/src/evm/offchain.ts +1 -1
  236. package/src/evm/types.ts +11 -0
  237. package/src/execution.ts +13 -9
  238. package/src/extra-args.ts +4 -3
  239. package/src/gas.ts +10 -3
  240. package/src/hasher/hasher.ts +2 -1
  241. package/src/hasher/merklemulti.ts +18 -8
  242. package/src/index.ts +15 -2
  243. package/src/offchain.ts +10 -14
  244. package/src/requests.ts +51 -53
  245. package/src/selectors.ts +23 -0
  246. package/src/solana/cleanup.ts +2 -4
  247. package/src/solana/exec.ts +13 -13
  248. package/src/solana/hasher.ts +9 -5
  249. package/src/solana/index.ts +126 -200
  250. package/src/solana/logs.ts +155 -0
  251. package/src/solana/offchain.ts +10 -7
  252. package/src/solana/patchBorsh.ts +3 -2
  253. package/src/solana/send.ts +14 -7
  254. package/src/solana/utils.ts +31 -17
  255. package/src/sui/discovery.ts +163 -0
  256. package/src/sui/events.ts +325 -0
  257. package/src/sui/hasher.ts +6 -5
  258. package/src/sui/index.ts +528 -80
  259. package/src/sui/manuallyExec/encoder.ts +88 -0
  260. package/src/sui/manuallyExec/index.ts +137 -0
  261. package/src/sui/objects.ts +358 -0
  262. package/src/ton/bindings/offramp.ts +96 -0
  263. package/src/ton/bindings/onramp.ts +72 -0
  264. package/src/ton/bindings/router.ts +65 -0
  265. package/src/ton/exec.ts +44 -0
  266. package/src/ton/hasher.ts +184 -0
  267. package/src/ton/index.ts +989 -0
  268. package/src/ton/logs.ts +157 -0
  269. package/src/ton/types.ts +143 -0
  270. package/src/ton/utils.ts +514 -0
  271. package/src/types.ts +6 -2
  272. package/src/utils.ts +58 -23
  273. package/tsconfig.json +2 -1
@@ -0,0 +1,11 @@
1
+ import type { TransactionRequest } from 'ethers'
2
+
3
+ import type { ChainFamily } from '../types.ts'
4
+
5
+ /**
6
+ * Type representing a set of unsigned EVM transactions
7
+ */
8
+ export type UnsignedEVMTx = {
9
+ family: typeof ChainFamily.EVM
10
+ transactions: Pick<TransactionRequest, 'from' | 'to' | 'data'>[]
11
+ }
package/src/execution.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import { memoize } from 'micro-memoize'
2
2
 
3
3
  import type { Chain, ChainStatic } from './chain.ts'
4
+ import {
5
+ CCIPMerkleRootMismatchError,
6
+ CCIPMessageNotInBatchError,
7
+ CCIPOffRampNotFoundError,
8
+ } from './errors/index.ts'
4
9
  import { Tree, getLeafHasher, proofFlagsToBits } from './hasher/index.ts'
5
10
  import {
6
11
  type CCIPCommit,
@@ -33,11 +38,12 @@ export function calculateManualExecProof<V extends CCIPVersion = CCIPVersion>(
33
38
  ): Omit<ExecutionReport, 'offchainTokenData' | 'message'> {
34
39
  const hasher = getLeafHasher(lane, ctx)
35
40
 
36
- const msgIdx = messagesInBatch.findIndex((message) => message.header.messageId === messageId)
41
+ const msgIdx = messagesInBatch.findIndex((message) => message.messageId === messageId)
37
42
  if (msgIdx < 0) {
38
- throw new Error(
39
- `Could not find ${messageId} in batch seqNums=[${Number(messagesInBatch[0].header.sequenceNumber)}..${Number(messagesInBatch[messagesInBatch.length - 1].header.sequenceNumber)}]`,
40
- )
43
+ throw new CCIPMessageNotInBatchError(messageId, {
44
+ min: messagesInBatch[0].sequenceNumber,
45
+ max: messagesInBatch[messagesInBatch.length - 1].sequenceNumber,
46
+ })
41
47
  }
42
48
 
43
49
  const leaves = messagesInBatch.map((message) => hasher(message))
@@ -45,9 +51,7 @@ export function calculateManualExecProof<V extends CCIPVersion = CCIPVersion>(
45
51
  // Create multi-merkle tree
46
52
  const tree = new Tree(leaves)
47
53
  if (merkleRoot && tree.root() !== merkleRoot) {
48
- throw new Error(
49
- `Merkle root created from send events doesn't match ReportAccepted merkle root: expected=${merkleRoot}, got=${tree.root()}`,
50
- )
54
+ throw new CCIPMerkleRootMismatchError(merkleRoot, tree.root())
51
55
  }
52
56
 
53
57
  // Generate proof from multi-merkle tree
@@ -89,7 +93,7 @@ export const discoverOffRamp = memoize(
89
93
  }
90
94
  }
91
95
  }
92
- throw new Error(`No matching offRamp found for "${onRamp}" on "${dest.network.name}"`)
96
+ throw new CCIPOffRampNotFoundError(onRamp, dest.network.name)
93
97
  },
94
98
  {
95
99
  transformKey: ([source, dest, onRamp]) =>
@@ -130,7 +134,7 @@ export async function* fetchExecutionReceipts(
130
134
  ...hints,
131
135
  })) {
132
136
  const receipt = (dest.constructor as ChainStatic).decodeReceipt(log)
133
- if (!receipt || receipt.messageId !== request.message.header.messageId) continue
137
+ if (!receipt || receipt.messageId !== request.message.messageId) continue
134
138
 
135
139
  const timestamp = log.tx?.timestamp ?? (await dest.getBlockTimestamp(log.blockNumber))
136
140
  yield { receipt, log, timestamp }
package/src/extra-args.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type BytesLike, id } from 'ethers'
2
2
 
3
+ import { CCIPChainFamilyUnsupportedError, CCIPExtraArgsParseError } from './errors/index.ts'
3
4
  import { supportedChains } from './supported-chains.ts'
4
5
  import { ChainFamily } from './types.ts'
5
6
 
@@ -67,7 +68,7 @@ export type ExtraArgs = EVMExtraArgsV1 | EVMExtraArgsV2 | SVMExtraArgsV1 | SuiEx
67
68
  **/
68
69
  export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily.EVM): string {
69
70
  const chain = supportedChains[from]
70
- if (!chain) throw new Error(`Unsupported chain family: ${from}`)
71
+ if (!chain) throw new CCIPChainFamilyUnsupportedError(from)
71
72
  return chain.encodeExtraArgs(args)
72
73
  }
73
74
 
@@ -90,7 +91,7 @@ export function decodeExtraArgs(
90
91
  let chains
91
92
  if (from) {
92
93
  const chain = supportedChains[from]
93
- if (!chain) throw new Error(`Unsupported chain family: ${from}`)
94
+ if (!chain) throw new CCIPChainFamilyUnsupportedError(from)
94
95
  chains = [chain]
95
96
  } else {
96
97
  chains = Object.values(supportedChains)
@@ -99,5 +100,5 @@ export function decodeExtraArgs(
99
100
  const decoded = chain.decodeExtraArgs(data)
100
101
  if (decoded) return decoded
101
102
  }
102
- throw new Error(`Could not parse extraArgs from "${from}"`)
103
+ throw new CCIPExtraArgsParseError(String(from ?? data))
103
104
  }
package/src/gas.ts CHANGED
@@ -14,6 +14,10 @@ import {
14
14
  import type { TypedContract } from 'ethers-abitype'
15
15
 
16
16
  import type { Chain } from './chain.ts'
17
+ import {
18
+ CCIPLegacyTokenPoolsUnsupportedError,
19
+ CCIPTokenDecimalsInsufficientError,
20
+ } from './errors/index.ts'
17
21
  import TokenABI from './evm/abi/BurnMintERC677Token.ts'
18
22
  import RouterABI from './evm/abi/Router.ts'
19
23
  import { defaultAbiCoder } from './evm/const.ts'
@@ -63,7 +67,7 @@ export async function estimateExecGasForRequest(
63
67
 
64
68
  const destTokenAmounts = await Promise.all(
65
69
  request.message.tokenAmounts.map(async (ta) => {
66
- if (!('destTokenAddress' in ta)) throw new Error('legacy <1.5 tokenPools not supported')
70
+ if (!('destTokenAddress' in ta)) throw new CCIPLegacyTokenPoolsUnsupportedError()
67
71
  const [{ decimals: sourceDecimals }, { decimals: destDecimals }] = await Promise.all([
68
72
  source
69
73
  .getTokenForTokenPool(ta.sourcePoolAddress)
@@ -73,8 +77,11 @@ export async function estimateExecGasForRequest(
73
77
  const destAmount =
74
78
  (ta.amount * 10n ** BigInt(destDecimals - sourceDecimals + 36)) / 10n ** 36n
75
79
  if (destAmount === 0n)
76
- throw new Error(
77
- `not enough decimals=${destDecimals} for token=${ta.destTokenAddress} on dest=${dest.network.name} to express ${formatUnits(ta.amount, sourceDecimals)}`,
80
+ throw new CCIPTokenDecimalsInsufficientError(
81
+ ta.destTokenAddress,
82
+ destDecimals,
83
+ dest.network.name,
84
+ formatUnits(ta.amount, sourceDecimals),
78
85
  )
79
86
  return { token: ta.destTokenAddress, amount: destAmount }
80
87
  }),
@@ -1,3 +1,4 @@
1
+ import { CCIPChainFamilyUnsupportedError } from '../errors/index.ts'
1
2
  import { supportedChains } from '../supported-chains.ts'
2
3
  import type { CCIPVersion, Lane, WithLogger } from '../types.ts'
3
4
  import { networkInfo } from '../utils.ts'
@@ -15,6 +16,6 @@ export function getLeafHasher<V extends CCIPVersion = CCIPVersion>(
15
16
  ): LeafHasher<V> {
16
17
  const destFamily = networkInfo(lane.destChainSelector).family
17
18
  const chain = supportedChains[destFamily]
18
- if (!chain) throw new Error(`Unsupported chain family: ${destFamily}`)
19
+ if (!chain) throw new CCIPChainFamilyUnsupportedError(destFamily)
19
20
  return chain.getDestLeafHasher(lane, ctx) as LeafHasher<V>
20
21
  }
@@ -1,5 +1,15 @@
1
1
  // For reference implementation, see https://github.com/smartcontractkit/ccip/blob/ccip-develop/core/services/ocr2/plugins/ccip/merklemulti/merkle_multi.go
2
2
  import { ZERO_HASH, hashInternal } from './common.ts'
3
+ import {
4
+ CCIPMerkleFlagsMismatchError,
5
+ CCIPMerkleHashesTooLargeError,
6
+ CCIPMerkleInternalError,
7
+ CCIPMerkleProofEmptyError,
8
+ CCIPMerkleProofFlagsMismatchError,
9
+ CCIPMerkleProofIncompleteError,
10
+ CCIPMerkleProofTooLargeError,
11
+ CCIPMerkleTreeEmptyError,
12
+ } from '../errors/index.ts'
3
13
 
4
14
  export const MAX_NUMBER_TREE_LEAVES = 256
5
15
 
@@ -146,7 +156,7 @@ export class Tree {
146
156
  */
147
157
  constructor(leafHashes: Hash[]) {
148
158
  if (leafHashes.length === 0) {
149
- throw new Error('Cannot construct a tree without leaves')
159
+ throw new CCIPMerkleTreeEmptyError()
150
160
  }
151
161
 
152
162
  // Initialize the first layer with leaf hashes.
@@ -227,21 +237,21 @@ export function verifyComputeRoot(leafHashes: Hash[], proof: Proof): Hash {
227
237
  const proofsLength = proof.hashes.length
228
238
 
229
239
  if (leavesLength === 0 && proofsLength === 0) {
230
- throw new Error('leaves and proofs are empty')
240
+ throw new CCIPMerkleProofEmptyError()
231
241
  }
232
242
 
233
243
  if (leavesLength > MAX_NUMBER_TREE_LEAVES + 1 || proofsLength > MAX_NUMBER_TREE_LEAVES + 1) {
234
- throw new Error(`leaves or proofs length beyond the limit of ${MAX_NUMBER_TREE_LEAVES}`)
244
+ throw new CCIPMerkleProofTooLargeError(MAX_NUMBER_TREE_LEAVES)
235
245
  }
236
246
 
237
247
  const totalHashes = leavesLength + proofsLength - 1
238
248
 
239
249
  if (totalHashes > MAX_NUMBER_TREE_LEAVES) {
240
- throw new Error(`total hashes length cannot be larger than ${MAX_NUMBER_TREE_LEAVES}`)
250
+ throw new CCIPMerkleHashesTooLargeError(totalHashes, MAX_NUMBER_TREE_LEAVES)
241
251
  }
242
252
 
243
253
  if (totalHashes !== proof.sourceFlags.length) {
244
- throw new Error(`hashes ${totalHashes} != sourceFlags ${proof.sourceFlags.length}`)
254
+ throw new CCIPMerkleFlagsMismatchError(totalHashes, proof.sourceFlags.length)
245
255
  }
246
256
 
247
257
  // If there are no hashes, return the first leaf hash.
@@ -253,7 +263,7 @@ export function verifyComputeRoot(leafHashes: Hash[], proof: Proof): Hash {
253
263
  const sourceProofCount = proof.countSourceFlags(false)
254
264
 
255
265
  if (sourceProofCount !== proofsLength) {
256
- throw new Error(`proof source flags ${sourceProofCount} != proof hashes ${proofsLength}`)
266
+ throw new CCIPMerkleProofFlagsMismatchError(sourceProofCount, proofsLength)
257
267
  }
258
268
 
259
269
  const hashes: Hash[] = new Array<Hash>(totalHashes)
@@ -293,7 +303,7 @@ export function verifyComputeRoot(leafHashes: Hash[], proof: Proof): Hash {
293
303
  }
294
304
 
295
305
  if (a === undefined || b === undefined) {
296
- throw new Error('a or b is undefined')
306
+ throw new CCIPMerkleInternalError('Hash operand is undefined')
297
307
  }
298
308
 
299
309
  // Compute the hash of a and b and store it in the hashes array.
@@ -302,7 +312,7 @@ export function verifyComputeRoot(leafHashes: Hash[], proof: Proof): Hash {
302
312
 
303
313
  // Check if all proofs were used during processing.
304
314
  if (hashPos !== totalHashes - 1 || leafPos !== leavesLength || proofPos !== proofsLength) {
305
- throw new Error('not all proofs used during processing')
315
+ throw new CCIPMerkleProofIncompleteError()
306
316
  }
307
317
 
308
318
  // Return the computed Merkle root hash.
package/src/index.ts CHANGED
@@ -37,15 +37,27 @@ export {
37
37
  CCIPVersion,
38
38
  ExecutionState,
39
39
  } from './types.ts'
40
- export { bigIntReplacer, bigIntReviver, decodeAddress, getDataBytes, networkInfo } from './utils.ts'
40
+ export {
41
+ bigIntReplacer,
42
+ bigIntReviver,
43
+ bytesToBuffer,
44
+ decodeAddress,
45
+ getDataBytes,
46
+ isSupportedTxHash,
47
+ networkInfo,
48
+ } from './utils.ts'
49
+
50
+ // errors
51
+ export * from './errors/index.ts'
41
52
 
42
53
  // chains
43
54
  import { AptosChain } from './aptos/index.ts'
44
55
  import { EVMChain } from './evm/index.ts'
45
56
  import { SolanaChain } from './solana/index.ts'
46
57
  import { SuiChain } from './sui/index.ts'
58
+ import { TONChain } from './ton/index.ts'
47
59
  import { ChainFamily } from './types.ts'
48
- export { AptosChain, ChainFamily, EVMChain, SolanaChain, SuiChain }
60
+ export { AptosChain, ChainFamily, EVMChain, SolanaChain, SuiChain, TONChain }
49
61
  // use `supportedChains` to override/register derived classes, if needed
50
62
  export { supportedChains } from './supported-chains.ts'
51
63
  // import `allSupportedChains` to get them all registered, in tree-shaken environments
@@ -54,4 +66,5 @@ export const allSupportedChains = {
54
66
  [ChainFamily.Solana]: SolanaChain,
55
67
  [ChainFamily.Aptos]: AptosChain,
56
68
  [ChainFamily.Sui]: SuiChain,
69
+ [ChainFamily.TON]: TONChain,
57
70
  }
package/src/offchain.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  import { keccak256 } from 'ethers'
2
2
 
3
+ import {
4
+ CCIPLbtcAttestationNotApprovedError,
5
+ CCIPLbtcAttestationNotFoundError,
6
+ CCIPUsdcAttestationError,
7
+ } from './errors/index.ts'
8
+
3
9
  const CIRCLE_API_URL = {
4
10
  mainnet: 'https://iris-api.circle.com/v1',
5
11
  testnet: 'https://iris-api-sandbox.circle.com/v1',
@@ -35,7 +41,7 @@ export async function getUsdcAttestation(message: string, isTestnet: boolean): P
35
41
  const res = await fetch(`${circleApiBaseUrl}/attestations/${msgHash}`)
36
42
  const json = (await res.json()) as CctpAttestationResponse
37
43
  if (!('status' in json) || json.status !== 'complete' || !json.attestation) {
38
- throw new Error('Could not fetch USDC attestation. Response: ' + JSON.stringify(json, null, 2))
44
+ throw new CCIPUsdcAttestationError(msgHash, json)
39
45
  }
40
46
  return json.attestation
41
47
  }
@@ -60,27 +66,17 @@ export async function getLbtcAttestation(
60
66
  })
61
67
  const response = (await res.json()) as LombardAttestationsResponse
62
68
  if (response == null || !('attestations' in response)) {
63
- throw new Error(
64
- 'Error while fetching LBTC attestation. Response: ' + JSON.stringify(response, null, 2),
65
- )
69
+ throw new CCIPLbtcAttestationNotFoundError(payloadHash, response)
66
70
  }
67
71
  const attestation = response.attestations.find((att) => att.message_hash === payloadHash)
68
72
  if (attestation == null) {
69
- throw new Error(
70
- 'Could not find requested LBTC attestation with hash:' +
71
- payloadHash +
72
- ' in response: ' +
73
- JSON.stringify(response, null, 2),
74
- )
73
+ throw new CCIPLbtcAttestationNotFoundError(payloadHash, response)
75
74
  }
76
75
  if (
77
76
  attestation.status !== 'NOTARIZATION_STATUS_SESSION_APPROVED' ||
78
77
  !('attestation' in attestation)
79
78
  ) {
80
- throw new Error(
81
- 'LBTC attestation is not approved or invalid. Response: ' +
82
- JSON.stringify(attestation, null, 2),
83
- )
79
+ throw new CCIPLbtcAttestationNotApprovedError(payloadHash, attestation)
84
80
  }
85
81
  return attestation
86
82
  }
package/src/requests.ts CHANGED
@@ -3,6 +3,15 @@ import type { PickDeep } from 'type-fest'
3
3
  import yaml from 'yaml'
4
4
 
5
5
  import type { Chain, ChainStatic, LogFilter } from './chain.ts'
6
+ import {
7
+ CCIPMessageBatchIncompleteError,
8
+ CCIPMessageDecodeError,
9
+ CCIPMessageIdNotFoundError,
10
+ CCIPMessageInvalidError,
11
+ CCIPMessageNotFoundInTxError,
12
+ CCIPNetworkFamilyUnsupportedError,
13
+ CCIPTokenNotInRegistryError,
14
+ } from './errors/index.ts'
6
15
  import type { EVMChain } from './evm/index.ts'
7
16
  import { decodeExtraArgs } from './extra-args.ts'
8
17
  import { supportedChains } from './supported-chains.ts'
@@ -14,18 +23,19 @@ import {
14
23
  type Log_,
15
24
  ChainFamily,
16
25
  } from './types.ts'
17
- import { convertKeysToCamelCase, decodeAddress, leToBigInt, networkInfo, util } from './utils.ts'
26
+ import { convertKeysToCamelCase, decodeAddress, leToBigInt, networkInfo } from './utils.ts'
18
27
 
19
28
  function decodeJsonMessage(data: Record<string, unknown>) {
20
- if (!data || typeof data != 'object') throw new Error(`invalid msg: ${util.inspect(data)}`)
29
+ if (!data || typeof data != 'object') throw new CCIPMessageInvalidError(data)
21
30
  if (data.message) data = data.message as Record<string, unknown>
31
+ if (data.header) {
32
+ Object.assign(data, data.header)
33
+ delete data.header
34
+ }
22
35
  let data_ = data as Record<string, unknown> & {
23
- header: {
24
- dest_chain_selector?: string
25
- destChainSelector?: string
26
- sourceChainSelector?: string
27
- source_chain_selector?: string
28
- }
36
+ dest_chain_selector?: string
37
+ destChainSelector?: string
38
+ source_chain_selector?: string
29
39
  sourceChainSelector?: string
30
40
  extraArgs?: string
31
41
  tokenAmounts: {
@@ -33,29 +43,17 @@ function decodeJsonMessage(data: Record<string, unknown>) {
33
43
  destGasAmount?: bigint
34
44
  }[]
35
45
  }
36
- const sourceChainSelector =
37
- data_.header?.sourceChainSelector ??
38
- data_.header?.source_chain_selector ??
39
- data_.sourceChainSelector
40
- if (!sourceChainSelector) throw new Error(`invalid msg: ${util.inspect(data)}`)
46
+ const sourceChainSelector = data_.source_chain_selector ?? data_.sourceChainSelector
47
+ if (!sourceChainSelector) throw new CCIPMessageInvalidError(data)
41
48
  const sourceNetwork = networkInfo(sourceChainSelector)
42
- if (!data_.header) {
43
- const header = {
44
- sourceChainSelector: data_.sourceChainSelector,
45
- messageId: data_.messageId,
46
- nonce: data_.nonce,
47
- sequenceNumber: data_.sequenceNumber,
48
- }
49
- data_.header = header
50
- }
51
49
 
52
- const destChainSelector = data_.header.dest_chain_selector ?? data_.header.destChainSelector
50
+ const destChainSelector = data_.dest_chain_selector ?? data_.destChainSelector
53
51
  if (destChainSelector) {
54
52
  const destFamily = networkInfo(destChainSelector).family
55
53
  data_ = convertKeysToCamelCase(data_, (v, k) =>
56
54
  typeof v === 'string' && v.match(/^\d+$/)
57
55
  ? BigInt(v)
58
- : k === 'receiver' || k === 'destTokenAddress'
56
+ : k === 'receiver' || k === 'destTokenAddress' || k === 'tokenReceiver'
59
57
  ? decodeAddress(v as string, destFamily)
60
58
  : v,
61
59
  ) as typeof data_
@@ -108,7 +106,7 @@ export function decodeMessage(data: string | Uint8Array | Record<string, unknown
108
106
  // continue
109
107
  }
110
108
  }
111
- throw new Error('Failed to decode message')
109
+ throw new CCIPMessageDecodeError()
112
110
  }
113
111
 
114
112
  /**
@@ -128,23 +126,23 @@ export async function fetchCCIPRequestsInTx(
128
126
  let lane
129
127
  const message = (source.constructor as ChainStatic).decodeMessage(log)
130
128
  if (!message) continue
131
- if ('destChainSelector' in message.header) {
129
+ if ('destChainSelector' in message) {
132
130
  const [_, version] = await source.typeAndVersion(log.address)
133
131
  lane = {
134
- sourceChainSelector: message.header.sourceChainSelector,
135
- destChainSelector: message.header.destChainSelector,
132
+ sourceChainSelector: message.sourceChainSelector,
133
+ destChainSelector: message.destChainSelector,
136
134
  onRamp: log.address,
137
135
  version: version as CCIPVersion,
138
136
  }
139
137
  } else if (source.network.family !== ChainFamily.EVM) {
140
- throw new Error(`Unsupported network family: ${source.network.family}`)
138
+ throw new CCIPNetworkFamilyUnsupportedError(source.network.family)
141
139
  } else {
142
140
  lane = await (source as EVMChain).getLaneForOnRamp(log.address)
143
141
  }
144
142
  requests.push({ lane, message, log, tx })
145
143
  }
146
144
  if (!requests.length) {
147
- throw new Error(`Could not find any CCIPSendRequested message in tx: ${txHash}`)
145
+ throw new CCIPMessageNotFoundInTxError(txHash)
148
146
  }
149
147
 
150
148
  return requests
@@ -168,10 +166,10 @@ export async function fetchCCIPRequestById(
168
166
  ...hints,
169
167
  })) {
170
168
  const message = (source.constructor as ChainStatic).decodeMessage(log)
171
- if (message?.header.messageId !== messageId) continue
169
+ if (message?.messageId !== messageId) continue
172
170
  let destChainSelector, version
173
- if ('destChainSelector' in message.header) {
174
- destChainSelector = message.header.destChainSelector
171
+ if ('destChainSelector' in message) {
172
+ destChainSelector = message.destChainSelector
175
173
  ;[, version] = await source.typeAndVersion(log.address)
176
174
  } else {
177
175
  ;({ destChainSelector, version } = await (source as EVMChain).getLaneForOnRamp(log.address))
@@ -179,7 +177,7 @@ export async function fetchCCIPRequestById(
179
177
  const tx = log.tx ?? (await source.getTransaction(log.transactionHash))
180
178
  return {
181
179
  lane: {
182
- sourceChainSelector: source.network.chainSelector,
180
+ sourceChainSelector: message.sourceChainSelector,
183
181
  destChainSelector,
184
182
  onRamp: log.address,
185
183
  version: version as CCIPVersion,
@@ -189,7 +187,7 @@ export async function fetchCCIPRequestById(
189
187
  tx,
190
188
  }
191
189
  }
192
- throw new Error('Could not find a CCIPSendRequested message with messageId: ' + messageId)
190
+ throw new CCIPMessageIdNotFoundError(messageId)
193
191
  }
194
192
 
195
193
  // Number of blocks to expand the search window for logs
@@ -207,7 +205,7 @@ export async function fetchAllMessagesInBatch<
207
205
  C extends Chain,
208
206
  R extends PickDeep<
209
207
  CCIPRequest,
210
- 'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.header.sequenceNumber'
208
+ 'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
211
209
  >,
212
210
  >(
213
211
  source: C,
@@ -223,13 +221,13 @@ export async function fetchAllMessagesInBatch<
223
221
  address: request.log.address,
224
222
  ...opts,
225
223
  }
226
- if (request.message.header.sequenceNumber === maxSeqNr) filter.endBlock = request.log.blockNumber
224
+ if (request.message.sequenceNumber === maxSeqNr) filter.endBlock = request.log.blockNumber
227
225
  else
228
226
  // start proportionally before send request block, including case when seqNum==min => startBlock
229
227
  filter.startBlock =
230
228
  request.log.blockNumber -
231
229
  Math.ceil(
232
- (Number(request.message.header.sequenceNumber - minSeqNr) / Number(maxSeqNr - minSeqNr)) *
230
+ (Number(request.message.sequenceNumber - minSeqNr) / Number(maxSeqNr - minSeqNr)) *
233
231
  filter.page,
234
232
  )
235
233
 
@@ -243,15 +241,15 @@ export async function fetchAllMessagesInBatch<
243
241
  const message = (source.constructor as ChainStatic).decodeMessage(log)
244
242
  if (
245
243
  !message ||
246
- ('destChainSelector' in message.header &&
247
- message.header.destChainSelector !== request.lane.destChainSelector)
244
+ ('destChainSelector' in message &&
245
+ message.destChainSelector !== request.lane.destChainSelector)
248
246
  )
249
247
  continue
250
- if (message.header.sequenceNumber < minSeqNr) continue
248
+ if (message.sequenceNumber < minSeqNr) continue
251
249
  messages.push(message)
252
- if (message.header.sequenceNumber >= maxSeqNr) break
250
+ if (message.sequenceNumber >= maxSeqNr) break
253
251
  }
254
- if (messages.length && messages[0].header.sequenceNumber > minSeqNr) {
252
+ if (messages.length && messages[0].sequenceNumber > minSeqNr) {
255
253
  // still work to be done backwards
256
254
  delete filter['startBlock']
257
255
  filter['endBlock'] = backwardsEndBlock
@@ -264,18 +262,19 @@ export async function fetchAllMessagesInBatch<
264
262
  const message = (source.constructor as ChainStatic).decodeMessage(log)
265
263
  if (
266
264
  !message ||
267
- ('destChainSelector' in message.header &&
268
- message.header.destChainSelector !== request.lane.destChainSelector)
265
+ ('destChainSelector' in message &&
266
+ message.destChainSelector !== request.lane.destChainSelector)
269
267
  )
270
268
  continue
271
269
  messages.unshift(message)
272
- if (message.header.sequenceNumber <= minSeqNr) break
270
+ if (message.sequenceNumber <= minSeqNr) break
273
271
  }
274
272
  }
275
273
 
276
274
  if (messages.length != Number(maxSeqNr - minSeqNr) + 1) {
277
- throw new Error(
278
- `Could not find all expected request events: from=${request.log.blockNumber}, wanted=[${Number(minSeqNr)}..${Number(maxSeqNr)}:${Number(maxSeqNr - minSeqNr) + 1}], got=[${messages.map((e) => Number(e.header.sequenceNumber)).join(',')}]`,
275
+ throw new CCIPMessageBatchIncompleteError(
276
+ { min: minSeqNr, max: maxSeqNr },
277
+ messages.map((e) => e.sequenceNumber),
279
278
  )
280
279
  }
281
280
  return messages
@@ -302,13 +301,13 @@ export async function* fetchRequestsForSender(
302
301
  const message = (source.constructor as ChainStatic).decodeMessage(log)
303
302
  if (message?.sender !== sender) continue
304
303
  let destChainSelector, version
305
- if ('destChainSelector' in message.header) {
306
- destChainSelector = message.header.destChainSelector
304
+ if ('destChainSelector' in message) {
305
+ destChainSelector = message.destChainSelector
307
306
  ;[, version] = await source.typeAndVersion(log.address)
308
307
  } else if (source.network.family === ChainFamily.EVM) {
309
308
  ;({ destChainSelector, version } = await (source as EVMChain).getLaneForOnRamp(log.address))
310
309
  } else {
311
- throw new Error(`Unsupported network family: ${source.network.family}`)
310
+ throw new CCIPNetworkFamilyUnsupportedError(source.network.family)
312
311
  }
313
312
  yield {
314
313
  lane: {
@@ -344,8 +343,7 @@ export async function sourceToDestTokenAmounts<S extends { token: string }>(
344
343
  tokenAdminRegistry,
345
344
  token,
346
345
  )
347
- if (!sourcePoolAddress)
348
- throw new Error(`Token=${token} not found in registry=${tokenAdminRegistry}`)
346
+ if (!sourcePoolAddress) throw new CCIPTokenNotInRegistryError(token, tokenAdminRegistry)
349
347
  const remotes = await source.getTokenPoolRemotes(sourcePoolAddress, destChainSelector)
350
348
  return {
351
349
  ...rest,
package/src/selectors.ts CHANGED
@@ -1335,6 +1335,29 @@ const selectors: Selectors = {
1335
1335
  family: 'sui',
1336
1336
  },
1337
1337
  // end:generate
1338
+
1339
+ // generate:
1340
+ // fetch('https://github.com/smartcontractkit/chain-selectors/raw/main/selectors_ton.yml')
1341
+ // .then((res) => res.text())
1342
+ // .then((body) => require('yaml').parse(body, { intAsBigInt: true }).selectors)
1343
+ // .then((obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, { ...v, family: 'ton' }])))
1344
+ // .then((obj) => [...require('util').inspect(obj).split('\n').slice(1, -1), ','])
1345
+ '-239': {
1346
+ name: 'ton-mainnet',
1347
+ selector: 16448340667252469081n,
1348
+ family: 'ton',
1349
+ },
1350
+ '-3': {
1351
+ name: 'ton-testnet',
1352
+ selector: 1399300952838017768n,
1353
+ family: 'ton',
1354
+ },
1355
+ '-217': {
1356
+ name: 'ton-localnet',
1357
+ selector: 13879075125137744094n,
1358
+ family: 'ton',
1359
+ },
1360
+ // end:generate
1338
1361
  }
1339
1362
 
1340
1363
  export default selectors
@@ -21,15 +21,13 @@ import type { WithLogger } from '../types.ts'
21
21
  * Clean up and recycle buffers and Address Lookup Tables owned by wallet.
22
22
  * @param ctx - Context object containing the Solana connection instance and logger.
23
23
  * @param wallet - Wallet instance to sign txs.
24
- * @param getLogs - SolanaChain-compatible getLogs function (to scan for Buffers and ALTs).
25
24
  * @param opts - Optional parameters. Set `waitDeactivation` to wait for lookup table deactivation
26
25
  * cool down period (513 slots) to pass before closing; by default, we deactivate (if needed)
27
26
  * and leave close to be done in the future.
28
27
  */
29
28
  export async function cleanUpBuffers(
30
- ctx: { connection: Connection } & WithLogger,
29
+ ctx: { connection: Connection; getLogs: SolanaChain['getLogs'] } & WithLogger,
31
30
  wallet: Wallet,
32
- getLogs: SolanaChain['getLogs'],
33
31
  opts?: { waitDeactivation?: boolean },
34
32
  ): Promise<void> {
35
33
  const { connection, logger = console } = ctx
@@ -103,7 +101,7 @@ export async function cleanUpBuffers(
103
101
  }
104
102
 
105
103
  let alreadyClosed = 0
106
- for await (const log of getLogs({
104
+ for await (const log of ctx.getLogs({
107
105
  address: wallet.publicKey.toBase58(),
108
106
  topics: [
109
107
  'Instruction: BufferExecutionReport',