@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,6 @@
1
+ import type { SVMExtraArgsV1 } from '../extra-args.ts'
2
+ import type { CCIPMessage_V1_6 } from '../types.ts'
3
+
4
+ // SourceTokenData adds `destGasAmount` (decoded from source's `destExecData`);
5
+ // not sure why they kept the "gas" name in Solana, but let's just be keep consistent
6
+ export type CCIPMessage_V1_6_Solana = CCIPMessage_V1_6 & SVMExtraArgsV1
@@ -0,0 +1,272 @@
1
+ import {
2
+ type AddressLookupTableAccount,
3
+ type Connection,
4
+ type Signer,
5
+ type SimulateTransactionConfig,
6
+ type Transaction,
7
+ type TransactionInstruction,
8
+ ComputeBudgetProgram,
9
+ PublicKey,
10
+ SendTransactionError,
11
+ TransactionMessage,
12
+ VersionedTransaction,
13
+ } from '@solana/web3.js'
14
+ import { type BytesLike, dataLength, dataSlice, hexlify } from 'ethers'
15
+
16
+ import type { Log_ } from '../types.ts'
17
+ import { getDataBytes, sleep } from '../utils.ts'
18
+
19
+ export function bytesToBuffer(bytes: BytesLike): Buffer {
20
+ return Buffer.from(getDataBytes(bytes).buffer)
21
+ }
22
+
23
+ export async function waitForFinalization(
24
+ connection: Connection,
25
+ signature: string,
26
+ intervalMs = 500,
27
+ maxAttempts = 500,
28
+ ): Promise<void> {
29
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
30
+ const status = await connection.getSignatureStatuses([signature])
31
+ const info = status.value[0]
32
+
33
+ if (info?.confirmationStatus === 'finalized') {
34
+ return
35
+ }
36
+ await sleep(intervalMs)
37
+ }
38
+
39
+ throw new Error(`Transaction ${signature} not finalized after timeout`)
40
+ }
41
+
42
+ export function camelToSnakeCase(str: string): string {
43
+ return str
44
+ .replace(/([A-Z]+)([A-Z][a-z]|$)/g, (_, p1: string, p2: string) => {
45
+ if (p2) {
46
+ return `_${p1.slice(0, -1).toLowerCase()}_${p2.toLowerCase()}`
47
+ }
48
+ return `_${p1.toLowerCase()}`
49
+ })
50
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
51
+ .toLowerCase()
52
+ .replace(/^_/, '')
53
+ }
54
+
55
+ type ParsedLog = Pick<Log_, 'topics' | 'index' | 'address' | 'data'> & { data: string }
56
+
57
+ /**
58
+ * Utility function to parse Solana logs with proper address and topic extraction.
59
+ *
60
+ * Solana logs are structured as a stack-based execution trace:
61
+ * - "Program <address> invoke [<depth>]" - Program call starts
62
+ * - "Program log: <data>" - Program emitted a log message
63
+ * - "Program data: <base64>" - Program emitted structured data (Anchor events)
64
+ * - "Program <address> success/failed" - Program call ends
65
+ *
66
+ * This function:
67
+ * 1. Tracks the program call stack to determine which program emitted each log
68
+ * 2. Extracts the first 8 bytes from base64 "Program data:" logs as topics (event discriminants)
69
+ * 3. Converts logs to EVM-compatible Log_ format for CCIP compatibility
70
+ * 4. Returns ALL logs from the transaction - filtering should be done by the caller
71
+ *
72
+ * @param logs - Array of logMessages from Solana transaction
73
+ * @returns Array of parsed log objects from all programs in the transaction
74
+ */
75
+ export function parseSolanaLogs(logs: readonly string[]): ParsedLog[] {
76
+ const results: ReturnType<typeof parseSolanaLogs> = []
77
+ const programStack: string[] = []
78
+
79
+ for (const [i, log] of logs.entries()) {
80
+ // Track program calls and returns to maintain the address stack
81
+ let match
82
+ if ((match = log.match(/^Program (\w+) invoke\b/))) {
83
+ programStack.push(match[1])
84
+ } else if ((match = log.match(/^Program (\w+) (success|failed)\b/))) {
85
+ // Pop from stack when program returns
86
+ programStack.pop()
87
+ } else if ((match = log.match(/^Program (log|data): /))) {
88
+ // Extract the actual log data
89
+ const logData = log.slice(match[0].length)
90
+ const currentProgram = programStack[programStack.length - 1]
91
+ let topics: string[] = []
92
+
93
+ if (log.startsWith('Program data: ')) {
94
+ try {
95
+ // Try to decode base64 and extract first 8 bytes as topic/discriminant
96
+ const buffer = getDataBytes(logData)
97
+ if (dataLength(buffer) >= 8) {
98
+ topics = [dataSlice(buffer, 0, 8)]
99
+ }
100
+ } catch {
101
+ // If base64 decoding fails, leave topics empty
102
+ }
103
+ }
104
+ // For regular log messages, use the current program on stack
105
+ results.push({
106
+ topics,
107
+ index: i,
108
+ address: currentProgram,
109
+ data: logData,
110
+ })
111
+ }
112
+ }
113
+
114
+ return results
115
+ }
116
+
117
+ export function getErrorFromLogs(
118
+ logs_: readonly string[] | readonly Pick<Log_, 'address' | 'index' | 'data' | 'topics'>[] | null,
119
+ ): { program: string; [k: string]: string } | undefined {
120
+ if (!logs_?.length) return
121
+ let logs
122
+ if (logs_.every((l) => typeof l === 'string')) logs = parseSolanaLogs(logs_)
123
+ else logs = logs_
124
+
125
+ const lastLog = logs[logs.length - 1]
126
+ // collect all logs from the last program execution (the one which failed)
127
+ const lastProgramLogs = logs
128
+ .reduceRight(
129
+ (acc, l) =>
130
+ // if acc is empty (i.e. on last log), or it is emitted by the same program and not a Program data:
131
+ !acc.length || (l.address === acc[0].address && !l.topics?.length) ? [l, ...acc] : acc,
132
+ [] as Pick<Log_, 'address' | 'index' | 'data'>[],
133
+ )
134
+ .map(({ data }) => data as string)
135
+ .reduceRight(
136
+ (acc, l) =>
137
+ l.endsWith(':') && acc.length
138
+ ? [`${l} ${acc[0]}`, ...acc.slice(1)]
139
+ : l.split(': ').length > 1 && l.split('. ').length > 1
140
+ ? [...l.replace(/\.$/, '').split('. '), ...acc]
141
+ : [l, ...acc],
142
+ [] as string[],
143
+ ) // cosmetic: join lines ending in ':' with next
144
+ .map((l) => {
145
+ try {
146
+ // convert number[]s (common in solana logs) into slightly more readable 0x-bytearrays
147
+ return l.replace(/\[(\d{1,3}, ){3,}\d+\]/g, (m) =>
148
+ hexlify(
149
+ new Uint8Array(
150
+ m
151
+ .substring(1, m.length - 1)
152
+ .split(', ')
153
+ .map((x) => +x),
154
+ ),
155
+ ),
156
+ )
157
+ } catch (_) {
158
+ return l
159
+ }
160
+ })
161
+ if (lastProgramLogs.every((l) => l.indexOf(': ') >= 0)) {
162
+ return {
163
+ program: lastLog.address,
164
+ ...Object.fromEntries(
165
+ lastProgramLogs.map((l) => [
166
+ l.substring(0, l.indexOf(': ')),
167
+ l.substring(l.indexOf(': ') + 2),
168
+ ]),
169
+ ),
170
+ }
171
+ } else {
172
+ return {
173
+ program: lastLog.address,
174
+ error: lastProgramLogs.join('\n'),
175
+ }
176
+ }
177
+ }
178
+
179
+ export async function simulateTransaction({
180
+ connection,
181
+ payerKey,
182
+ computeUnitsOverride,
183
+ ...rest
184
+ }: {
185
+ connection: Connection
186
+ payerKey: PublicKey
187
+ computeUnitsOverride?: number
188
+ addressLookupTableAccounts?: AddressLookupTableAccount[]
189
+ } & ({ instructions: TransactionInstruction[] } | { tx: Transaction | VersionedTransaction })) {
190
+ // Add max compute units for simulation
191
+ const maxComputeUnits = 1_400_000
192
+ const recentBlockhash = '11111111111111111111111111111112'
193
+ const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({
194
+ units: computeUnitsOverride || maxComputeUnits,
195
+ })
196
+
197
+ let tx: VersionedTransaction
198
+ if (!('tx' in rest)) {
199
+ // Create message with compute budget instruction
200
+ const message = new TransactionMessage({
201
+ payerKey,
202
+ recentBlockhash,
203
+ instructions: [computeBudgetIx, ...rest.instructions],
204
+ })
205
+
206
+ const messageV0 = message.compileToV0Message(rest.addressLookupTableAccounts)
207
+ tx = new VersionedTransaction(messageV0)
208
+ } else if (!('version' in rest.tx)) {
209
+ // Create message with compute budget instruction
210
+ const message = new TransactionMessage({
211
+ payerKey,
212
+ recentBlockhash,
213
+ instructions: [computeBudgetIx, ...rest.tx.instructions],
214
+ })
215
+
216
+ const messageV0 = message.compileToV0Message(rest.addressLookupTableAccounts)
217
+ tx = new VersionedTransaction(messageV0)
218
+ } else {
219
+ tx = rest.tx
220
+ }
221
+
222
+ const config: SimulateTransactionConfig = {
223
+ commitment: 'confirmed',
224
+ replaceRecentBlockhash: true,
225
+ sigVerify: false,
226
+ }
227
+
228
+ const result = await connection.simulateTransaction(tx, config)
229
+
230
+ if (result.value.err) {
231
+ console.debug('Simulation results:', {
232
+ logs: result.value.logs,
233
+ unitsConsumed: result.value.unitsConsumed,
234
+ returnData: result.value.returnData,
235
+ err: result.value.err,
236
+ })
237
+ // same error sendTransaction sends, to be catched up
238
+ throw new SendTransactionError({
239
+ action: 'simulate',
240
+ signature: '',
241
+ transactionMessage: JSON.stringify(result.value.err),
242
+ logs: result.value.logs!,
243
+ })
244
+ }
245
+
246
+ return result.value
247
+ }
248
+
249
+ /**
250
+ * Used as `provider` in anchor's `Program` constructor, to support `.view()` simulations
251
+ * without * requiring a full AnchorProvider with wallet
252
+ * @param connection - Connection to the Solana network
253
+ * @param feePayer - Fee payer for the simulated transaction
254
+ * @returns Value returned by the simulated method
255
+ */
256
+ export function simulationProvider(
257
+ connection: Connection,
258
+ feePayer: PublicKey = new PublicKey('11111111111111111111111111111112'),
259
+ ) {
260
+ return {
261
+ connection,
262
+ wallet: {
263
+ publicKey: feePayer,
264
+ },
265
+ simulate: async (tx: Transaction | VersionedTransaction, _signers?: Signer[]) =>
266
+ simulateTransaction({
267
+ connection,
268
+ payerKey: feePayer,
269
+ tx,
270
+ }),
271
+ }
272
+ }
@@ -0,0 +1,90 @@
1
+ import { concat, id, keccak256, zeroPadValue } from 'ethers'
2
+
3
+ import { encodeNumber, encodeRawBytes } from '../aptos/utils.ts'
4
+ import { decodeExtraArgs } from '../extra-args.ts'
5
+ import { type LeafHasher, LEAF_DOMAIN_SEPARATOR } from '../hasher/common.ts'
6
+ import { type CCIPMessage, type CCIPMessage_V1_6, CCIPVersion } from '../types.ts'
7
+ import type { CCIPMessage_V1_6_Sui } from './types.ts'
8
+
9
+ export function getSuiLeafHasher<V extends CCIPVersion = CCIPVersion>({
10
+ sourceChainSelector,
11
+ destChainSelector,
12
+ onRamp,
13
+ version,
14
+ }: {
15
+ sourceChainSelector: bigint
16
+ destChainSelector: bigint
17
+ onRamp: string
18
+ version: V
19
+ }): LeafHasher<V> {
20
+ let metadataHash: string
21
+ switch (version) {
22
+ case CCIPVersion.V1_6:
23
+ metadataHash = hashSuiMetadata(sourceChainSelector, destChainSelector, onRamp)
24
+ return ((message: CCIPMessage<typeof CCIPVersion.V1_6>): string =>
25
+ hashV16SuiMessage(message, metadataHash)) as LeafHasher<V>
26
+ default:
27
+ throw new Error(`Unsupported hasher version for Sui: ${version as string}`)
28
+ }
29
+ }
30
+
31
+ export function hashV16SuiMessage(
32
+ message: CCIPMessage_V1_6 | CCIPMessage_V1_6_Sui,
33
+ metadataHash: string,
34
+ ): string {
35
+ let tokenReceiver, gasLimit
36
+ if ('tokenReceiver' in message) {
37
+ ;({ tokenReceiver, gasLimit } = message)
38
+ } else {
39
+ const parsedArgs = decodeExtraArgs(message.extraArgs)
40
+ if (!parsedArgs || parsedArgs._tag !== 'SuiExtraArgsV1')
41
+ throw new Error('Invalid extraArgs for Sui message, must be SUIExtraArgsV1')
42
+ ;({ tokenReceiver, gasLimit } = parsedArgs)
43
+ }
44
+
45
+ const innerHash = concat([
46
+ encodeNumber(message.header.messageId),
47
+ zeroPadValue(message.receiver, 32),
48
+ encodeNumber(message.header.sequenceNumber),
49
+ encodeNumber(gasLimit),
50
+ zeroPadValue(tokenReceiver, 32),
51
+ encodeNumber(message.header.nonce),
52
+ ])
53
+
54
+ const tokenHash = concat([
55
+ encodeNumber(message.tokenAmounts.length),
56
+ ...message.tokenAmounts.map((token) =>
57
+ concat([
58
+ encodeRawBytes(token.sourcePoolAddress),
59
+ zeroPadValue(token.destTokenAddress, 32),
60
+ encodeNumber(token.destGasAmount),
61
+ encodeRawBytes(token.extraData),
62
+ encodeNumber(token.amount),
63
+ ]),
64
+ ),
65
+ ])
66
+
67
+ const outerHash = concat([
68
+ zeroPadValue(LEAF_DOMAIN_SEPARATOR, 32),
69
+ metadataHash,
70
+ keccak256(innerHash),
71
+ keccak256(message.sender),
72
+ keccak256(message.data),
73
+ keccak256(tokenHash),
74
+ ])
75
+
76
+ return keccak256(outerHash)
77
+ }
78
+
79
+ export const hashSuiMetadata = (
80
+ sourceChainSelector: bigint,
81
+ destChainSelector: bigint,
82
+ onRamp: string,
83
+ ): string => {
84
+ const versionHash = id('Any2SuiMessageHashV1')
85
+ const encodedSource = encodeNumber(sourceChainSelector)
86
+ const encodedDest = encodeNumber(destChainSelector)
87
+ const onrampHash = keccak256(onRamp)
88
+
89
+ return keccak256(concat([versionHash, encodedSource, encodedDest, onrampHash]))
90
+ }
@@ -0,0 +1,198 @@
1
+ import { type BytesLike, isBytesLike } from 'ethers'
2
+
3
+ import { AptosChain } from '../aptos/index.ts'
4
+ import { type ChainTransaction, type LogFilter, Chain, ChainFamily } from '../chain.ts'
5
+ import type { EVMExtraArgsV2, ExtraArgs, SVMExtraArgsV1 } from '../extra-args.ts'
6
+ import type { LeafHasher } from '../hasher/common.ts'
7
+ import { supportedChains } from '../supported-chains.ts'
8
+ import type {
9
+ AnyMessage,
10
+ CCIPRequest,
11
+ CommitReport,
12
+ ExecutionReceipt,
13
+ ExecutionReport,
14
+ Lane,
15
+ Log_,
16
+ NetworkInfo,
17
+ OffchainTokenData,
18
+ } from '../types.ts'
19
+ import type { CCIPMessage_V1_6_Sui } from './types.ts'
20
+
21
+ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
22
+ static readonly family = ChainFamily.Sui
23
+ static readonly decimals = 8
24
+
25
+ readonly network: NetworkInfo<typeof ChainFamily.Sui>
26
+
27
+ constructor() {
28
+ super()
29
+ throw new Error('Not implemented')
30
+ }
31
+
32
+ static async fromUrl(_url: string): Promise<SuiChain> {
33
+ return Promise.reject(new Error('Not implemented'))
34
+ }
35
+
36
+ async destroy(): Promise<void> {
37
+ // Nothing to cleanup for Aptos implementation
38
+ }
39
+
40
+ async getBlockTimestamp(_version: number | 'finalized'): Promise<number> {
41
+ return Promise.reject(new Error('Not implemented'))
42
+ }
43
+
44
+ async getTransaction(_hash: string | number): Promise<ChainTransaction> {
45
+ return Promise.reject(new Error('Not implemented'))
46
+ }
47
+
48
+ // eslint-disable-next-line require-yield
49
+ async *getLogs(_opts: LogFilter & { versionAsHash?: boolean }) {
50
+ await Promise.resolve()
51
+ throw new Error('Not implemented')
52
+ }
53
+
54
+ async typeAndVersion(
55
+ _address: string,
56
+ ): Promise<
57
+ | [type_: string, version: string, typeAndVersion: string]
58
+ | [type_: string, version: string, typeAndVersion: string, suffix: string]
59
+ > {
60
+ return Promise.reject(new Error('Not implemented'))
61
+ }
62
+
63
+ getRouterForOnRamp(_onRamp: string, _destChainSelector: bigint): Promise<string> {
64
+ return Promise.reject(new Error('Not implemented'))
65
+ }
66
+
67
+ getRouterForOffRamp(_offRamp: string, _sourceChainSelector: bigint): Promise<string> {
68
+ return Promise.reject(new Error('Not implemented'))
69
+ }
70
+
71
+ getNativeTokenForRouter(_router: string): Promise<string> {
72
+ return Promise.reject(new Error('Not implemented'))
73
+ }
74
+
75
+ getOffRampsForRouter(_router: string, _sourceChainSelector: bigint): Promise<string[]> {
76
+ return Promise.reject(new Error('Not implemented'))
77
+ }
78
+
79
+ getOnRampForRouter(_router: string, _destChainSelector: bigint): Promise<string> {
80
+ return Promise.reject(new Error('Not implemented'))
81
+ }
82
+
83
+ async getOnRampForOffRamp(_offRamp: string, _sourceChainSelector: bigint): Promise<string> {
84
+ return Promise.reject(new Error('Not implemented'))
85
+ }
86
+
87
+ getCommitStoreForOffRamp(_offRamp: string): Promise<string> {
88
+ return Promise.reject(new Error('Not implemented'))
89
+ }
90
+
91
+ async getTokenForTokenPool(_tokenPool: string): Promise<string> {
92
+ return Promise.reject(new Error('Not implemented'))
93
+ }
94
+
95
+ async getTokenInfo(_token: string): Promise<{ symbol: string; decimals: number }> {
96
+ return Promise.reject(new Error('Not implemented'))
97
+ }
98
+
99
+ getTokenAdminRegistryFor(_address: string): Promise<string> {
100
+ return Promise.reject(new Error('Not implemented'))
101
+ }
102
+
103
+ async getWalletAddress(_opts?: { wallet?: unknown }): Promise<string> {
104
+ return Promise.reject(new Error('Not implemented'))
105
+ }
106
+
107
+ // Static methods for decoding
108
+ static decodeMessage(_log: Log_): CCIPMessage_V1_6_Sui | undefined {
109
+ throw new Error('Not implemented')
110
+ }
111
+
112
+ static decodeExtraArgs(
113
+ extraArgs: BytesLike,
114
+ ):
115
+ | (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
116
+ | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
117
+ | undefined {
118
+ return AptosChain.decodeExtraArgs(extraArgs)
119
+ }
120
+
121
+ static encodeExtraArgs(extraArgs: ExtraArgs): string {
122
+ return AptosChain.encodeExtraArgs(extraArgs)
123
+ }
124
+
125
+ static decodeCommits(_log: Log_, _lane?: Lane): CommitReport[] | undefined {
126
+ throw new Error('Not implemented')
127
+ }
128
+
129
+ static decodeReceipt(_log: Log_): ExecutionReceipt | undefined {
130
+ throw new Error('Not implemented')
131
+ }
132
+
133
+ static getAddress(bytes: BytesLike): string {
134
+ return AptosChain.getAddress(bytes)
135
+ }
136
+
137
+ static getDestLeafHasher(_lane: Lane): LeafHasher {
138
+ throw new Error('Not implemented')
139
+ }
140
+
141
+ async getFee(_router: string, _destChainSelector: bigint, _message: AnyMessage): Promise<bigint> {
142
+ return Promise.reject(new Error('Not implemented'))
143
+ }
144
+
145
+ async sendMessage(
146
+ _router: string,
147
+ _destChainSelector: bigint,
148
+ _message: AnyMessage & { fee: bigint },
149
+ _opts?: { wallet?: unknown; approveMax?: boolean },
150
+ ): Promise<ChainTransaction> {
151
+ return Promise.reject(new Error('Not implemented'))
152
+ }
153
+
154
+ fetchOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
155
+ if (!('receiverObjectIds' in request.message)) {
156
+ throw new Error('Invalid message, not v1.6 Sui')
157
+ }
158
+ // default offchain token data
159
+ return Promise.resolve(request.message.tokenAmounts.map(() => undefined))
160
+ }
161
+
162
+ async executeReport(
163
+ _offRamp: string,
164
+ _execReport: ExecutionReport,
165
+ _opts?: { wallet?: unknown; gasLimit?: number },
166
+ ): Promise<ChainTransaction> {
167
+ return Promise.reject(new Error('Not implemented'))
168
+ }
169
+
170
+ static parse(data: unknown) {
171
+ if (isBytesLike(data)) {
172
+ const parsedExtraArgs = this.decodeExtraArgs(data)
173
+ if (parsedExtraArgs) return parsedExtraArgs
174
+ }
175
+ }
176
+
177
+ async getSupportedTokens(_address: string): Promise<string[]> {
178
+ return Promise.reject(new Error('Not implemented'))
179
+ }
180
+
181
+ async getRegistryTokenConfig(_address: string, _tokenName: string): Promise<never> {
182
+ return Promise.reject(new Error('Not implemented'))
183
+ }
184
+
185
+ async getTokenPoolConfigs(_tokenPool: string): Promise<never> {
186
+ return Promise.reject(new Error('Not implemented'))
187
+ }
188
+
189
+ async getTokenPoolRemotes(_tokenPool: string): Promise<never> {
190
+ return Promise.reject(new Error('Not implemented'))
191
+ }
192
+
193
+ async listFeeTokens(_router: string): Promise<never> {
194
+ return Promise.reject(new Error('Not implemented'))
195
+ }
196
+ }
197
+
198
+ supportedChains[ChainFamily.Sui] = SuiChain
@@ -0,0 +1,22 @@
1
+ import { bcs } from '@mysten/sui/bcs'
2
+ import { concat } from 'ethers'
3
+
4
+ import { type SuiExtraArgsV1, SuiExtraArgsV1Tag } from '../extra-args.ts'
5
+ import type { CCIPMessage_V1_6 } from '../types.ts'
6
+ import { getAddressBytes, getDataBytes } from '../utils.ts'
7
+
8
+ export type CCIPMessage_V1_6_Sui = CCIPMessage_V1_6 & SuiExtraArgsV1
9
+
10
+ export const SuiExtraArgsV1Codec = bcs.struct('SuiExtraArgsV1', {
11
+ gasLimit: bcs.u64(),
12
+ allowOutOfOrderExecution: bcs.bool(),
13
+ tokenReceiver: bcs.vector(bcs.u8()),
14
+ receiverObjectIds: bcs.vector(bcs.vector(bcs.u8())),
15
+ })
16
+
17
+ export function encodeSuiExtraArgsV1(args: SuiExtraArgsV1): string {
18
+ const tokenReceiver = getAddressBytes(args.tokenReceiver)
19
+ const receiverObjectIds = args.receiverObjectIds.map((id) => getDataBytes(id))
20
+ const bcsData = SuiExtraArgsV1Codec.serialize({ ...args, tokenReceiver, receiverObjectIds })
21
+ return concat([SuiExtraArgsV1Tag, bcsData.toBytes()])
22
+ }
@@ -0,0 +1,4 @@
1
+ import type { ChainFamily, ChainStatic } from './chain.ts'
2
+
3
+ // global record; can be mutated when implementing or extending a Chain family support
4
+ export const supportedChains: Partial<{ [F in ChainFamily]: ChainStatic<F> }> = {}