@chainlink/ccip-sdk 0.0.0 → 0.90.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 (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -0
  3. package/dist/aptos/exec.d.ts +18 -0
  4. package/dist/aptos/exec.d.ts.map +1 -0
  5. package/dist/aptos/exec.js +55 -0
  6. package/dist/aptos/exec.js.map +1 -0
  7. package/dist/aptos/hasher.d.ts +11 -0
  8. package/dist/aptos/hasher.d.ts.map +1 -0
  9. package/dist/aptos/hasher.js +62 -0
  10. package/dist/aptos/hasher.js.map +1 -0
  11. package/dist/aptos/index.d.ts +92 -0
  12. package/dist/aptos/index.d.ts.map +1 -0
  13. package/dist/aptos/index.js +482 -0
  14. package/dist/aptos/index.js.map +1 -0
  15. package/dist/aptos/logs.d.ts +9 -0
  16. package/dist/aptos/logs.d.ts.map +1 -0
  17. package/dist/aptos/logs.js +167 -0
  18. package/dist/aptos/logs.js.map +1 -0
  19. package/dist/aptos/send.d.ts +11 -0
  20. package/dist/aptos/send.d.ts.map +1 -0
  21. package/dist/aptos/send.js +78 -0
  22. package/dist/aptos/send.js.map +1 -0
  23. package/dist/aptos/token.d.ts +4 -0
  24. package/dist/aptos/token.d.ts.map +1 -0
  25. package/dist/aptos/token.js +134 -0
  26. package/dist/aptos/token.js.map +1 -0
  27. package/dist/aptos/types.d.ts +78 -0
  28. package/dist/aptos/types.d.ts.map +1 -0
  29. package/dist/aptos/types.js +60 -0
  30. package/dist/aptos/types.js.map +1 -0
  31. package/dist/aptos/utils.d.ts +12 -0
  32. package/dist/aptos/utils.d.ts.map +1 -0
  33. package/dist/aptos/utils.js +15 -0
  34. package/dist/aptos/utils.js.map +1 -0
  35. package/dist/chain.d.ts +344 -0
  36. package/dist/chain.d.ts.map +1 -0
  37. package/dist/chain.js +41 -0
  38. package/dist/chain.js.map +1 -0
  39. package/dist/commits.d.ts +25 -0
  40. package/dist/commits.d.ts.map +1 -0
  41. package/dist/commits.js +29 -0
  42. package/dist/commits.js.map +1 -0
  43. package/dist/evm/abi/BurnMintERC677Token.d.ts +602 -0
  44. package/dist/evm/abi/BurnMintERC677Token.d.ts.map +1 -0
  45. package/dist/evm/abi/BurnMintERC677Token.js +488 -0
  46. package/dist/evm/abi/BurnMintERC677Token.js.map +1 -0
  47. package/dist/evm/abi/CommitStore_1_2.d.ts +688 -0
  48. package/dist/evm/abi/CommitStore_1_2.d.ts.map +1 -0
  49. package/dist/evm/abi/CommitStore_1_2.js +638 -0
  50. package/dist/evm/abi/CommitStore_1_2.js.map +1 -0
  51. package/dist/evm/abi/CommitStore_1_5.d.ts +708 -0
  52. package/dist/evm/abi/CommitStore_1_5.d.ts.map +1 -0
  53. package/dist/evm/abi/CommitStore_1_5.js +675 -0
  54. package/dist/evm/abi/CommitStore_1_5.js.map +1 -0
  55. package/dist/evm/abi/FeeQuoter_1_6.d.ts +1770 -0
  56. package/dist/evm/abi/FeeQuoter_1_6.d.ts.map +1 -0
  57. package/dist/evm/abi/FeeQuoter_1_6.js +1904 -0
  58. package/dist/evm/abi/FeeQuoter_1_6.js.map +1 -0
  59. package/dist/evm/abi/LockReleaseTokenPool_1_5.d.ts +1116 -0
  60. package/dist/evm/abi/LockReleaseTokenPool_1_5.d.ts.map +1 -0
  61. package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1096 -0
  62. package/dist/evm/abi/LockReleaseTokenPool_1_5.js.map +1 -0
  63. package/dist/evm/abi/LockReleaseTokenPool_1_5_1.d.ts +1306 -0
  64. package/dist/evm/abi/LockReleaseTokenPool_1_5_1.d.ts.map +1 -0
  65. package/dist/evm/abi/LockReleaseTokenPool_1_5_1.js +1278 -0
  66. package/dist/evm/abi/LockReleaseTokenPool_1_5_1.js.map +1 -0
  67. package/dist/evm/abi/LockReleaseTokenPool_1_6_1.d.ts +1290 -0
  68. package/dist/evm/abi/LockReleaseTokenPool_1_6_1.d.ts.map +1 -0
  69. package/dist/evm/abi/LockReleaseTokenPool_1_6_1.js +1288 -0
  70. package/dist/evm/abi/LockReleaseTokenPool_1_6_1.js.map +1 -0
  71. package/dist/evm/abi/OffRamp_1_2.d.ts +1217 -0
  72. package/dist/evm/abi/OffRamp_1_2.d.ts.map +1 -0
  73. package/dist/evm/abi/OffRamp_1_2.js +1204 -0
  74. package/dist/evm/abi/OffRamp_1_2.js.map +1 -0
  75. package/dist/evm/abi/OffRamp_1_5.d.ts +1271 -0
  76. package/dist/evm/abi/OffRamp_1_5.d.ts.map +1 -0
  77. package/dist/evm/abi/OffRamp_1_5.js +1273 -0
  78. package/dist/evm/abi/OffRamp_1_5.js.map +1 -0
  79. package/dist/evm/abi/OffRamp_1_6.d.ts +1472 -0
  80. package/dist/evm/abi/OffRamp_1_6.d.ts.map +1 -0
  81. package/dist/evm/abi/OffRamp_1_6.js +1529 -0
  82. package/dist/evm/abi/OffRamp_1_6.js.map +1 -0
  83. package/dist/evm/abi/OnRamp_1_2.d.ts +1391 -0
  84. package/dist/evm/abi/OnRamp_1_2.d.ts.map +1 -0
  85. package/dist/evm/abi/OnRamp_1_2.js +1343 -0
  86. package/dist/evm/abi/OnRamp_1_2.js.map +1 -0
  87. package/dist/evm/abi/OnRamp_1_5.d.ts +1443 -0
  88. package/dist/evm/abi/OnRamp_1_5.d.ts.map +1 -0
  89. package/dist/evm/abi/OnRamp_1_5.js +1427 -0
  90. package/dist/evm/abi/OnRamp_1_5.js.map +1 -0
  91. package/dist/evm/abi/OnRamp_1_6.d.ts +796 -0
  92. package/dist/evm/abi/OnRamp_1_6.d.ts.map +1 -0
  93. package/dist/evm/abi/OnRamp_1_6.js +880 -0
  94. package/dist/evm/abi/OnRamp_1_6.js.map +1 -0
  95. package/dist/evm/abi/Router.d.ts +541 -0
  96. package/dist/evm/abi/Router.d.ts.map +1 -0
  97. package/dist/evm/abi/Router.js +508 -0
  98. package/dist/evm/abi/Router.js.map +1 -0
  99. package/dist/evm/abi/TokenAdminRegistry_1_5.d.ts +373 -0
  100. package/dist/evm/abi/TokenAdminRegistry_1_5.d.ts.map +1 -0
  101. package/dist/evm/abi/TokenAdminRegistry_1_5.js +333 -0
  102. package/dist/evm/abi/TokenAdminRegistry_1_5.js.map +1 -0
  103. package/dist/evm/const.d.ts +27 -0
  104. package/dist/evm/const.d.ts.map +1 -0
  105. package/dist/evm/const.js +63 -0
  106. package/dist/evm/const.js.map +1 -0
  107. package/dist/evm/errors.d.ts +36 -0
  108. package/dist/evm/errors.d.ts.map +1 -0
  109. package/dist/evm/errors.js +192 -0
  110. package/dist/evm/errors.js.map +1 -0
  111. package/dist/evm/hasher.d.ts +5 -0
  112. package/dist/evm/hasher.d.ts.map +1 -0
  113. package/dist/evm/hasher.js +116 -0
  114. package/dist/evm/hasher.js.map +1 -0
  115. package/dist/evm/index.d.ts +121 -0
  116. package/dist/evm/index.d.ts.map +1 -0
  117. package/dist/evm/index.js +904 -0
  118. package/dist/evm/index.js.map +1 -0
  119. package/dist/evm/messages.d.ts +35 -0
  120. package/dist/evm/messages.d.ts.map +1 -0
  121. package/dist/evm/messages.js +11 -0
  122. package/dist/evm/messages.js.map +1 -0
  123. package/dist/evm/offchain.d.ts +16 -0
  124. package/dist/evm/offchain.d.ts.map +1 -0
  125. package/dist/evm/offchain.js +142 -0
  126. package/dist/evm/offchain.js.map +1 -0
  127. package/dist/execution.d.ts +80 -0
  128. package/dist/execution.d.ts.map +1 -0
  129. package/dist/execution.js +91 -0
  130. package/dist/execution.js.map +1 -0
  131. package/dist/extra-args.d.ts +45 -0
  132. package/dist/extra-args.d.ts.map +1 -0
  133. package/dist/extra-args.js +44 -0
  134. package/dist/extra-args.js.map +1 -0
  135. package/dist/gas.d.ts +27 -0
  136. package/dist/gas.d.ts.map +1 -0
  137. package/dist/gas.js +80 -0
  138. package/dist/gas.js.map +1 -0
  139. package/dist/hasher/common.d.ts +12 -0
  140. package/dist/hasher/common.d.ts.map +1 -0
  141. package/dist/hasher/common.js +19 -0
  142. package/dist/hasher/common.js.map +1 -0
  143. package/dist/hasher/hasher.d.ts +4 -0
  144. package/dist/hasher/hasher.d.ts.map +1 -0
  145. package/dist/hasher/hasher.js +11 -0
  146. package/dist/hasher/hasher.js.map +1 -0
  147. package/dist/hasher/index.d.ts +4 -0
  148. package/dist/hasher/index.d.ts.map +1 -0
  149. package/dist/hasher/index.js +4 -0
  150. package/dist/hasher/index.js.map +1 -0
  151. package/dist/hasher/merklemulti.d.ts +58 -0
  152. package/dist/hasher/merklemulti.d.ts.map +1 -0
  153. package/dist/hasher/merklemulti.js +257 -0
  154. package/dist/hasher/merklemulti.js.map +1 -0
  155. package/dist/index.d.ts +13 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +13 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/offchain.d.ts +20 -0
  160. package/dist/offchain.d.ts.map +1 -0
  161. package/dist/offchain.js +59 -0
  162. package/dist/offchain.js.map +1 -0
  163. package/dist/requests.d.ts +48 -0
  164. package/dist/requests.d.ts.map +1 -0
  165. package/dist/requests.js +286 -0
  166. package/dist/requests.js.map +1 -0
  167. package/dist/selectors.d.ts +9 -0
  168. package/dist/selectors.d.ts.map +1 -0
  169. package/dist/selectors.js +1330 -0
  170. package/dist/selectors.js.map +1 -0
  171. package/dist/solana/cleanup.d.ts +15 -0
  172. package/dist/solana/cleanup.d.ts.map +1 -0
  173. package/dist/solana/cleanup.js +159 -0
  174. package/dist/solana/cleanup.js.map +1 -0
  175. package/dist/solana/exec.d.ts +15 -0
  176. package/dist/solana/exec.d.ts.map +1 -0
  177. package/dist/solana/exec.js +417 -0
  178. package/dist/solana/exec.js.map +1 -0
  179. package/dist/solana/hasher.d.ts +4 -0
  180. package/dist/solana/hasher.d.ts.map +1 -0
  181. package/dist/solana/hasher.js +81 -0
  182. package/dist/solana/hasher.js.map +1 -0
  183. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts +866 -0
  184. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts.map +1 -0
  185. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js +866 -0
  186. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js.map +1 -0
  187. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts +949 -0
  188. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts.map +1 -0
  189. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js +949 -0
  190. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js.map +1 -0
  191. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts +1374 -0
  192. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts.map +1 -0
  193. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js +1374 -0
  194. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js.map +1 -0
  195. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts +104 -0
  196. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts.map +1 -0
  197. package/dist/solana/idl/1.6.0/CCIP_COMMON.js +104 -0
  198. package/dist/solana/idl/1.6.0/CCIP_COMMON.js.map +1 -0
  199. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts +2746 -0
  200. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts.map +1 -0
  201. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js +2746 -0
  202. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js.map +1 -0
  203. package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts +2332 -0
  204. package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts.map +1 -0
  205. package/dist/solana/idl/1.6.0/CCIP_ROUTER.js +2332 -0
  206. package/dist/solana/idl/1.6.0/CCIP_ROUTER.js.map +1 -0
  207. package/dist/solana/index.d.ts +205 -0
  208. package/dist/solana/index.d.ts.map +1 -0
  209. package/dist/solana/index.js +1085 -0
  210. package/dist/solana/index.js.map +1 -0
  211. package/dist/solana/offchain.d.ts +31 -0
  212. package/dist/solana/offchain.d.ts.map +1 -0
  213. package/dist/solana/offchain.js +152 -0
  214. package/dist/solana/offchain.js.map +1 -0
  215. package/dist/solana/patchBorsh.d.ts +2 -0
  216. package/dist/solana/patchBorsh.d.ts.map +1 -0
  217. package/dist/solana/patchBorsh.js +60 -0
  218. package/dist/solana/patchBorsh.js.map +1 -0
  219. package/dist/solana/send.d.ts +14 -0
  220. package/dist/solana/send.d.ts.map +1 -0
  221. package/dist/solana/send.js +272 -0
  222. package/dist/solana/send.js.map +1 -0
  223. package/dist/solana/types.d.ts +4 -0
  224. package/dist/solana/types.d.ts.map +1 -0
  225. package/dist/solana/types.js +2 -0
  226. package/dist/solana/types.js.map +1 -0
  227. package/dist/solana/utils.d.ts +58 -0
  228. package/dist/solana/utils.d.ts.map +1 -0
  229. package/dist/solana/utils.js +211 -0
  230. package/dist/solana/utils.js.map +1 -0
  231. package/dist/sui/hasher.d.ts +12 -0
  232. package/dist/sui/hasher.d.ts.map +1 -0
  233. package/dist/sui/hasher.js +63 -0
  234. package/dist/sui/hasher.js.map +1 -0
  235. package/dist/sui/index.d.ts +72 -0
  236. package/dist/sui/index.d.ts.map +1 -0
  237. package/dist/sui/index.js +128 -0
  238. package/dist/sui/index.js.map +1 -0
  239. package/dist/sui/types.d.ts +17 -0
  240. package/dist/sui/types.d.ts.map +1 -0
  241. package/dist/sui/types.js +17 -0
  242. package/dist/sui/types.js.map +1 -0
  243. package/dist/supported-chains.d.ts +5 -0
  244. package/dist/supported-chains.d.ts.map +1 -0
  245. package/dist/supported-chains.js +3 -0
  246. package/dist/supported-chains.js.map +1 -0
  247. package/dist/types.d.ts +118 -0
  248. package/dist/types.d.ts.map +1 -0
  249. package/dist/types.js +11 -0
  250. package/dist/types.js.map +1 -0
  251. package/dist/utils.d.ts +117 -0
  252. package/dist/utils.d.ts.map +1 -0
  253. package/dist/utils.js +336 -0
  254. package/dist/utils.js.map +1 -0
  255. package/package.json +66 -8
  256. package/src/aptos/exec.ts +69 -0
  257. package/src/aptos/hasher.ts +92 -0
  258. package/src/aptos/index.ts +660 -0
  259. package/src/aptos/logs.ts +210 -0
  260. package/src/aptos/send.ts +120 -0
  261. package/src/aptos/token.ts +150 -0
  262. package/src/aptos/types.ts +85 -0
  263. package/src/aptos/utils.ts +24 -0
  264. package/src/chain.ts +398 -0
  265. package/src/commits.ts +44 -0
  266. package/src/evm/abi/BurnMintERC677Token.ts +487 -0
  267. package/src/evm/abi/CommitStore_1_2.ts +637 -0
  268. package/src/evm/abi/CommitStore_1_5.ts +674 -0
  269. package/src/evm/abi/FeeQuoter_1_6.ts +1903 -0
  270. package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1095 -0
  271. package/src/evm/abi/LockReleaseTokenPool_1_5_1.ts +1277 -0
  272. package/src/evm/abi/LockReleaseTokenPool_1_6_1.ts +1287 -0
  273. package/src/evm/abi/OffRamp_1_2.ts +1203 -0
  274. package/src/evm/abi/OffRamp_1_5.ts +1272 -0
  275. package/src/evm/abi/OffRamp_1_6.ts +1528 -0
  276. package/src/evm/abi/OnRamp_1_2.ts +1342 -0
  277. package/src/evm/abi/OnRamp_1_5.ts +1426 -0
  278. package/src/evm/abi/OnRamp_1_6.ts +879 -0
  279. package/src/evm/abi/Router.ts +507 -0
  280. package/src/evm/abi/TokenAdminRegistry_1_5.ts +332 -0
  281. package/src/evm/const.ts +69 -0
  282. package/src/evm/errors.ts +212 -0
  283. package/src/evm/hasher.ts +166 -0
  284. package/src/evm/index.ts +1262 -0
  285. package/src/evm/messages.ts +73 -0
  286. package/src/evm/offchain.ts +189 -0
  287. package/src/execution.ts +131 -0
  288. package/src/extra-args.ts +71 -0
  289. package/src/gas.ts +135 -0
  290. package/src/hasher/common.ts +23 -0
  291. package/src/hasher/hasher.ts +12 -0
  292. package/src/hasher/index.ts +3 -0
  293. package/src/hasher/merklemulti.ts +309 -0
  294. package/src/index.ts +51 -0
  295. package/src/offchain.ts +86 -0
  296. package/src/requests.ts +339 -0
  297. package/src/selectors.ts +1340 -0
  298. package/src/solana/cleanup.ts +216 -0
  299. package/src/solana/exec.ts +645 -0
  300. package/src/solana/hasher.ts +104 -0
  301. package/src/solana/idl/1.6.0/BASE_TOKEN_POOL.ts +1734 -0
  302. package/src/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.ts +1900 -0
  303. package/src/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts +2750 -0
  304. package/src/solana/idl/1.6.0/CCIP_COMMON.ts +210 -0
  305. package/src/solana/idl/1.6.0/CCIP_OFFRAMP.ts +5494 -0
  306. package/src/solana/idl/1.6.0/CCIP_ROUTER.ts +4671 -0
  307. package/src/solana/index.ts +1454 -0
  308. package/src/solana/offchain.ts +209 -0
  309. package/src/solana/patchBorsh.ts +67 -0
  310. package/src/solana/send.ts +436 -0
  311. package/src/solana/types.ts +6 -0
  312. package/src/solana/utils.ts +272 -0
  313. package/src/sui/hasher.ts +90 -0
  314. package/src/sui/index.ts +198 -0
  315. package/src/sui/types.ts +22 -0
  316. package/src/supported-chains.ts +4 -0
  317. package/src/types.ts +153 -0
  318. package/src/utils.ts +405 -0
  319. package/tsconfig.json +18 -0
@@ -0,0 +1,1262 @@
1
+ import util from 'util'
2
+
3
+ import { parseAbi } from 'abitype'
4
+ import {
5
+ type BytesLike,
6
+ type JsonRpcApiProvider,
7
+ type Log,
8
+ type Provider,
9
+ type Signer,
10
+ type TransactionReceipt,
11
+ AbstractSigner,
12
+ BaseWallet,
13
+ Contract,
14
+ JsonRpcProvider,
15
+ Result,
16
+ SigningKey,
17
+ WebSocketProvider,
18
+ ZeroAddress,
19
+ concat,
20
+ dataSlice,
21
+ encodeBase58,
22
+ getAddress,
23
+ getBytes,
24
+ hexlify,
25
+ isBytesLike,
26
+ isHexString,
27
+ toBigInt,
28
+ zeroPadValue,
29
+ } from 'ethers'
30
+ import type { TypedContract } from 'ethers-abitype'
31
+ import moize, { type Key } from 'moize'
32
+
33
+ import {
34
+ type ChainTransaction,
35
+ type LogFilter,
36
+ type TokenPoolRemote,
37
+ Chain,
38
+ ChainFamily,
39
+ } from '../chain.ts'
40
+ import {
41
+ type EVMExtraArgsV1,
42
+ type EVMExtraArgsV2,
43
+ type ExtraArgs,
44
+ type SVMExtraArgsV1,
45
+ type SuiExtraArgsV1,
46
+ EVMExtraArgsV1Tag,
47
+ EVMExtraArgsV2Tag,
48
+ SVMExtraArgsV1Tag,
49
+ SuiExtraArgsV1Tag,
50
+ } from '../extra-args.ts'
51
+ import type { LeafHasher } from '../hasher/common.ts'
52
+ import { supportedChains } from '../supported-chains.ts'
53
+ import {
54
+ type AnyMessage,
55
+ type CCIPMessage,
56
+ type CCIPRequest,
57
+ type CommitReport,
58
+ type ExecutionReceipt,
59
+ type ExecutionReport,
60
+ type ExecutionState,
61
+ type Lane,
62
+ type Log_,
63
+ type NetworkInfo,
64
+ type OffchainTokenData,
65
+ CCIPVersion,
66
+ } from '../types.ts'
67
+ import {
68
+ blockRangeGenerator,
69
+ decodeAddress,
70
+ decodeOnRampAddress,
71
+ getAddressBytes,
72
+ getDataBytes,
73
+ getSomeBlockNumberBefore,
74
+ networkInfo,
75
+ parseTypeAndVersion,
76
+ } from '../utils.ts'
77
+ import type Token_ABI from './abi/BurnMintERC677Token.ts'
78
+ import type FeeQuoter_ABI from './abi/FeeQuoter_1_6.ts'
79
+ import type TokenPool_1_5_ABI from './abi/LockReleaseTokenPool_1_5.ts'
80
+ import type TokenPool_ABI from './abi/LockReleaseTokenPool_1_6_1.ts'
81
+ import EVM2EVMOffRamp_1_2_ABI from './abi/OffRamp_1_2.ts'
82
+ import EVM2EVMOffRamp_1_5_ABI from './abi/OffRamp_1_5.ts'
83
+ import OffRamp_1_6_ABI from './abi/OffRamp_1_6.ts'
84
+ import EVM2EVMOnRamp_1_2_ABI from './abi/OnRamp_1_2.ts'
85
+ import EVM2EVMOnRamp_1_5_ABI from './abi/OnRamp_1_5.ts'
86
+ import OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
87
+ import type Router_ABI from './abi/Router.ts'
88
+ import type TokenAdminRegistry_1_5_ABI from './abi/TokenAdminRegistry_1_5.ts'
89
+ import {
90
+ DEFAULT_APPROVE_GAS_LIMIT,
91
+ DEFAULT_GAS_LIMIT,
92
+ commitsFragments,
93
+ defaultAbiCoder,
94
+ getAllFragmentsMatchingEvents,
95
+ interfaces,
96
+ receiptsFragments,
97
+ requestsFragments,
98
+ } from './const.ts'
99
+ import { parseData } from './errors.ts'
100
+ import { getV12LeafHasher, getV16LeafHasher } from './hasher.ts'
101
+ import {
102
+ type CCIPMessage_V1_6_EVM,
103
+ type CleanAddressable,
104
+ parseSourceTokenData,
105
+ } from './messages.ts'
106
+ import { encodeEVMOffchainTokenData, fetchEVMOffchainTokenData } from './offchain.ts'
107
+
108
+ const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)'])
109
+
110
+ const EVMExtraArgsV1 = 'tuple(uint256 gasLimit)'
111
+ const EVMExtraArgsV2 = 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution)'
112
+ const SVMExtraArgsV1 =
113
+ 'tuple(uint32 computeUnits, uint64 accountIsWritableBitmap, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] accounts)'
114
+ const SuiExtraArgsV1 =
115
+ 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] receiverObjectIds)'
116
+
117
+ function resultToObject<T>(o: T): T {
118
+ return o instanceof Promise
119
+ ? (o.then(resultToObject) as T)
120
+ : o instanceof Result
121
+ ? (o.toObject() as T)
122
+ : o
123
+ }
124
+
125
+ function resultsToMessage(result: Result): Record<string, unknown> {
126
+ if (result.message) result = result.message as Result
127
+ return {
128
+ ...result.toObject(),
129
+ tokenAmounts: (result.tokenAmounts as Result[]).map((ta) => ta.toObject()),
130
+ ...(result.sourceTokenData
131
+ ? { sourceTokenData: (result.sourceTokenData as Result).toArray() }
132
+ : {}),
133
+ ...(result.header ? { header: (result.header as Result).toObject() } : {}),
134
+ } as unknown as CCIPMessage
135
+ }
136
+
137
+ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
138
+ static readonly family = ChainFamily.EVM
139
+ static readonly decimals = 18
140
+
141
+ readonly network: NetworkInfo<typeof ChainFamily.EVM>
142
+ readonly provider: JsonRpcApiProvider
143
+
144
+ constructor(provider: JsonRpcApiProvider, network: NetworkInfo) {
145
+ if (network.family !== ChainFamily.EVM)
146
+ throw new Error(`Invalid network family for EVMChain: ${network.family}`)
147
+ super()
148
+
149
+ this.network = network
150
+ this.provider = provider
151
+
152
+ this.typeAndVersion = moize.default(this.typeAndVersion.bind(this))
153
+ this.getBlockTimestamp = moize.default(this.getBlockTimestamp.bind(this), {
154
+ maxSize: 100,
155
+ updateCacheForKey: (key: Key[]) => typeof key[key.length - 1] !== 'number',
156
+ })
157
+ this.getTransaction = moize.default(this.getTransaction.bind(this), {
158
+ maxSize: 100,
159
+ transformArgs: (args: Key[]) =>
160
+ typeof args[0] !== 'string'
161
+ ? [(args[0] as unknown as TransactionReceipt).hash]
162
+ : (args as unknown as string[]),
163
+ })
164
+ this.getTokenForTokenPool = moize.default(this.getTokenForTokenPool.bind(this))
165
+ this.getNativeTokenForRouter = moize.default(this.getNativeTokenForRouter.bind(this), {
166
+ maxArgs: 1,
167
+ isPromise: true,
168
+ })
169
+ this.getTokenInfo = moize.default(this.getTokenInfo.bind(this))
170
+ this.getWallet = moize.default(this.getWallet.bind(this), { maxSize: 1, maxArgs: 0 })
171
+ this.getTokenAdminRegistryFor = moize.default(this.getTokenAdminRegistryFor.bind(this), {
172
+ isPromise: true,
173
+ maxArgs: 1,
174
+ })
175
+ }
176
+
177
+ // overwrite EVMChain.getWallet to implement custom wallet loading
178
+ // some signers don't like to be `.connect`ed, so pass provider as first param
179
+ static getWallet(_provider: Provider, _opts: { wallet?: unknown }): Promise<Signer> {
180
+ throw new Error('static EVM wallet loading not available')
181
+ }
182
+
183
+ // cached wallet/signer getter
184
+ async getWallet(opts: { wallet?: unknown } = {}): Promise<Signer> {
185
+ if (
186
+ typeof opts.wallet === 'number' ||
187
+ (typeof opts.wallet === 'string' && opts.wallet.match(/^(\d+|0x[a-fA-F0-9]{40})$/))
188
+ ) {
189
+ // if given a number, numeric string or address, use ethers `provider.getSigner` (e.g. geth or MM)
190
+ return this.provider.getSigner(
191
+ typeof opts.wallet === 'string' && opts.wallet.match(/^0x[a-fA-F0-9]{40}$/)
192
+ ? opts.wallet
193
+ : Number(opts.wallet),
194
+ )
195
+ } else if (typeof opts.wallet === 'string') {
196
+ // support receiving private key directly (not recommended)
197
+ try {
198
+ return Promise.resolve(
199
+ new BaseWallet(
200
+ new SigningKey((opts.wallet.startsWith('0x') ? '' : '0x') + opts.wallet),
201
+ this.provider,
202
+ ),
203
+ )
204
+ } catch (_) {
205
+ // pass
206
+ }
207
+ } else if (opts.wallet instanceof AbstractSigner) {
208
+ // if given a signer, return/cache it
209
+ return opts.wallet
210
+ }
211
+ return (this.constructor as typeof EVMChain).getWallet(this.provider, opts)
212
+ }
213
+
214
+ /**
215
+ * Expose ethers provider's `listAccounts`, if provider supports it
216
+ */
217
+ async listAccounts(): Promise<string[]> {
218
+ return (await this.provider.listAccounts()).map(({ address }) => address)
219
+ }
220
+
221
+ async getWalletAddress(opts?: { wallet?: unknown }): Promise<string> {
222
+ return (await this.getWallet(opts)).getAddress()
223
+ }
224
+
225
+ static async _getProvider(url: string): Promise<JsonRpcApiProvider> {
226
+ let provider: JsonRpcApiProvider
227
+ let providerReady: Promise<JsonRpcApiProvider>
228
+ if (url.startsWith('ws')) {
229
+ const provider_ = new WebSocketProvider(url)
230
+ providerReady = new Promise((resolve, reject) => {
231
+ provider_.websocket.onerror = reject
232
+ provider_
233
+ ._waitUntilReady()
234
+ .then(() => resolve(provider_))
235
+ .catch(reject)
236
+ })
237
+ provider = provider_
238
+ } else if (url.startsWith('http')) {
239
+ provider = new JsonRpcProvider(url)
240
+ providerReady = Promise.resolve(provider)
241
+ } else {
242
+ throw new Error(
243
+ `Unknown JSON RPC protocol in endpoint (should be wss?:// or https?://): ${url}`,
244
+ )
245
+ }
246
+ return providerReady
247
+ }
248
+
249
+ static async fromProvider(provider: JsonRpcApiProvider): Promise<EVMChain> {
250
+ try {
251
+ return new EVMChain(provider, networkInfo(Number((await provider.getNetwork()).chainId)))
252
+ } catch (err) {
253
+ provider.destroy()
254
+ throw err
255
+ }
256
+ }
257
+
258
+ static async fromUrl(url: string): Promise<EVMChain> {
259
+ return this.fromProvider(await this._getProvider(url))
260
+ }
261
+
262
+ // eslint-disable-next-line @typescript-eslint/require-await
263
+ async destroy(): Promise<void> {
264
+ this.provider.destroy()
265
+ }
266
+
267
+ async getBlockTimestamp(block: number | 'finalized'): Promise<number> {
268
+ const res = await this.provider.getBlock(block)
269
+ if (!res) throw new Error(`Block not found: ${block}`)
270
+ return res.timestamp
271
+ }
272
+
273
+ async getTransaction(hash: string | TransactionReceipt): Promise<ChainTransaction> {
274
+ const tx = typeof hash === 'string' ? await this.provider.getTransactionReceipt(hash) : hash
275
+ if (!tx) throw new Error(`Transaction not found: ${hash as string}`)
276
+ const timestamp = await this.getBlockTimestamp(tx.blockNumber)
277
+ const chainTx = {
278
+ ...tx,
279
+ chain: this,
280
+ timestamp,
281
+ logs: [] as Log_[],
282
+ }
283
+ const logs: Log_[] = tx.logs.map((l) => Object.assign(l, { tx: chainTx }))
284
+ chainTx.logs = logs
285
+ return chainTx
286
+ }
287
+
288
+ async *getLogs(filter: LogFilter): AsyncIterableIterator<Log> {
289
+ const endBlock = filter.endBlock ?? (await this.provider.getBlockNumber())
290
+ if (
291
+ filter.topics?.length &&
292
+ filter.topics.every((t: string | string[]): t is string => typeof t === 'string')
293
+ ) {
294
+ const topics = new Set(
295
+ filter.topics
296
+ .filter(isHexString)
297
+ .concat(Object.keys(getAllFragmentsMatchingEvents(filter.topics)) as `0x${string}`[])
298
+ .flat(),
299
+ )
300
+ if (!topics.size) {
301
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
302
+ throw new Error(`Could not find matching topics: ${filter.topics}`)
303
+ }
304
+ filter.topics = [Array.from(topics)]
305
+ }
306
+ if (!filter.startBlock && filter.startTime) {
307
+ filter.startBlock = await getSomeBlockNumberBefore(
308
+ this.getBlockTimestamp.bind(this),
309
+ endBlock,
310
+ filter.startTime,
311
+ )
312
+ }
313
+ for (const blockRange of blockRangeGenerator({ ...filter, endBlock })) {
314
+ console.debug('evm getLogs:', {
315
+ ...blockRange,
316
+ ...(filter.address ? { address: filter.address } : {}),
317
+ ...(filter.topics?.length ? { topics: filter.topics } : {}),
318
+ })
319
+ const logs = await this.provider.getLogs({
320
+ ...blockRange,
321
+ ...(filter.address ? { address: filter.address } : {}),
322
+ ...(filter.topics?.length ? { topics: filter.topics } : {}),
323
+ })
324
+ if (!filter.startBlock) logs.reverse()
325
+ yield* logs
326
+ }
327
+ }
328
+
329
+ static decodeMessage(log: {
330
+ topics?: readonly string[]
331
+ data: unknown
332
+ }): CCIPMessage | undefined {
333
+ if (!isBytesLike(log.data)) throw new Error(`invalid data=${util.inspect(log.data)}`)
334
+ let fragments
335
+ if (log.topics?.[0]) {
336
+ fragments = [requestsFragments[log.topics[0] as `0x${string}`]]
337
+ if (!fragments[0]) return
338
+ } else {
339
+ fragments = Object.values(requestsFragments)
340
+ }
341
+ let message
342
+ for (const fragment of fragments) {
343
+ try {
344
+ // we don't actually use Interface instance here, `decodeEventLog` is mostly static when given a fragment
345
+ const result = interfaces.OnRamp_v1_6.decodeEventLog(fragment, log.data, log.topics)
346
+ message = resultsToMessage(result)
347
+ } catch (_) {
348
+ // try next fragment
349
+ }
350
+ }
351
+ if (!message) return
352
+ if (!isHexString(message.sender, 20)) throw new Error('could not decode CCIPMessage')
353
+
354
+ if (!message.header) {
355
+ // CCIPMessage_V1_2_EVM
356
+ message.header = {
357
+ messageId: message.messageId as string,
358
+ sequenceNumber: message.sequenceNumber as bigint,
359
+ nonce: message.nonce as bigint,
360
+ sourceChainSelector: message.sourceChainSelector as bigint,
361
+ }
362
+ }
363
+
364
+ const sourceFamily = networkInfo(
365
+ (message.header as { sourceChainSelector: bigint }).sourceChainSelector,
366
+ ).family
367
+ let destFamily: ChainFamily = ChainFamily.EVM
368
+ if ((message.header as { destChainSelector: bigint } | undefined)?.destChainSelector) {
369
+ destFamily = networkInfo(
370
+ (message.header as { destChainSelector: bigint }).destChainSelector,
371
+ ).family
372
+ }
373
+ // conversions to make any message version be compatible with latest v1.6
374
+ message.tokenAmounts = (message.tokenAmounts as Record<string, string | bigint | number>[]).map(
375
+ (tokenAmount, i) => {
376
+ if ('sourceTokenData' in message) {
377
+ // CCIPMessage_V1_2_EVM
378
+ try {
379
+ tokenAmount = {
380
+ ...parseSourceTokenData(
381
+ (message as { sourceTokenData: string[] }).sourceTokenData[i],
382
+ ),
383
+ ...tokenAmount,
384
+ }
385
+ } catch (_) {
386
+ console.debug(
387
+ 'legacy sourceTokenData:',
388
+ i,
389
+ (message as { sourceTokenData: string[] }).sourceTokenData[i],
390
+ )
391
+ }
392
+ }
393
+ if (typeof tokenAmount.destExecData === 'string' && tokenAmount.destGasAmount == null) {
394
+ // CCIPMessage_V1_6_EVM
395
+ tokenAmount.destGasAmount = toBigInt(getDataBytes(tokenAmount.destExecData))
396
+ }
397
+ // Can be undefined if the message is from before v1.5 and failed to parse sourceTokenData
398
+ if (tokenAmount.sourcePoolAddress) {
399
+ tokenAmount.sourcePoolAddress = decodeAddress(
400
+ tokenAmount.sourcePoolAddress as string,
401
+ sourceFamily,
402
+ )
403
+ }
404
+ if (tokenAmount.destTokenAddress) {
405
+ tokenAmount.destTokenAddress = decodeAddress(
406
+ tokenAmount.destTokenAddress as string,
407
+ destFamily,
408
+ )
409
+ }
410
+ return tokenAmount
411
+ },
412
+ )
413
+ message.sender = decodeAddress(message.sender, sourceFamily)
414
+ message.feeToken = decodeAddress(message.feeToken as string, sourceFamily)
415
+ message.receiver = decodeAddress(message.receiver as string, destFamily)
416
+ if (message.extraArgs) {
417
+ // v1.6+
418
+ const parsed = this.decodeExtraArgs(message.extraArgs as string)
419
+ if (!parsed) throw new Error(`Unknown extraArgs: ${message.extraArgs as string}`)
420
+ const { _tag, ...rest } = parsed
421
+ // merge parsed extraArgs to any family in message root object
422
+ Object.assign(message, rest)
423
+ } else if (message.nonce === 0n) {
424
+ // v1.2..v1.5 targets EVM only; extraArgs is not explicit, gasLimit is already in
425
+ // message body, allowOutOfOrderExecution (in v1.5) was present only as nonce=0
426
+ message.allowOutOfOrderExecution = true
427
+ }
428
+ return message as CCIPMessage
429
+ }
430
+
431
+ static decodeCommits(
432
+ log: { topics?: readonly string[]; data: unknown },
433
+ lane?: Omit<Lane, 'destChainSelector'>,
434
+ ): CommitReport[] | undefined {
435
+ if (!isBytesLike(log.data)) throw new Error(`invalid data=${util.inspect(log.data)}`)
436
+ let fragments
437
+ if (log.topics?.[0]) {
438
+ const fragment = commitsFragments[log.topics[0] as `0x${string}`]
439
+ if (!fragment) return
440
+ const isCcipV15 = fragment.name === 'ReportAccepted'
441
+ // CCIP<=1.5 doesn't have lane info in event, so we need lane to be provided (e.g. from CommitStore's configs)
442
+ if (isCcipV15 && !lane) throw new Error('decoding commits from CCIP<=v1.5 requires lane')
443
+ fragments = [fragment]
444
+ } else fragments = Object.values(commitsFragments)
445
+ for (const fragment of fragments) {
446
+ let result
447
+ try {
448
+ result = interfaces.OffRamp_v1_6.decodeEventLog(fragment, log.data, log.topics)
449
+ } catch (_) {
450
+ continue
451
+ }
452
+ if (result.length === 1) result = result[0] as Result
453
+ const isCcipV15 = fragment.name === 'ReportAccepted'
454
+ if (isCcipV15) {
455
+ return [
456
+ {
457
+ merkleRoot: result.merkleRoot as string,
458
+ minSeqNr: (result.interval as Result).min as bigint,
459
+ maxSeqNr: (result.interval as Result).max as bigint,
460
+ sourceChainSelector: lane!.sourceChainSelector,
461
+ onRampAddress: lane!.onRamp,
462
+ },
463
+ ]
464
+ } else {
465
+ const reports: CommitReport[] = []
466
+ for (const c of [...(result[0] as Result[]), ...(result[1] as Result[])]) {
467
+ // if ccip>=v1.6 and lane is provided, use it to filter reports; otherwise, include all
468
+ if (lane && c.sourceChainSelector !== lane.sourceChainSelector) continue
469
+ const onRampAddress = decodeOnRampAddress(
470
+ c.onRampAddress as string,
471
+ networkInfo(c.sourceChainSelector as bigint).family,
472
+ )
473
+ if (lane && onRampAddress !== lane.onRamp) continue
474
+ reports.push({ ...c.toObject(), onRampAddress } as CommitReport)
475
+ }
476
+ if (reports.length) return reports
477
+ }
478
+ }
479
+ }
480
+
481
+ static decodeReceipt(log: {
482
+ topics?: readonly string[]
483
+ data: unknown
484
+ }): ExecutionReceipt | undefined {
485
+ if (!isBytesLike(log.data)) throw new Error(`invalid data=${util.inspect(log.data)}`)
486
+ let fragments
487
+ if (log.topics?.[0]) {
488
+ fragments = [receiptsFragments[log.topics[0] as `0x${string}`]]
489
+ if (!fragments[0]) return
490
+ } else fragments = Object.values(receiptsFragments)
491
+ for (const fragment of fragments) {
492
+ try {
493
+ const result = interfaces.OffRamp_v1_6.decodeEventLog(fragment, log.data, log.topics)
494
+ return {
495
+ ...result.toObject(),
496
+ // ...(fragment.inputs.filter((p) => p.indexed).map((p, i) => [p.name, log.topics[i+1]] as const)).
497
+ state: Number(result.state as bigint) as ExecutionState,
498
+ } as ExecutionReceipt
499
+ } catch (_) {
500
+ // continue
501
+ }
502
+ }
503
+ }
504
+
505
+ static decodeExtraArgs(
506
+ extraArgs: BytesLike,
507
+ ):
508
+ | (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
509
+ | (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
510
+ | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
511
+ | (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
512
+ | undefined {
513
+ const data = getDataBytes(extraArgs),
514
+ tag = dataSlice(data, 0, 4)
515
+ switch (tag) {
516
+ case EVMExtraArgsV1Tag: {
517
+ const args = defaultAbiCoder.decode([EVMExtraArgsV1], dataSlice(data, 4))
518
+ return { ...((args[0] as Result).toObject() as EVMExtraArgsV1), _tag: 'EVMExtraArgsV1' }
519
+ }
520
+ case EVMExtraArgsV2Tag: {
521
+ const args = defaultAbiCoder.decode([EVMExtraArgsV2], dataSlice(data, 4))
522
+ return { ...((args[0] as Result).toObject() as EVMExtraArgsV2), _tag: 'EVMExtraArgsV2' }
523
+ }
524
+ case SVMExtraArgsV1Tag: {
525
+ const args = defaultAbiCoder.decode([SVMExtraArgsV1], dataSlice(data, 4))
526
+ const parsed = (args[0] as Result).toObject() as SVMExtraArgsV1
527
+ parsed.tokenReceiver = encodeBase58(parsed.tokenReceiver)
528
+ parsed.accounts = parsed.accounts.map((a: string) => encodeBase58(a))
529
+ return { ...parsed, _tag: 'SVMExtraArgsV1' }
530
+ }
531
+ case SuiExtraArgsV1Tag: {
532
+ const args = defaultAbiCoder.decode([SuiExtraArgsV1], dataSlice(data, 4))
533
+ const parsed = (args[0] as Result).toObject() as SuiExtraArgsV1
534
+ return {
535
+ ...parsed,
536
+ receiverObjectIds: Array.from<string>(parsed.receiverObjectIds),
537
+ _tag: 'SuiExtraArgsV1',
538
+ }
539
+ }
540
+ default:
541
+ return undefined
542
+ }
543
+ }
544
+
545
+ static encodeExtraArgs(args: ExtraArgs): string {
546
+ if (!args) return '0x'
547
+ if ('computeUnits' in args) {
548
+ return concat([
549
+ SVMExtraArgsV1Tag,
550
+ defaultAbiCoder.encode(
551
+ [SVMExtraArgsV1],
552
+ [
553
+ {
554
+ ...args,
555
+ tokenReceiver: getAddressBytes(args.tokenReceiver),
556
+ accounts: args.accounts.map((a) => getAddressBytes(a)),
557
+ },
558
+ ],
559
+ ),
560
+ ])
561
+ } else if ('receiverObjectIds' in args) {
562
+ return concat([
563
+ SuiExtraArgsV1Tag,
564
+ defaultAbiCoder.encode(
565
+ [SuiExtraArgsV1],
566
+ [
567
+ {
568
+ ...args,
569
+ tokenReceiver: zeroPadValue(getAddressBytes(args.tokenReceiver), 32),
570
+ receiverObjectIds: args.receiverObjectIds.map((a) => getDataBytes(a)),
571
+ },
572
+ ],
573
+ ),
574
+ ])
575
+ } else if ('allowOutOfOrderExecution' in args) {
576
+ if (args.gasLimit == null) args.gasLimit = DEFAULT_GAS_LIMIT
577
+ return concat([EVMExtraArgsV2Tag, defaultAbiCoder.encode([EVMExtraArgsV2], [args])])
578
+ } else if (args.gasLimit != null) {
579
+ return concat([EVMExtraArgsV1Tag, defaultAbiCoder.encode([EVMExtraArgsV1], [args])])
580
+ }
581
+ return '0x'
582
+ }
583
+
584
+ static getAddress(bytes: BytesLike): string {
585
+ bytes = getBytes(bytes)
586
+ if (bytes.length < 20) throw new Error(`Invalid address: ${hexlify(bytes)}`)
587
+ else if (bytes.length > 20) {
588
+ if (bytes.slice(0, bytes.length - 20).every((b) => b === 0)) {
589
+ bytes = bytes.slice(-20)
590
+ } else {
591
+ throw new Error(`Invalid address: ${hexlify(bytes)}`)
592
+ }
593
+ }
594
+ return getAddress(hexlify(bytes))
595
+ }
596
+
597
+ async typeAndVersion(address: string) {
598
+ const contract = new Contract(
599
+ address,
600
+ VersionedContractABI,
601
+ this.provider,
602
+ ) as unknown as TypedContract<typeof VersionedContractABI>
603
+ return parseTypeAndVersion(await contract.typeAndVersion())
604
+ }
605
+
606
+ async getLaneForOnRamp(onRamp: string): Promise<Lane> {
607
+ const [, version] = await this.typeAndVersion(onRamp)
608
+ const onRampABI = version === CCIPVersion.V1_2 ? EVM2EVMOnRamp_1_2_ABI : EVM2EVMOnRamp_1_5_ABI
609
+ const contract = new Contract(onRamp, onRampABI, this.provider) as unknown as TypedContract<
610
+ typeof onRampABI
611
+ >
612
+ // TODO: memo this call
613
+ const staticConfig = await contract.getStaticConfig()
614
+ if (!staticConfig.destChainSelector)
615
+ throw new Error(
616
+ `No destChainSelector in OnRamp.staticConfig: ${JSON.stringify(staticConfig)}`,
617
+ )
618
+ return {
619
+ sourceChainSelector: this.network.chainSelector,
620
+ destChainSelector: staticConfig.destChainSelector,
621
+ version: version as CCIPVersion,
622
+ onRamp,
623
+ }
624
+ }
625
+
626
+ async getRouterForOnRamp(onRamp: string, destChainSelector: bigint): Promise<string> {
627
+ const [, version] = await this.typeAndVersion(onRamp)
628
+ let onRampABI
629
+ switch (version) {
630
+ case CCIPVersion.V1_2:
631
+ onRampABI = EVM2EVMOnRamp_1_2_ABI
632
+ // falls through
633
+ case CCIPVersion.V1_5: {
634
+ onRampABI ??= EVM2EVMOnRamp_1_5_ABI
635
+ const contract = new Contract(onRamp, onRampABI, this.provider) as unknown as TypedContract<
636
+ typeof onRampABI
637
+ >
638
+ const { router } = await contract.getDynamicConfig()
639
+ return router as string
640
+ }
641
+ case CCIPVersion.V1_6: {
642
+ onRampABI = OnRamp_1_6_ABI
643
+ const contract = new Contract(onRamp, onRampABI, this.provider) as unknown as TypedContract<
644
+ typeof onRampABI
645
+ >
646
+ const [, , router] = await contract.getDestChainConfig(destChainSelector)
647
+ return router as string
648
+ }
649
+ default:
650
+ throw new Error(`Unsupported version: ${version}`)
651
+ }
652
+ }
653
+
654
+ async getRouterForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
655
+ const [, version] = await this.typeAndVersion(offRamp)
656
+ let offRampABI, router
657
+ switch (version) {
658
+ case CCIPVersion.V1_2:
659
+ offRampABI = EVM2EVMOffRamp_1_2_ABI
660
+ // falls through
661
+ case CCIPVersion.V1_5: {
662
+ offRampABI ??= EVM2EVMOffRamp_1_5_ABI
663
+ const contract = new Contract(
664
+ offRamp,
665
+ offRampABI,
666
+ this.provider,
667
+ ) as unknown as TypedContract<typeof offRampABI>
668
+ ;({ router } = await contract.getDynamicConfig())
669
+ break
670
+ }
671
+ case CCIPVersion.V1_6: {
672
+ offRampABI = OffRamp_1_6_ABI
673
+ const contract = new Contract(
674
+ offRamp,
675
+ offRampABI,
676
+ this.provider,
677
+ ) as unknown as TypedContract<typeof offRampABI>
678
+ ;({ router } = await contract.getSourceChainConfig(sourceChainSelector))
679
+ break
680
+ }
681
+ default:
682
+ throw new Error(`Unsupported version: ${version}`)
683
+ }
684
+ return router as string
685
+ }
686
+
687
+ async getNativeTokenForRouter(router: string): Promise<string> {
688
+ const contract = new Contract(
689
+ router,
690
+ interfaces.Router,
691
+ this.provider,
692
+ ) as unknown as TypedContract<typeof Router_ABI>
693
+ return contract.getWrappedNative() as Promise<string>
694
+ }
695
+
696
+ async getOffRampsForRouter(router: string, sourceChainSelector: bigint): Promise<string[]> {
697
+ const contract = new Contract(
698
+ router,
699
+ interfaces.Router,
700
+ this.provider,
701
+ ) as unknown as TypedContract<typeof Router_ABI>
702
+ const offRamps = await contract.getOffRamps()
703
+ return offRamps
704
+ .filter((offRamp) => offRamp.sourceChainSelector === sourceChainSelector)
705
+ .map(({ offRamp }) => offRamp) as string[]
706
+ }
707
+
708
+ async getOnRampForRouter(router: string, destChainSelector: bigint): Promise<string> {
709
+ const contract = new Contract(
710
+ router,
711
+ interfaces.Router,
712
+ this.provider,
713
+ ) as unknown as TypedContract<typeof Router_ABI>
714
+ return contract.getOnRamp(destChainSelector) as Promise<string>
715
+ }
716
+
717
+ async getOnRampForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
718
+ const [, version] = await this.typeAndVersion(offRamp)
719
+ let offRampABI
720
+ switch (version) {
721
+ case CCIPVersion.V1_2:
722
+ offRampABI = EVM2EVMOffRamp_1_2_ABI
723
+ // falls through
724
+ case CCIPVersion.V1_5: {
725
+ offRampABI ??= EVM2EVMOffRamp_1_5_ABI
726
+ const contract = new Contract(
727
+ offRamp,
728
+ offRampABI,
729
+ this.provider,
730
+ ) as unknown as TypedContract<typeof offRampABI>
731
+ const { onRamp } = await contract.getStaticConfig()
732
+ return onRamp as string
733
+ }
734
+ case CCIPVersion.V1_6: {
735
+ offRampABI = OffRamp_1_6_ABI
736
+ const contract = new Contract(
737
+ offRamp,
738
+ offRampABI,
739
+ this.provider,
740
+ ) as unknown as TypedContract<typeof offRampABI>
741
+ const { onRamp } = await contract.getSourceChainConfig(sourceChainSelector)
742
+ return decodeOnRampAddress(onRamp, networkInfo(sourceChainSelector).family)
743
+ }
744
+ default:
745
+ throw new Error(`Unsupported version: ${version}`)
746
+ }
747
+ }
748
+
749
+ async getCommitStoreForOffRamp(offRamp: string): Promise<string> {
750
+ const [, version] = await this.typeAndVersion(offRamp)
751
+ let offRampABI
752
+ switch (version) {
753
+ case CCIPVersion.V1_2:
754
+ offRampABI = EVM2EVMOffRamp_1_2_ABI
755
+ // falls through
756
+ case CCIPVersion.V1_5: {
757
+ offRampABI ??= EVM2EVMOffRamp_1_5_ABI
758
+ const contract = new Contract(
759
+ offRamp,
760
+ offRampABI,
761
+ this.provider,
762
+ ) as unknown as TypedContract<typeof offRampABI>
763
+ const { commitStore } = await contract.getStaticConfig()
764
+ return commitStore as string
765
+ }
766
+ case CCIPVersion.V1_6: {
767
+ return offRamp
768
+ }
769
+ default:
770
+ throw new Error(`Unsupported version: ${version}`)
771
+ }
772
+ }
773
+
774
+ async getTokenForTokenPool(tokenPool: string): Promise<string> {
775
+ const contract = new Contract(
776
+ tokenPool,
777
+ interfaces.TokenPool_v1_6,
778
+ this.provider,
779
+ ) as unknown as TypedContract<typeof TokenPool_ABI>
780
+ return contract.getToken() as Promise<string>
781
+ }
782
+
783
+ async getTokenInfo(token: string): Promise<{ decimals: number; symbol: string; name: string }> {
784
+ const contract = new Contract(
785
+ token,
786
+ interfaces.Token,
787
+ this.provider,
788
+ ) as unknown as TypedContract<typeof Token_ABI>
789
+ const [symbol, decimals, name] = await Promise.all([
790
+ contract.symbol(),
791
+ contract.decimals(),
792
+ contract.name(),
793
+ ])
794
+ return { symbol, decimals: Number(decimals), name }
795
+ }
796
+
797
+ static getDestLeafHasher({
798
+ sourceChainSelector,
799
+ destChainSelector,
800
+ onRamp,
801
+ version,
802
+ }: Lane): LeafHasher {
803
+ switch (version) {
804
+ case CCIPVersion.V1_2:
805
+ case CCIPVersion.V1_5:
806
+ if (networkInfo(sourceChainSelector).family !== ChainFamily.EVM)
807
+ throw new Error(`Unsupported source chain: ${sourceChainSelector}`)
808
+ return getV12LeafHasher(sourceChainSelector, destChainSelector, onRamp) as LeafHasher
809
+ case CCIPVersion.V1_6:
810
+ return getV16LeafHasher(sourceChainSelector, destChainSelector, onRamp) as LeafHasher
811
+ default:
812
+ throw new Error(`Unsupported hasher version for EVM: ${version as string}`)
813
+ }
814
+ }
815
+
816
+ async _getSomeOnRampFor(router: string): Promise<string> {
817
+ // when given a router, we take any onRamp we can find, as usually they all use same registry
818
+ const someOtherNetwork = this.network.isTestnet
819
+ ? this.network.name === 'ethereum-testnet-sepolia'
820
+ ? 'avalanche-testnet-fuji'
821
+ : 'ethereum-testnet-sepolia'
822
+ : this.network.name === 'ethereum-mainnet'
823
+ ? 'avalanche-mainnet'
824
+ : 'ethereum-mainnet'
825
+ return this.getOnRampForRouter(router, networkInfo(someOtherNetwork).chainSelector)
826
+ }
827
+
828
+ async getTokenAdminRegistryFor(address: string): Promise<string> {
829
+ let [type, version, typeAndVersion] = await this.typeAndVersion(address)
830
+ if (type === 'TokenAdminRegistry') {
831
+ return address
832
+ } else if (type === 'Router') {
833
+ address = await this._getSomeOnRampFor(address)
834
+ ;[type, version, typeAndVersion] = await this.typeAndVersion(address)
835
+ } else if (!type.includes('Ramp')) {
836
+ throw new Error(`Not a Router, Ramp or TokenAdminRegistry: ${address} is "${typeAndVersion}"`)
837
+ }
838
+ const contract = new Contract(
839
+ address,
840
+ version < CCIPVersion.V1_6
841
+ ? type.includes('OnRamp')
842
+ ? interfaces.EVM2EVMOnRamp_v1_5
843
+ : interfaces.EVM2EVMOffRamp_v1_5
844
+ : type.includes('OnRamp')
845
+ ? interfaces.OnRamp_v1_6
846
+ : interfaces.OffRamp_v1_6,
847
+ this.provider,
848
+ ) as unknown as TypedContract<typeof OnRamp_1_6_ABI | typeof OffRamp_1_6_ABI>
849
+ const { tokenAdminRegistry } = await contract.getStaticConfig()
850
+ return tokenAdminRegistry as string
851
+ }
852
+
853
+ async getFeeQuoterFor(address: string): Promise<string> {
854
+ let [type, version, typeAndVersion] = await this.typeAndVersion(address)
855
+ if (type === 'FeeQuoter') {
856
+ return address
857
+ } else if (type === 'Router') {
858
+ address = await this._getSomeOnRampFor(address)
859
+ ;[type, version, typeAndVersion] = await this.typeAndVersion(address)
860
+ } else if (!type.includes('Ramp')) {
861
+ throw new Error(`Not a Router, Ramp or FeeQuoter: ${address} is "${typeAndVersion}"`)
862
+ }
863
+ if (version < CCIPVersion.V1_6)
864
+ throw new Error(`Version < v1.6 doesn't have feeQuoter: got=${version}`)
865
+
866
+ const contract = new Contract(
867
+ address,
868
+ type.includes('OnRamp') ? interfaces.OnRamp_v1_6 : interfaces.OffRamp_v1_6,
869
+ this.provider,
870
+ ) as unknown as TypedContract<typeof OnRamp_1_6_ABI | typeof OffRamp_1_6_ABI>
871
+ const { feeQuoter } = await contract.getDynamicConfig()
872
+ return feeQuoter as string
873
+ }
874
+
875
+ async getFee(router_: string, destChainSelector: bigint, message: AnyMessage): Promise<bigint> {
876
+ const router = new Contract(
877
+ router_,
878
+ interfaces.Router,
879
+ this.provider,
880
+ ) as unknown as TypedContract<typeof Router_ABI>
881
+ return router.getFee(destChainSelector, {
882
+ receiver: zeroPadValue(getAddressBytes(message.receiver), 32),
883
+ data: hexlify(message.data),
884
+ tokenAmounts: message.tokenAmounts ?? [],
885
+ feeToken: message.feeToken ?? ZeroAddress,
886
+ extraArgs: hexlify((this.constructor as typeof EVMChain).encodeExtraArgs(message.extraArgs)),
887
+ })
888
+ }
889
+
890
+ async sendMessage(
891
+ router_: string,
892
+ destChainSelector: bigint,
893
+ message: AnyMessage & { fee: bigint },
894
+ opts?: { wallet?: unknown; approveMax?: boolean },
895
+ ): Promise<ChainTransaction> {
896
+ const feeToken = message.feeToken ?? ZeroAddress
897
+ const receiver = zeroPadValue(getAddressBytes(message.receiver), 32)
898
+ const data = hexlify(message.data)
899
+ const extraArgs = hexlify(
900
+ (this.constructor as typeof EVMChain).encodeExtraArgs(message.extraArgs),
901
+ )
902
+
903
+ // make sure to approve once per token, for the total amount (including fee, if needed)
904
+ const amountsToApprove = (message.tokenAmounts ?? []).reduce(
905
+ (acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }),
906
+ {} as { [token: string]: bigint },
907
+ )
908
+ if (feeToken !== ZeroAddress)
909
+ amountsToApprove[feeToken] = (amountsToApprove[feeToken] ?? 0n) + message.fee
910
+
911
+ const wallet = await this.getWallet(opts) // moized wallet arg (if called previously)
912
+
913
+ // approve all tokens (including fee token) in parallel
914
+ let nonce = await this.provider.getTransactionCount(await this.getWalletAddress())
915
+ await Promise.all(
916
+ Object.entries(amountsToApprove).map(async ([token, amount]) => {
917
+ const contract = new Contract(token, interfaces.Token, wallet) as unknown as TypedContract<
918
+ typeof Token_ABI
919
+ >
920
+ const allowance = await contract.allowance(await wallet.getAddress(), router_)
921
+ if (allowance < amount) {
922
+ const amnt = opts?.approveMax ? 2n ** 256n - 1n : amount
923
+ // optimization: hardcode nonce and gasLimit to send all approvals in parallel without estimating
924
+ console.info('Approving', amnt, 'of', token, 'tokens for router', router_)
925
+ const tx = await contract.approve(router_, amnt, {
926
+ nonce: nonce++,
927
+ gasLimit: DEFAULT_APPROVE_GAS_LIMIT,
928
+ })
929
+ console.info('=>', tx.hash)
930
+ await tx.wait(1, 60_000)
931
+ }
932
+ }),
933
+ )
934
+
935
+ const router = new Contract(router_, interfaces.Router, wallet) as unknown as TypedContract<
936
+ typeof Router_ABI
937
+ >
938
+ const tx = await router.ccipSend(
939
+ destChainSelector,
940
+ {
941
+ receiver,
942
+ data,
943
+ tokenAmounts: message.tokenAmounts ?? [],
944
+ extraArgs,
945
+ feeToken,
946
+ },
947
+ {
948
+ nonce: nonce++,
949
+ // if native fee, include it in value; otherwise, it's transferedFrom feeToken
950
+ ...(feeToken === ZeroAddress ? { value: message.fee } : {}),
951
+ },
952
+ )
953
+ const receipt = await tx.wait(1)
954
+ return this.getTransaction(receipt!)
955
+ }
956
+
957
+ fetchOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
958
+ return fetchEVMOffchainTokenData(request)
959
+ }
960
+
961
+ async executeReport(
962
+ offRamp: string,
963
+ execReport: ExecutionReport,
964
+ opts?: { wallet?: string; gasLimit?: number; tokensGasLimit?: number },
965
+ ) {
966
+ const [_, version] = await this.typeAndVersion(offRamp)
967
+ const wallet = await this.getWallet(opts)
968
+
969
+ let manualExecTx
970
+ const offchainTokenData = execReport.offchainTokenData.map(encodeEVMOffchainTokenData)
971
+
972
+ switch (version) {
973
+ case CCIPVersion.V1_2: {
974
+ const contract = new Contract(
975
+ offRamp,
976
+ EVM2EVMOffRamp_1_2_ABI,
977
+ wallet,
978
+ ) as unknown as TypedContract<typeof EVM2EVMOffRamp_1_2_ABI>
979
+ const gasOverride = BigInt(opts?.gasLimit ?? 0)
980
+ manualExecTx = await contract.manuallyExecute(
981
+ {
982
+ ...execReport,
983
+ proofs: execReport.proofs.map((d) => hexlify(d)),
984
+ messages: [execReport.message as CCIPMessage<typeof CCIPVersion.V1_2>],
985
+ offchainTokenData: [offchainTokenData],
986
+ },
987
+ [gasOverride],
988
+ )
989
+ break
990
+ }
991
+ case CCIPVersion.V1_5: {
992
+ const contract = new Contract(
993
+ offRamp,
994
+ EVM2EVMOffRamp_1_5_ABI,
995
+ wallet,
996
+ ) as unknown as TypedContract<typeof EVM2EVMOffRamp_1_5_ABI>
997
+ manualExecTx = await contract.manuallyExecute(
998
+ {
999
+ ...execReport,
1000
+ proofs: execReport.proofs.map((d) => hexlify(d)),
1001
+ messages: [execReport.message as CCIPMessage<typeof CCIPVersion.V1_5>],
1002
+ offchainTokenData: [offchainTokenData],
1003
+ },
1004
+ [
1005
+ {
1006
+ receiverExecutionGasLimit: BigInt(opts?.gasLimit ?? 0),
1007
+ tokenGasOverrides: execReport.message.tokenAmounts.map(() =>
1008
+ BigInt(opts?.tokensGasLimit ?? opts?.gasLimit ?? 0),
1009
+ ),
1010
+ },
1011
+ ],
1012
+ )
1013
+ break
1014
+ }
1015
+ case CCIPVersion.V1_6: {
1016
+ // normalize message
1017
+ const sender = zeroPadValue(getAddressBytes(execReport.message.sender), 32)
1018
+ const tokenAmounts = (execReport.message as CCIPMessage_V1_6_EVM).tokenAmounts.map(
1019
+ (ta) => ({
1020
+ ...ta,
1021
+ sourcePoolAddress: zeroPadValue(getAddressBytes(ta.sourcePoolAddress), 32),
1022
+ extraData: hexlify(getDataBytes(ta.extraData)),
1023
+ }),
1024
+ )
1025
+ const message = {
1026
+ ...(execReport.message as CCIPMessage_V1_6_EVM),
1027
+ sender,
1028
+ tokenAmounts,
1029
+ }
1030
+ const contract = new Contract(offRamp, OffRamp_1_6_ABI, wallet) as unknown as TypedContract<
1031
+ typeof OffRamp_1_6_ABI
1032
+ >
1033
+ manualExecTx = await contract.manuallyExecute(
1034
+ [
1035
+ {
1036
+ ...execReport,
1037
+ proofs: execReport.proofs.map((p) => hexlify(p)),
1038
+ sourceChainSelector: execReport.message.header.sourceChainSelector,
1039
+ messages: [message],
1040
+ offchainTokenData: [offchainTokenData],
1041
+ },
1042
+ ],
1043
+ [
1044
+ [
1045
+ {
1046
+ receiverExecutionGasLimit: BigInt(opts?.gasLimit ?? 0),
1047
+ tokenGasOverrides: execReport.message.tokenAmounts.map(() =>
1048
+ BigInt(opts?.tokensGasLimit ?? opts?.gasLimit ?? 0),
1049
+ ),
1050
+ },
1051
+ ],
1052
+ ],
1053
+ )
1054
+ break
1055
+ }
1056
+ default:
1057
+ throw new Error(`Unsupported version: ${version}`)
1058
+ }
1059
+ const receipt = await this.provider.waitForTransaction(manualExecTx.hash, 1, 60e3)
1060
+ if (!receipt?.hash) throw new Error(`Could not confirm exec tx: ${manualExecTx.hash}`)
1061
+ if (!receipt.status) throw new Error(`Exec transaction reverted: ${manualExecTx.hash}`)
1062
+ return this.getTransaction(receipt)
1063
+ }
1064
+
1065
+ static parse(data: unknown) {
1066
+ return parseData(data)
1067
+ }
1068
+
1069
+ /**
1070
+ * Get the supported tokens for a given contract address
1071
+ *
1072
+ * @param address Router, OnRamp, OffRamp or TokenAdminRegistry contract
1073
+ * @returns An array of supported token addresses.
1074
+ */
1075
+ async getSupportedTokens(registry: string, opts?: { page?: number }): Promise<string[]> {
1076
+ const contract = new Contract(
1077
+ registry,
1078
+ interfaces.TokenAdminRegistry,
1079
+ this.provider,
1080
+ ) as unknown as TypedContract<typeof TokenAdminRegistry_1_5_ABI>
1081
+
1082
+ const limit = (opts?.page ?? 1000) || Number.MAX_SAFE_INTEGER
1083
+ const res = []
1084
+ let page
1085
+ do {
1086
+ page = await contract.getAllConfiguredTokens(BigInt(res.length), BigInt(limit))
1087
+ res.push(...page)
1088
+ } while (page.length === limit)
1089
+ return res as string[]
1090
+ }
1091
+
1092
+ async getRegistryTokenConfig(
1093
+ registry: string,
1094
+ token: string,
1095
+ ): Promise<{
1096
+ administrator: string
1097
+ pendingAdministrator?: string
1098
+ tokenPool?: string
1099
+ }> {
1100
+ const contract = new Contract(
1101
+ registry,
1102
+ interfaces.TokenAdminRegistry,
1103
+ this.provider,
1104
+ ) as unknown as TypedContract<typeof TokenAdminRegistry_1_5_ABI>
1105
+
1106
+ const config = (await resultToObject(contract.getTokenConfig(token))) as CleanAddressable<
1107
+ Partial<Awaited<ReturnType<(typeof contract)['getTokenConfig']>>>
1108
+ >
1109
+ if (!config.administrator || config.administrator === ZeroAddress)
1110
+ throw new Error(`Token ${token} is not configured in registry ${registry}`)
1111
+ if (!config.pendingAdministrator || config.pendingAdministrator === ZeroAddress)
1112
+ delete config.pendingAdministrator
1113
+ if (!config.tokenPool || config.tokenPool === ZeroAddress) delete config.tokenPool
1114
+ return {
1115
+ ...config,
1116
+ administrator: config.administrator,
1117
+ }
1118
+ }
1119
+
1120
+ async getTokenPoolConfigs(tokenPool: string): Promise<{
1121
+ token: string
1122
+ router: string
1123
+ typeAndVersion: string
1124
+ }> {
1125
+ const [_, , typeAndVersion] = await this.typeAndVersion(tokenPool)
1126
+
1127
+ const contract = new Contract(
1128
+ tokenPool,
1129
+ interfaces.TokenPool_v1_6,
1130
+ this.provider,
1131
+ ) as unknown as TypedContract<typeof TokenPool_ABI>
1132
+
1133
+ const token = contract.getToken()
1134
+ const router = contract.getRouter()
1135
+ return Promise.all([token, router]).then(([token, router]) => {
1136
+ return {
1137
+ token: token as string,
1138
+ router: router as string,
1139
+ typeAndVersion,
1140
+ }
1141
+ })
1142
+ }
1143
+
1144
+ async getTokenPoolRemotes(
1145
+ tokenPool: string,
1146
+ remoteChainSelector?: bigint,
1147
+ ): Promise<Record<string, TokenPoolRemote>> {
1148
+ const [_, version] = await this.typeAndVersion(tokenPool)
1149
+
1150
+ let supportedChains: Promise<NetworkInfo[]>
1151
+ if (remoteChainSelector) supportedChains = Promise.resolve([networkInfo(remoteChainSelector)])
1152
+
1153
+ let remotePools: Promise<string[][]>
1154
+ let contract
1155
+ if (version < '1.5.1') {
1156
+ const contract_ = new Contract(
1157
+ tokenPool,
1158
+ interfaces.TokenPool_v1_5,
1159
+ this.provider,
1160
+ ) as unknown as TypedContract<typeof TokenPool_1_5_ABI>
1161
+ contract = contract_
1162
+ supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1163
+ remotePools = supportedChains.then((chains) =>
1164
+ Promise.all(
1165
+ chains.map((chain) =>
1166
+ contract_
1167
+ .getRemotePool(chain.chainSelector)
1168
+ .then((remotePool) => [decodeAddress(remotePool, chain.family)]),
1169
+ ),
1170
+ ),
1171
+ )
1172
+ } else {
1173
+ const contract_ = new Contract(
1174
+ tokenPool,
1175
+ interfaces.TokenPool_v1_6,
1176
+ this.provider,
1177
+ ) as unknown as TypedContract<typeof TokenPool_ABI>
1178
+ contract = contract_
1179
+ supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1180
+ remotePools = supportedChains.then((chains) =>
1181
+ Promise.all(
1182
+ chains.map((chain) =>
1183
+ contract_
1184
+ .getRemotePools(chain.chainSelector)
1185
+ .then((pools) => pools.map((remotePool) => decodeAddress(remotePool, chain.family))),
1186
+ ),
1187
+ ),
1188
+ )
1189
+ }
1190
+ const remoteInfo = supportedChains.then((chains) =>
1191
+ Promise.all(
1192
+ chains.map((chain) =>
1193
+ Promise.all([
1194
+ contract.getRemoteToken(chain.chainSelector),
1195
+ resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1196
+ resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1197
+ ] as const),
1198
+ ),
1199
+ ),
1200
+ )
1201
+ return Promise.all([supportedChains, remotePools, remoteInfo]).then(
1202
+ ([supportedChains, remotePools, remoteInfo]) =>
1203
+ Object.fromEntries(
1204
+ supportedChains.map(
1205
+ (chain, i) =>
1206
+ [
1207
+ chain.name,
1208
+ {
1209
+ remoteToken: decodeAddress(remoteInfo[i][0], chain.family),
1210
+ remotePools: remotePools[i].map((pool) => decodeAddress(pool, chain.family)),
1211
+ inboundRateLimiterState: remoteInfo[i][1].isEnabled ? remoteInfo[i][1] : null,
1212
+ outboundRateLimiterState: remoteInfo[i][2].isEnabled ? remoteInfo[i][2] : null,
1213
+ },
1214
+ ] as const,
1215
+ ),
1216
+ ),
1217
+ )
1218
+ }
1219
+ async listFeeTokens(router: string) {
1220
+ const onRamp = await this._getSomeOnRampFor(router)
1221
+ const [_, version] = await this.typeAndVersion(onRamp)
1222
+ let tokens
1223
+ let onRampABI
1224
+ switch (version) {
1225
+ case CCIPVersion.V1_2:
1226
+ onRampABI = EVM2EVMOnRamp_1_2_ABI
1227
+ // falls through
1228
+ case CCIPVersion.V1_5: {
1229
+ onRampABI ??= EVM2EVMOnRamp_1_5_ABI
1230
+ const contract = new Contract(onRamp, onRampABI, this.provider) as unknown as TypedContract<
1231
+ typeof onRampABI
1232
+ >
1233
+ tokens = await Promise.all([
1234
+ this.getNativeTokenForRouter(router),
1235
+ contract.getStaticConfig().then(({ linkToken }) => linkToken),
1236
+ ])
1237
+ break
1238
+ }
1239
+ case CCIPVersion.V1_6: {
1240
+ const feeQuoter = await this.getFeeQuoterFor(onRamp)
1241
+ const contract = new Contract(
1242
+ feeQuoter,
1243
+ interfaces.FeeQuoter,
1244
+ this.provider,
1245
+ ) as unknown as TypedContract<typeof FeeQuoter_ABI>
1246
+ tokens = await contract.getFeeTokens()
1247
+ break
1248
+ }
1249
+ default:
1250
+ throw new Error(`Unsupported version: ${version}`)
1251
+ }
1252
+ return Object.fromEntries(
1253
+ await Promise.all(
1254
+ tokens.map(
1255
+ async (token) => [token as string, await this.getTokenInfo(token as string)] as const,
1256
+ ),
1257
+ ),
1258
+ )
1259
+ }
1260
+ }
1261
+
1262
+ supportedChains[ChainFamily.EVM] = EVMChain