@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,645 @@
1
+ import { type AnchorProvider, type IdlTypes, Program } from '@coral-xyz/anchor'
2
+ import {
3
+ type AccountMeta,
4
+ type Transaction,
5
+ type TransactionInstruction,
6
+ AddressLookupTableAccount,
7
+ AddressLookupTableProgram,
8
+ ComputeBudgetProgram,
9
+ PublicKey,
10
+ SendTransactionError,
11
+ SystemProgram,
12
+ TransactionExpiredBlockheightExceededError,
13
+ TransactionMessage,
14
+ VersionedTransaction,
15
+ } from '@solana/web3.js'
16
+ import BN from 'bn.js'
17
+ import { hexlify } from 'ethers'
18
+
19
+ import type { ExecutionReport } from '../types.ts'
20
+ import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
21
+ import { encodeSolanaOffchainTokenData } from './offchain.ts'
22
+ import type { CCIPMessage_V1_6_Solana } from './types.ts'
23
+ import type { ChainTransaction } from '../chain.ts'
24
+ import { getDataBytes, sleep, toLeArray } from '../utils.ts'
25
+ import { bytesToBuffer, simulateTransaction, simulationProvider } from './utils.ts'
26
+ import './patchBorsh.ts'
27
+
28
+ type ExecStepTx = readonly [reason: string, transactions: VersionedTransaction]
29
+
30
+ type ExecAlt = {
31
+ addressLookupTableAccount: AddressLookupTableAccount
32
+ initialTxs: ExecStepTx[]
33
+ finalTxs: ExecStepTx[]
34
+ }
35
+
36
+ export async function executeReport({
37
+ offrampProgram,
38
+ execReport,
39
+ ...opts
40
+ }: {
41
+ offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
42
+ execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
43
+ gasLimit?: number
44
+ forceLookupTable?: boolean
45
+ forceBuffer?: boolean
46
+ clearLeftoverAccounts?: boolean
47
+ }): Promise<Pick<ChainTransaction, 'hash'>> {
48
+ const provider = offrampProgram.provider as AnchorProvider
49
+ const wallet = provider.wallet
50
+ const connection = provider.connection
51
+
52
+ const execTxs = await buildExecTxToSolana(offrampProgram, execReport, opts?.gasLimit, opts)
53
+
54
+ let execTxSignature: string, signature: string
55
+ for (const [i, [reason, transaction]] of execTxs.entries()) {
56
+ // Refresh the blockhash for each transaction, as the blockhash is only valid for a short time
57
+ // and we spend a lot of time waiting for finalization of the previous transactions.
58
+ transaction.message.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
59
+
60
+ const signed = await wallet.signTransaction(transaction)
61
+
62
+ try {
63
+ signature = await connection.sendTransaction(signed)
64
+
65
+ if (reason === 'exec') execTxSignature = signature
66
+ } catch (e) {
67
+ if (
68
+ e instanceof SendTransactionError &&
69
+ e.logs?.some((log) =>
70
+ log.includes('Error Code: ExecutionReportBufferAlreadyContainsChunk.'),
71
+ )
72
+ ) {
73
+ console.warn(
74
+ `Skipping tx ${i + 1} of ${execTxs.length} because a chunk is already in the buffer.`,
75
+ )
76
+ continue
77
+ } else {
78
+ throw e
79
+ }
80
+ }
81
+
82
+ console.debug(`Confirming tx #${i + 1} of ${execTxs.length}: ${signature} (${reason})...`)
83
+ for (let currentAttempt = 0; ; currentAttempt++) {
84
+ try {
85
+ const latestBlockhash = await connection.getLatestBlockhash()
86
+ await connection.confirmTransaction(
87
+ {
88
+ signature,
89
+ blockhash: latestBlockhash.blockhash,
90
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
91
+ },
92
+ 'confirmed',
93
+ )
94
+ break
95
+ } catch (e) {
96
+ if (currentAttempt < 5 && e instanceof TransactionExpiredBlockheightExceededError) {
97
+ await sleep(1000)
98
+ } else {
99
+ throw e
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ return { hash: execTxSignature! }
106
+ }
107
+
108
+ async function buildExecTxToSolana(
109
+ offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
110
+ execReport: ExecutionReport<CCIPMessage_V1_6_Solana>,
111
+ computeUnitsOverride: number | undefined,
112
+ opts?: { forceLookupTable?: boolean; forceBuffer?: boolean; clearLeftoverAccounts?: boolean },
113
+ ): Promise<ExecStepTx[]> {
114
+ const provider = offrampProgram.provider as AnchorProvider
115
+ offrampProgram = new Program(CCIP_OFFRAMP_IDL, offrampProgram.programId, provider)
116
+ const payerAddress = provider.wallet.publicKey
117
+
118
+ let bufferId
119
+ if (opts?.forceBuffer) {
120
+ // Use messageId for bufferId. This is arbitrary, but easy to track.
121
+ bufferId = bytesToBuffer(execReport.message.header.messageId)
122
+ }
123
+
124
+ const {
125
+ executionReport: preparedReport,
126
+ tokenIndexes,
127
+ accounts,
128
+ addressLookupTables,
129
+ } = await getManuallyExecuteInputs({
130
+ execReport,
131
+ offrampProgram,
132
+ transmitter: payerAddress.toBase58(),
133
+ bufferId,
134
+ })
135
+
136
+ const addressLookupTableAccounts = await Promise.all(
137
+ addressLookupTables.map(async (acc) => {
138
+ const lookupTableAccountInfo = await provider.connection.getAddressLookupTable(acc)
139
+
140
+ if (!lookupTableAccountInfo.value) {
141
+ throw new Error(`Lookup table account not found: ${acc.toBase58()}`)
142
+ }
143
+
144
+ return lookupTableAccountInfo.value
145
+ }),
146
+ )
147
+
148
+ let serializedReport = offrampProgram.coder.types.encode(
149
+ 'ExecutionReportSingleChain',
150
+ preparedReport,
151
+ )
152
+
153
+ const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
154
+
155
+ let alt
156
+ if (opts?.forceLookupTable) {
157
+ alt = await buildLookupTableTxs(provider, accounts)
158
+ addressLookupTableAccounts.push(alt.addressLookupTableAccount)
159
+ }
160
+
161
+ const transactions: ExecStepTx[] = []
162
+ if (bufferId) {
163
+ console.log(`Execute report will be pre-buffered through the offramp. This may take some time.`)
164
+ transactions.push(
165
+ ...(await bufferedTransactionData(
166
+ offrampProgram,
167
+ serializedReport,
168
+ recentBlockhash,
169
+ bufferId,
170
+ opts,
171
+ )),
172
+ )
173
+ serializedReport = Buffer.from([]) // clear 1st param to manuallyExecute method if buffered
174
+ }
175
+
176
+ const execTx = await offrampProgram.methods
177
+ .manuallyExecute(serializedReport, tokenIndexes)
178
+ .accounts({
179
+ config: accounts[0].pubkey,
180
+ referenceAddresses: accounts[1].pubkey,
181
+ sourceChain: accounts[2].pubkey,
182
+ commitReport: accounts[3].pubkey,
183
+ offramp: accounts[4].pubkey,
184
+ allowedOfframp: accounts[5].pubkey,
185
+ authority: accounts[6].pubkey,
186
+ systemProgram: accounts[7].pubkey,
187
+ sysvarInstructions: accounts[8].pubkey,
188
+ rmnRemote: accounts[9].pubkey,
189
+ rmnRemoteCurses: accounts[10].pubkey,
190
+ rmnRemoteConfig: accounts[11].pubkey,
191
+ })
192
+ .remainingAccounts(accounts.slice(12))
193
+ .transaction()
194
+
195
+ computeUnitsOverride ||= Math.ceil(
196
+ 1.1 *
197
+ ((
198
+ await simulateTransaction({
199
+ instructions: execTx.instructions,
200
+ connection: provider.connection,
201
+ payerKey: provider.wallet.publicKey,
202
+ addressLookupTableAccounts,
203
+ computeUnitsOverride,
204
+ })
205
+ ).unitsConsumed || 0),
206
+ )
207
+
208
+ // Add compute budget instruction at the beginning of instructions
209
+ execTx.instructions.unshift(
210
+ ComputeBudgetProgram.setComputeUnitLimit({
211
+ units: computeUnitsOverride,
212
+ }),
213
+ )
214
+
215
+ // actual exec tx
216
+ transactions.push([
217
+ 'exec',
218
+ toVersionedTransaction(
219
+ execTx.instructions,
220
+ provider.wallet.publicKey,
221
+ recentBlockhash,
222
+ addressLookupTableAccounts,
223
+ ),
224
+ ])
225
+
226
+ if (alt) {
227
+ transactions.unshift(...alt.initialTxs)
228
+ transactions.push(...alt.finalTxs)
229
+ }
230
+
231
+ return transactions
232
+ }
233
+
234
+ async function buildLookupTableTxs(
235
+ provider: AnchorProvider,
236
+ accounts: readonly AccountMeta[],
237
+ ): Promise<ExecAlt> {
238
+ const recentSlot = await provider.connection.getSlot('finalized')
239
+
240
+ const [createIx, altAddr] = AddressLookupTableProgram.createLookupTable({
241
+ authority: provider.wallet.publicKey,
242
+ payer: provider.wallet.publicKey,
243
+ recentSlot,
244
+ })
245
+ console.log('Using Address Lookup Table', altAddr.toBase58())
246
+
247
+ const addresses = accounts.map((a) => a.pubkey)
248
+
249
+ if (addresses.length > 256) {
250
+ throw new Error(
251
+ `The number of addresses (${addresses.length}) exceeds the maximum limit imposed by Solana of 256 for Address Lookup Tables`,
252
+ )
253
+ }
254
+
255
+ // 1232 bytes is the max size of a transaction, 32 bytes used for each address.
256
+ // 1232 / 32 ~= 38.5
257
+ const firstChunkLength = 28
258
+ const maxAddressesPerTx = 35
259
+ const extendIxs: TransactionInstruction[] = []
260
+ const ranges: [number, number][] = []
261
+ for (
262
+ let [start, end] = [0, firstChunkLength];
263
+ start < addresses.length;
264
+ [start, end] = [end, end + maxAddressesPerTx]
265
+ ) {
266
+ const addressesChunk = addresses.slice(start, end)
267
+ const extendIx = AddressLookupTableProgram.extendLookupTable({
268
+ payer: provider.wallet.publicKey,
269
+ authority: provider.wallet.publicKey,
270
+ lookupTable: altAddr,
271
+ addresses: addressesChunk,
272
+ })
273
+ extendIxs.push(extendIx)
274
+ ranges.push([start, start + addressesChunk.length - 1])
275
+ }
276
+
277
+ const deactivateIx = AddressLookupTableProgram.deactivateLookupTable({
278
+ lookupTable: altAddr,
279
+ authority: provider.wallet.publicKey,
280
+ })
281
+
282
+ // disable closeTx, to be cleaned in SolanaChain.cleanUpBuffers
283
+ // const closeIx = AddressLookupTableProgram.closeLookupTable({
284
+ // authority: provider.wallet.publicKey,
285
+ // recipient: provider.wallet.publicKey,
286
+ // lookupTable: altAddr,
287
+ // })
288
+
289
+ const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
290
+
291
+ return {
292
+ addressLookupTableAccount: new AddressLookupTableAccount({
293
+ key: altAddr,
294
+ state: {
295
+ deactivationSlot: BigInt(0),
296
+ lastExtendedSlot: recentSlot,
297
+ lastExtendedSlotStartIndex: 0,
298
+ addresses,
299
+ },
300
+ }),
301
+ initialTxs: [
302
+ // first extendIx fits in create tx
303
+ [
304
+ `lookup[create + 0..${ranges[0][1]}]`,
305
+ toVersionedTransaction(
306
+ [createIx, extendIxs[0]],
307
+ provider.wallet.publicKey,
308
+ recentBlockhash,
309
+ ),
310
+ ],
311
+ ...extendIxs
312
+ .slice(1)
313
+ .map<ExecStepTx>((ix, i) => [
314
+ `lookup[${ranges[i + 1][0]}..${ranges[i + 1][1]}]`,
315
+ toVersionedTransaction([ix], provider.wallet.publicKey, recentBlockhash),
316
+ ]),
317
+ ],
318
+ finalTxs: [
319
+ [
320
+ `lookup[deactivate]`,
321
+ toVersionedTransaction([deactivateIx], provider.wallet.publicKey, recentBlockhash),
322
+ ],
323
+ ],
324
+ }
325
+ }
326
+
327
+ async function bufferedTransactionData(
328
+ offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
329
+ serializedReport: Buffer,
330
+ recentBlockhash: string,
331
+ bufferId: Buffer,
332
+ opts?: { clearLeftoverAccounts?: boolean },
333
+ ): Promise<ExecStepTx[]> {
334
+ const provider = offrampProgram.provider as AnchorProvider
335
+
336
+ const [bufferAddress] = PublicKey.findProgramAddressSync(
337
+ [Buffer.from('execution_report_buffer'), bufferId, provider.wallet.publicKey.toBuffer()],
338
+ offrampProgram.programId,
339
+ )
340
+
341
+ const [configPDA] = PublicKey.findProgramAddressSync(
342
+ [Buffer.from('config')],
343
+ offrampProgram.programId,
344
+ )
345
+
346
+ console.log(
347
+ `The bufferID is ${hexlify(bufferId)}, and the PDA address for the buffer is ${bufferAddress.toString()}\nIf this buffering process is aborted, remember to cleanUp the account to recover locked rent.`,
348
+ )
349
+
350
+ const chunkSize = 800
351
+ const bufferedExecTxs: ExecStepTx[] = []
352
+
353
+ const bufferingAccounts = {
354
+ executionReportBuffer: bufferAddress,
355
+ config: configPDA,
356
+ authority: provider.wallet.publicKey,
357
+ systemProgram: SystemProgram.programId,
358
+ }
359
+
360
+ if (opts?.clearLeftoverAccounts) {
361
+ const clearTx = await offrampProgram.methods
362
+ .closeExecutionReportBuffer(bufferId)
363
+ .accounts(bufferingAccounts)
364
+ .transaction()
365
+
366
+ bufferedExecTxs.push([
367
+ 'buffering[clear]',
368
+ toVersionedTransaction(clearTx, provider.wallet.publicKey, recentBlockhash),
369
+ ])
370
+ }
371
+
372
+ const numChunks = Math.ceil(serializedReport.length / chunkSize)
373
+ for (let i = 0; i < serializedReport.length; i += chunkSize) {
374
+ const end = Math.min(i + chunkSize, serializedReport.length)
375
+ const chunk: Buffer = serializedReport.subarray(i, end)
376
+
377
+ const appendTx = await offrampProgram.methods
378
+ .bufferExecutionReport(bufferId, serializedReport.length, chunk, i / chunkSize, numChunks)
379
+ .accounts(bufferingAccounts)
380
+ .transaction()
381
+ bufferedExecTxs.push([
382
+ `buffering[${i / chunkSize}=${end - i}B]`,
383
+ toVersionedTransaction(appendTx, provider.wallet.publicKey, recentBlockhash),
384
+ ])
385
+ }
386
+
387
+ return bufferedExecTxs
388
+ }
389
+
390
+ function toVersionedTransaction(
391
+ input: Transaction | TransactionInstruction[],
392
+ payerKey: PublicKey,
393
+ recentBlockhash: string,
394
+ addressLookupTableAccounts?: AddressLookupTableAccount[],
395
+ ): VersionedTransaction {
396
+ const instructions: TransactionInstruction[] = Array.isArray(input) ? input : input.instructions
397
+
398
+ const message = new TransactionMessage({ payerKey, recentBlockhash, instructions })
399
+ return new VersionedTransaction(message.compileToV0Message(addressLookupTableAccounts))
400
+ }
401
+
402
+ async function getManuallyExecuteInputs({
403
+ execReport,
404
+ offrampProgram,
405
+ transmitter,
406
+ bufferId,
407
+ }: {
408
+ execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
409
+ offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
410
+ transmitter: string
411
+ bufferId?: Buffer
412
+ }) {
413
+ const executionReport = prepareExecutionReport(execReport)
414
+
415
+ const messageAccountMetas = execReport.message.accounts.map((acc, index) => {
416
+ const bitmap = BigInt(execReport.message.accountIsWritableBitmap)
417
+ const isWritable = (bitmap & (1n << BigInt(index))) !== 0n
418
+
419
+ return {
420
+ pubkey: new PublicKey(acc),
421
+ isSigner: false,
422
+ isWritable,
423
+ }
424
+ })
425
+
426
+ // Convert message.receiver to AccountMeta and prepend to messaging accounts
427
+ const receiverAccountMeta = {
428
+ pubkey: new PublicKey(execReport.message.receiver),
429
+ isSigner: false,
430
+ isWritable: false,
431
+ }
432
+
433
+ console.debug('Message receiver:', execReport.message.receiver)
434
+
435
+ // Prepend receiver to messaging accounts
436
+ const messagingAccounts: AccountMeta[] =
437
+ execReport.message.receiver !== PublicKey.default.toBase58()
438
+ ? [receiverAccountMeta, ...messageAccountMetas]
439
+ : [] // on plain token transfers, there are no messaging accounts
440
+ const tokenTransferAndOffchainData: IdlTypes<
441
+ typeof CCIP_OFFRAMP_IDL
442
+ >['TokenTransferAndOffchainData'][] = execReport.message.tokenAmounts.map((ta, idx) => ({
443
+ data: bytesToBuffer(encodeSolanaOffchainTokenData(execReport.offchainTokenData[idx])),
444
+ transfer: {
445
+ sourcePoolAddress: bytesToBuffer(ta.sourcePoolAddress),
446
+ destTokenAddress: new PublicKey(ta.destTokenAddress),
447
+ destGasAmount: Number(ta.destGasAmount),
448
+ extraData: bytesToBuffer(ta.extraData || '0x'),
449
+ amount: {
450
+ leBytes: Array.from(toLeArray(ta.amount, 32)),
451
+ },
452
+ },
453
+ }))
454
+
455
+ const {
456
+ accounts,
457
+ addressLookupTableAccounts: addressLookupTables,
458
+ tokenIndexes,
459
+ } = await autoDeriveExecutionAccounts({
460
+ offrampProgram,
461
+ originalSender: bytesToBuffer(execReport.message.sender),
462
+ transmitter: new PublicKey(transmitter),
463
+ messagingAccounts,
464
+ sourceChainSelector: execReport.message.header.sourceChainSelector,
465
+ tokenTransferAndOffchainData,
466
+ merkleRoot: bytesToBuffer(execReport.merkleRoot),
467
+ bufferId,
468
+ tokenReceiver: new PublicKey(execReport.message.tokenReceiver),
469
+ })
470
+
471
+ return {
472
+ executionReport,
473
+ tokenIndexes,
474
+ accounts,
475
+ addressLookupTables,
476
+ }
477
+ }
478
+
479
+ function prepareExecutionReport({
480
+ message,
481
+ offchainTokenData,
482
+ proofs,
483
+ }: ExecutionReport<CCIPMessage_V1_6_Solana>): IdlTypes<
484
+ typeof CCIP_OFFRAMP_IDL
485
+ >['ExecutionReportSingleChain'] {
486
+ return {
487
+ sourceChainSelector: new BN(message.header.sourceChainSelector.toString()),
488
+ message: {
489
+ header: {
490
+ messageId: Array.from(getDataBytes(message.header.messageId)),
491
+ sourceChainSelector: new BN(message.header.sourceChainSelector),
492
+ destChainSelector: new BN(message.header.destChainSelector),
493
+ sequenceNumber: new BN(message.header.sequenceNumber),
494
+ nonce: new BN(message.header.nonce),
495
+ },
496
+ sender: bytesToBuffer(message.sender),
497
+ data: bytesToBuffer(message.data),
498
+ tokenReceiver: new PublicKey(message.tokenReceiver),
499
+ tokenAmounts: message.tokenAmounts.map((token) => ({
500
+ sourcePoolAddress: bytesToBuffer(token.sourcePoolAddress),
501
+ destTokenAddress: new PublicKey(token.destTokenAddress),
502
+ destGasAmount: Number(token.destGasAmount),
503
+ extraData: bytesToBuffer(token.extraData),
504
+ amount: {
505
+ leBytes: Array.from(toLeArray(token.amount, 32)),
506
+ },
507
+ })),
508
+ extraArgs: {
509
+ computeUnits: Number(message.computeUnits),
510
+ isWritableBitmap: new BN(message.accountIsWritableBitmap),
511
+ },
512
+ },
513
+ offchainTokenData: offchainTokenData.map((d) =>
514
+ bytesToBuffer(encodeSolanaOffchainTokenData(d)),
515
+ ),
516
+ proofs: proofs.map((p) => Array.from(getDataBytes(p))),
517
+ }
518
+ }
519
+
520
+ async function autoDeriveExecutionAccounts({
521
+ offrampProgram,
522
+ originalSender,
523
+ transmitter,
524
+ messagingAccounts,
525
+ sourceChainSelector,
526
+ tokenTransferAndOffchainData,
527
+ merkleRoot,
528
+ tokenReceiver,
529
+ bufferId,
530
+ }: {
531
+ offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
532
+ originalSender: Buffer
533
+ transmitter: PublicKey
534
+ messagingAccounts: IdlTypes<typeof CCIP_OFFRAMP_IDL>['CcipAccountMeta'][]
535
+ sourceChainSelector: bigint
536
+ tokenTransferAndOffchainData: Array<
537
+ IdlTypes<typeof CCIP_OFFRAMP_IDL>['TokenTransferAndOffchainData']
538
+ >
539
+ merkleRoot: Buffer
540
+ tokenReceiver: PublicKey
541
+ bufferId?: Buffer
542
+ }) {
543
+ const derivedAccounts: AccountMeta[] = []
544
+ const lookupTables: PublicKey[] = []
545
+ const tokenIndices: number[] = []
546
+ let askWith: AccountMeta[] = []
547
+ let stage = 'Start'
548
+ let tokenIndex = 0
549
+
550
+ const [configPDA] = PublicKey.findProgramAddressSync(
551
+ [Buffer.from('config')],
552
+ offrampProgram.programId,
553
+ )
554
+
555
+ while (true) {
556
+ const params: IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsExecuteParams'] = {
557
+ executeCaller: transmitter,
558
+ messageAccounts: messagingAccounts,
559
+ sourceChainSelector: new BN(sourceChainSelector.toString()),
560
+ originalSender: originalSender,
561
+ tokenTransfers: tokenTransferAndOffchainData,
562
+ merkleRoot: Array.from(merkleRoot),
563
+ bufferId: bufferId ?? Buffer.from([]),
564
+ tokenReceiver,
565
+ }
566
+
567
+ // Workarounds for tx-too-large issues during account derivation
568
+ if (/BuildDynamicAccounts/.test(stage)) {
569
+ params.messageAccounts = [] // omit messaging accounts
570
+ } else {
571
+ params.tokenTransfers = tokenTransferAndOffchainData.map((tt) => ({
572
+ ...tt,
573
+ data: Buffer.from([]), // omit offchain token data
574
+ }))
575
+ }
576
+
577
+ // copy of Program which avoids signing every simulation
578
+ const readOnlyProgram = new Program(
579
+ offrampProgram.idl,
580
+ offrampProgram.programId,
581
+ simulationProvider(offrampProgram.provider.connection, transmitter),
582
+ )
583
+ // Execute as a view call to get the response
584
+ const response = (await readOnlyProgram.methods
585
+ .deriveAccountsExecute(params, stage)
586
+ .accounts({
587
+ config: configPDA,
588
+ })
589
+ .remainingAccounts(askWith)
590
+ .view()
591
+ .catch((error: unknown) => {
592
+ console.error('Error deriving accounts:', error)
593
+ console.error('Params:', params)
594
+ throw error as Error
595
+ })) as IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsResponse']
596
+
597
+ // Check if we're at the start of a token transfer
598
+ const isStartOfToken = /^TokenTransferStaticAccounts\/\d+\/0$/.test(response.currentStage)
599
+ if (isStartOfToken) {
600
+ const numKnownAccounts = 12
601
+ tokenIndices.push(tokenIndex - numKnownAccounts)
602
+ }
603
+
604
+ // Update token index
605
+ tokenIndex += response.accountsToSave.length
606
+
607
+ console.debug('After stage', stage, 'tokenIndices', tokenIndices, 'nextTokenIndex', tokenIndex)
608
+
609
+ // Collect the derived accounts
610
+ for (const meta of response.accountsToSave) {
611
+ derivedAccounts.push({
612
+ pubkey: meta.pubkey,
613
+ isWritable: meta.isWritable,
614
+ isSigner: meta.isSigner,
615
+ })
616
+ }
617
+
618
+ // Prepare askWith for next iteration
619
+ askWith = response.askAgainWith.map((meta) => ({
620
+ pubkey: meta.pubkey,
621
+ isWritable: meta.isWritable,
622
+ isSigner: meta.isSigner,
623
+ }))
624
+
625
+ // Collect lookup tables
626
+ lookupTables.push(...response.lookUpTablesToSave)
627
+
628
+ // Check if derivation is complete
629
+ if (!response.nextStage || response.nextStage.length === 0) {
630
+ break
631
+ }
632
+
633
+ stage = response.nextStage
634
+ }
635
+
636
+ console.debug('Resulting derived accounts:', derivedAccounts)
637
+ console.debug('Resulting derived address lookup tables:', lookupTables)
638
+ console.debug('Resulting derived token indexes:', tokenIndices)
639
+
640
+ return {
641
+ accounts: derivedAccounts,
642
+ addressLookupTableAccounts: lookupTables,
643
+ tokenIndexes: Buffer.from(tokenIndices),
644
+ }
645
+ }