@chainlink/ccip-sdk 0.91.0 → 0.92.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 (273) hide show
  1. package/README.md +127 -80
  2. package/dist/aptos/hasher.d.ts.map +1 -1
  3. package/dist/aptos/hasher.js +7 -6
  4. package/dist/aptos/hasher.js.map +1 -1
  5. package/dist/aptos/index.d.ts +7 -2
  6. package/dist/aptos/index.d.ts.map +1 -1
  7. package/dist/aptos/index.js +29 -20
  8. package/dist/aptos/index.js.map +1 -1
  9. package/dist/aptos/logs.d.ts +5 -3
  10. package/dist/aptos/logs.d.ts.map +1 -1
  11. package/dist/aptos/logs.js +64 -27
  12. package/dist/aptos/logs.js.map +1 -1
  13. package/dist/aptos/token.d.ts.map +1 -1
  14. package/dist/aptos/token.js +2 -1
  15. package/dist/aptos/token.js.map +1 -1
  16. package/dist/aptos/types.js +6 -6
  17. package/dist/aptos/types.js.map +1 -1
  18. package/dist/chain.d.ts +36 -11
  19. package/dist/chain.d.ts.map +1 -1
  20. package/dist/chain.js +34 -2
  21. package/dist/chain.js.map +1 -1
  22. package/dist/commits.d.ts +2 -3
  23. package/dist/commits.d.ts.map +1 -1
  24. package/dist/commits.js +19 -8
  25. package/dist/commits.js.map +1 -1
  26. package/dist/errors/CCIPError.d.ts +48 -0
  27. package/dist/errors/CCIPError.d.ts.map +1 -0
  28. package/dist/errors/CCIPError.js +65 -0
  29. package/dist/errors/CCIPError.js.map +1 -0
  30. package/dist/errors/codes.d.ts +120 -0
  31. package/dist/errors/codes.d.ts.map +1 -0
  32. package/dist/errors/codes.js +156 -0
  33. package/dist/errors/codes.js.map +1 -0
  34. package/dist/errors/index.d.ts +26 -0
  35. package/dist/errors/index.d.ts.map +1 -0
  36. package/dist/errors/index.js +51 -0
  37. package/dist/errors/index.js.map +1 -0
  38. package/dist/errors/recovery.d.ts +6 -0
  39. package/dist/errors/recovery.d.ts.map +1 -0
  40. package/dist/errors/recovery.js +118 -0
  41. package/dist/errors/recovery.js.map +1 -0
  42. package/dist/errors/specialized.d.ts +637 -0
  43. package/dist/errors/specialized.d.ts.map +1 -0
  44. package/dist/errors/specialized.js +1298 -0
  45. package/dist/errors/specialized.js.map +1 -0
  46. package/dist/errors/utils.d.ts +11 -0
  47. package/dist/errors/utils.d.ts.map +1 -0
  48. package/dist/errors/utils.js +61 -0
  49. package/dist/errors/utils.js.map +1 -0
  50. package/dist/evm/abi/CommitStore_1_5.js +1 -1
  51. package/dist/evm/abi/LockReleaseTokenPool_1_5.js +1 -1
  52. package/dist/evm/abi/OffRamp_1_5.js +1 -1
  53. package/dist/evm/abi/OnRamp_1_5.js +1 -1
  54. package/dist/evm/abi/PriceRegistry_1_2.d.ts +443 -0
  55. package/dist/evm/abi/PriceRegistry_1_2.d.ts.map +1 -0
  56. package/dist/evm/abi/PriceRegistry_1_2.js +439 -0
  57. package/dist/evm/abi/PriceRegistry_1_2.js.map +1 -0
  58. package/dist/evm/const.d.ts +1 -0
  59. package/dist/evm/const.d.ts.map +1 -1
  60. package/dist/evm/const.js +2 -0
  61. package/dist/evm/const.js.map +1 -1
  62. package/dist/evm/hasher.d.ts.map +1 -1
  63. package/dist/evm/hasher.js +7 -6
  64. package/dist/evm/hasher.js.map +1 -1
  65. package/dist/evm/index.d.ts +9 -13
  66. package/dist/evm/index.d.ts.map +1 -1
  67. package/dist/evm/index.js +85 -68
  68. package/dist/evm/index.js.map +1 -1
  69. package/dist/evm/logs.d.ts.map +1 -1
  70. package/dist/evm/logs.js +47 -16
  71. package/dist/evm/logs.js.map +1 -1
  72. package/dist/evm/messages.d.ts +7 -6
  73. package/dist/evm/messages.d.ts.map +1 -1
  74. package/dist/evm/offchain.js +1 -1
  75. package/dist/evm/offchain.js.map +1 -1
  76. package/dist/evm/types.d.ts +10 -0
  77. package/dist/evm/types.d.ts.map +1 -0
  78. package/dist/evm/types.js +2 -0
  79. package/dist/evm/types.js.map +1 -0
  80. package/dist/execution.d.ts.map +1 -1
  81. package/dist/execution.js +9 -5
  82. package/dist/execution.js.map +1 -1
  83. package/dist/extra-args.d.ts.map +1 -1
  84. package/dist/extra-args.js +4 -3
  85. package/dist/extra-args.js.map +1 -1
  86. package/dist/gas.d.ts.map +1 -1
  87. package/dist/gas.js +3 -2
  88. package/dist/gas.js.map +1 -1
  89. package/dist/hasher/hasher.d.ts.map +1 -1
  90. package/dist/hasher/hasher.js +2 -1
  91. package/dist/hasher/hasher.js.map +1 -1
  92. package/dist/hasher/merklemulti.d.ts.map +1 -1
  93. package/dist/hasher/merklemulti.js +9 -8
  94. package/dist/hasher/merklemulti.js.map +1 -1
  95. package/dist/index.d.ts +5 -2
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +6 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/offchain.d.ts.map +1 -1
  100. package/dist/offchain.js +5 -8
  101. package/dist/offchain.js.map +1 -1
  102. package/dist/requests.d.ts +1 -1
  103. package/dist/requests.d.ts.map +1 -1
  104. package/dist/requests.js +37 -43
  105. package/dist/requests.js.map +1 -1
  106. package/dist/selectors.d.ts.map +1 -1
  107. package/dist/selectors.js +22 -0
  108. package/dist/selectors.js.map +1 -1
  109. package/dist/solana/cleanup.d.ts +2 -2
  110. package/dist/solana/cleanup.d.ts.map +1 -1
  111. package/dist/solana/cleanup.js +2 -3
  112. package/dist/solana/cleanup.js.map +1 -1
  113. package/dist/solana/exec.d.ts.map +1 -1
  114. package/dist/solana/exec.js +12 -12
  115. package/dist/solana/exec.js.map +1 -1
  116. package/dist/solana/hasher.d.ts.map +1 -1
  117. package/dist/solana/hasher.js +6 -5
  118. package/dist/solana/hasher.js.map +1 -1
  119. package/dist/solana/index.d.ts +30 -13
  120. package/dist/solana/index.d.ts.map +1 -1
  121. package/dist/solana/index.js +96 -143
  122. package/dist/solana/index.js.map +1 -1
  123. package/dist/solana/logs.d.ts +15 -0
  124. package/dist/solana/logs.d.ts.map +1 -0
  125. package/dist/solana/logs.js +106 -0
  126. package/dist/solana/logs.js.map +1 -0
  127. package/dist/solana/offchain.d.ts.map +1 -1
  128. package/dist/solana/offchain.js +6 -5
  129. package/dist/solana/offchain.js.map +1 -1
  130. package/dist/solana/patchBorsh.d.ts.map +1 -1
  131. package/dist/solana/patchBorsh.js +3 -2
  132. package/dist/solana/patchBorsh.js.map +1 -1
  133. package/dist/solana/send.d.ts.map +1 -1
  134. package/dist/solana/send.js +8 -7
  135. package/dist/solana/send.js.map +1 -1
  136. package/dist/solana/utils.d.ts +7 -8
  137. package/dist/solana/utils.d.ts.map +1 -1
  138. package/dist/solana/utils.js +23 -11
  139. package/dist/solana/utils.js.map +1 -1
  140. package/dist/sui/discovery.d.ts +18 -0
  141. package/dist/sui/discovery.d.ts.map +1 -0
  142. package/dist/sui/discovery.js +116 -0
  143. package/dist/sui/discovery.js.map +1 -0
  144. package/dist/sui/events.d.ts +36 -0
  145. package/dist/sui/events.d.ts.map +1 -0
  146. package/dist/sui/events.js +179 -0
  147. package/dist/sui/events.js.map +1 -0
  148. package/dist/sui/hasher.d.ts.map +1 -1
  149. package/dist/sui/hasher.js +6 -5
  150. package/dist/sui/hasher.js.map +1 -1
  151. package/dist/sui/index.d.ts +69 -41
  152. package/dist/sui/index.d.ts.map +1 -1
  153. package/dist/sui/index.js +402 -65
  154. package/dist/sui/index.js.map +1 -1
  155. package/dist/sui/manuallyExec/encoder.d.ts +8 -0
  156. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -0
  157. package/dist/sui/manuallyExec/encoder.js +76 -0
  158. package/dist/sui/manuallyExec/encoder.js.map +1 -0
  159. package/dist/sui/manuallyExec/index.d.ts +37 -0
  160. package/dist/sui/manuallyExec/index.d.ts.map +1 -0
  161. package/dist/sui/manuallyExec/index.js +81 -0
  162. package/dist/sui/manuallyExec/index.js.map +1 -0
  163. package/dist/sui/objects.d.ts +46 -0
  164. package/dist/sui/objects.d.ts.map +1 -0
  165. package/dist/sui/objects.js +259 -0
  166. package/dist/sui/objects.js.map +1 -0
  167. package/dist/ton/bindings/offramp.d.ts +48 -0
  168. package/dist/ton/bindings/offramp.d.ts.map +1 -0
  169. package/dist/ton/bindings/offramp.js +63 -0
  170. package/dist/ton/bindings/offramp.js.map +1 -0
  171. package/dist/ton/bindings/onramp.d.ts +40 -0
  172. package/dist/ton/bindings/onramp.d.ts.map +1 -0
  173. package/dist/ton/bindings/onramp.js +51 -0
  174. package/dist/ton/bindings/onramp.js.map +1 -0
  175. package/dist/ton/bindings/router.d.ts +47 -0
  176. package/dist/ton/bindings/router.d.ts.map +1 -0
  177. package/dist/ton/bindings/router.js +51 -0
  178. package/dist/ton/bindings/router.js.map +1 -0
  179. package/dist/ton/exec.d.ts +18 -0
  180. package/dist/ton/exec.d.ts.map +1 -0
  181. package/dist/ton/exec.js +28 -0
  182. package/dist/ton/exec.js.map +1 -0
  183. package/dist/ton/hasher.d.ts +27 -0
  184. package/dist/ton/hasher.d.ts.map +1 -0
  185. package/dist/ton/hasher.js +134 -0
  186. package/dist/ton/hasher.js.map +1 -0
  187. package/dist/ton/index.d.ts +247 -0
  188. package/dist/ton/index.d.ts.map +1 -0
  189. package/dist/ton/index.js +781 -0
  190. package/dist/ton/index.js.map +1 -0
  191. package/dist/ton/logs.d.ts +26 -0
  192. package/dist/ton/logs.d.ts.map +1 -0
  193. package/dist/ton/logs.js +126 -0
  194. package/dist/ton/logs.js.map +1 -0
  195. package/dist/ton/types.d.ts +37 -0
  196. package/dist/ton/types.d.ts.map +1 -0
  197. package/dist/ton/types.js +92 -0
  198. package/dist/ton/types.js.map +1 -0
  199. package/dist/ton/utils.d.ts +67 -0
  200. package/dist/ton/utils.d.ts.map +1 -0
  201. package/dist/ton/utils.js +425 -0
  202. package/dist/ton/utils.js.map +1 -0
  203. package/dist/types.d.ts +4 -2
  204. package/dist/types.d.ts.map +1 -1
  205. package/dist/types.js +1 -0
  206. package/dist/types.js.map +1 -1
  207. package/dist/utils.d.ts +10 -0
  208. package/dist/utils.d.ts.map +1 -1
  209. package/dist/utils.js +52 -17
  210. package/dist/utils.js.map +1 -1
  211. package/package.json +12 -10
  212. package/src/aptos/hasher.ts +10 -6
  213. package/src/aptos/index.ts +50 -31
  214. package/src/aptos/logs.ts +85 -29
  215. package/src/aptos/token.ts +5 -1
  216. package/src/aptos/types.ts +6 -6
  217. package/src/chain.ts +83 -12
  218. package/src/commits.ts +23 -11
  219. package/src/errors/CCIPError.ts +86 -0
  220. package/src/errors/codes.ts +179 -0
  221. package/src/errors/index.ts +175 -0
  222. package/src/errors/recovery.ts +170 -0
  223. package/src/errors/specialized.ts +1655 -0
  224. package/src/errors/utils.ts +73 -0
  225. package/src/evm/abi/CommitStore_1_5.ts +1 -1
  226. package/src/evm/abi/LockReleaseTokenPool_1_5.ts +1 -1
  227. package/src/evm/abi/OffRamp_1_5.ts +1 -1
  228. package/src/evm/abi/OnRamp_1_5.ts +1 -1
  229. package/src/evm/abi/PriceRegistry_1_2.ts +438 -0
  230. package/src/evm/const.ts +2 -0
  231. package/src/evm/hasher.ts +7 -6
  232. package/src/evm/index.ts +104 -86
  233. package/src/evm/logs.ts +64 -16
  234. package/src/evm/messages.ts +14 -14
  235. package/src/evm/offchain.ts +1 -1
  236. package/src/evm/types.ts +11 -0
  237. package/src/execution.ts +13 -9
  238. package/src/extra-args.ts +4 -3
  239. package/src/gas.ts +10 -3
  240. package/src/hasher/hasher.ts +2 -1
  241. package/src/hasher/merklemulti.ts +18 -8
  242. package/src/index.ts +14 -2
  243. package/src/offchain.ts +10 -14
  244. package/src/requests.ts +51 -53
  245. package/src/selectors.ts +23 -0
  246. package/src/solana/cleanup.ts +2 -4
  247. package/src/solana/exec.ts +13 -13
  248. package/src/solana/hasher.ts +9 -5
  249. package/src/solana/index.ts +126 -200
  250. package/src/solana/logs.ts +155 -0
  251. package/src/solana/offchain.ts +10 -7
  252. package/src/solana/patchBorsh.ts +3 -2
  253. package/src/solana/send.ts +14 -7
  254. package/src/solana/utils.ts +31 -17
  255. package/src/sui/discovery.ts +163 -0
  256. package/src/sui/events.ts +328 -0
  257. package/src/sui/hasher.ts +6 -5
  258. package/src/sui/index.ts +528 -80
  259. package/src/sui/manuallyExec/encoder.ts +88 -0
  260. package/src/sui/manuallyExec/index.ts +137 -0
  261. package/src/sui/objects.ts +358 -0
  262. package/src/ton/bindings/offramp.ts +96 -0
  263. package/src/ton/bindings/onramp.ts +72 -0
  264. package/src/ton/bindings/router.ts +65 -0
  265. package/src/ton/exec.ts +44 -0
  266. package/src/ton/hasher.ts +184 -0
  267. package/src/ton/index.ts +989 -0
  268. package/src/ton/logs.ts +157 -0
  269. package/src/ton/types.ts +143 -0
  270. package/src/ton/utils.ts +514 -0
  271. package/src/types.ts +6 -2
  272. package/src/utils.ts +58 -23
  273. package/tsconfig.json +2 -1
@@ -0,0 +1,157 @@
1
+ import { Address } from '@ton/core'
2
+ import type { TonClient4 } from '@ton/ton'
3
+
4
+ import type { LogFilter } from '../chain.ts'
5
+ import { CCIPArgumentInvalidError } from '../errors/specialized.ts'
6
+ import type { Log_ } from '../types.ts'
7
+
8
+ /** Decoder functions passed to fetchLogs to identify and parse TON log events avoiding circular imports */
9
+ export interface LogDecoders {
10
+ /** Try to decode as CCIP message, returns messageId if successful */
11
+ tryDecodeAsMessage: (log: Pick<Log_, 'data'>) => { messageId: string } | undefined
12
+ /** Try to decode as commit report, returns truthy if successful */
13
+ tryDecodeAsCommit: (log: Pick<Log_, 'data'>) => unknown[] | undefined
14
+ }
15
+
16
+ /**
17
+ * Fetches logs from a TON address by iterating through account transactions.
18
+ *
19
+ * Note: For TON, `startBlock` and `endBlock` in opts represent logical time (lt),
20
+ * not block sequence numbers. This is because TON transaction APIs are indexed by lt.
21
+ * The lt is monotonically increasing per account and suitable for ordering.
22
+ *
23
+ * @param provider - TonClient4 instance
24
+ * @param opts - Log filter options (startBlock/endBlock are lt values)
25
+ * @param ltTimestampCache - Cache mapping lt to Unix timestamp
26
+ * @param decoders - Message decoder functions
27
+ */
28
+ export async function* fetchLogs(
29
+ provider: TonClient4,
30
+ opts: LogFilter,
31
+ ltTimestampCache: Map<number, number>,
32
+ decoders: LogDecoders,
33
+ ): AsyncIterableIterator<Log_> {
34
+ if (!opts.address) {
35
+ throw new CCIPArgumentInvalidError('address', 'Address is required for TON log filtering')
36
+ }
37
+
38
+ const address = Address.parse(opts.address)
39
+ const searchForward = !!(opts.startBlock || opts.startTime)
40
+
41
+ // Get the latest block for account state lookup
42
+ const lastBlock = await provider.getLastBlock()
43
+
44
+ // Get account state to find the last transaction
45
+ const account = await provider.getAccountLite(lastBlock.last.seqno, address)
46
+ if (!account.account.last) {
47
+ return // No transactions
48
+ }
49
+
50
+ // Pagination cursor
51
+ let cursorLt: bigint = BigInt(account.account.last.lt)
52
+ let cursorHash: Buffer = Buffer.from(account.account.last.hash, 'base64')
53
+
54
+ const collectedLogs: Log_[] = []
55
+ let isFirstBatch = true
56
+
57
+ while (true) {
58
+ const txs = await provider.getAccountTransactions(address, cursorLt, cursorHash)
59
+ if (!txs || txs.length === 0) break
60
+
61
+ // Skip first tx when paginating (it's the same as last from previous batch)
62
+ const startIdx = isFirstBatch ? 0 : 1
63
+ isFirstBatch = false
64
+
65
+ for (let i = startIdx; i < txs.length; i++) {
66
+ const { tx } = txs[i]
67
+ const txLt = Number(tx.lt)
68
+ const timestamp = tx.now
69
+
70
+ // Cache lt → timestamp
71
+ ltTimestampCache.set(txLt, timestamp)
72
+
73
+ // Range filters
74
+ if (opts.startBlock && typeof opts.startBlock === 'number' && txLt < opts.startBlock) {
75
+ if (searchForward) yield* collectedLogs.reverse()
76
+ return
77
+ }
78
+ if (opts.startTime && timestamp < opts.startTime) {
79
+ if (searchForward) yield* collectedLogs.reverse()
80
+ return
81
+ }
82
+ if (opts.endBlock && typeof opts.endBlock === 'number' && txLt > opts.endBlock) {
83
+ continue
84
+ }
85
+
86
+ // Extract logs from external-out messages
87
+ const compositeHash = `${address.toRawString()}:${tx.lt}:${tx.hash().toString('hex')}`
88
+ let index = 0
89
+
90
+ for (const msg of tx.outMessages.values()) {
91
+ if (msg.info.type !== 'external-out') {
92
+ index++
93
+ continue
94
+ }
95
+
96
+ const data = msg.body.toBoc().toString('base64')
97
+ const topicFilter = opts.topics?.[0]
98
+
99
+ // Try to identify log type and build topics array
100
+ const topics: string[] = []
101
+
102
+ if (topicFilter === 'CommitReportAccepted') {
103
+ // Looking for commits - skip if not a valid commit
104
+ if (!decoders.tryDecodeAsCommit({ data })) {
105
+ index++
106
+ continue
107
+ }
108
+ topics.push('CommitReportAccepted')
109
+ } else {
110
+ // Try to decode as CCIP message
111
+ const message = decoders.tryDecodeAsMessage({ data })
112
+ if (topicFilter && !message) {
113
+ // Topic filter set but couldn't decode as message - skip
114
+ index++
115
+ continue
116
+ }
117
+ if (message) {
118
+ topics.push('CCIPMessageSent')
119
+ }
120
+ }
121
+
122
+ const log: Log_ = {
123
+ address: address.toRawString(),
124
+ topics,
125
+ data,
126
+ blockNumber: txLt,
127
+ transactionHash: compositeHash,
128
+ index,
129
+ }
130
+
131
+ if (searchForward) {
132
+ collectedLogs.push(log)
133
+ } else {
134
+ yield log
135
+ }
136
+ index++
137
+ }
138
+ }
139
+
140
+ // Update pagination cursor
141
+ if (txs.length < 2) break
142
+ const lastTx = txs[txs.length - 1].tx
143
+ cursorLt = lastTx.lt
144
+ cursorHash = Buffer.from(lastTx.hash())
145
+
146
+ // Early exit if past start boundary
147
+ if (
148
+ opts.startBlock &&
149
+ typeof opts.startBlock === 'number' &&
150
+ Number(cursorLt) < opts.startBlock
151
+ )
152
+ break
153
+ if (opts.startTime && lastTx.now < opts.startTime) break
154
+ }
155
+
156
+ if (searchForward) yield* collectedLogs.reverse()
157
+ }
@@ -0,0 +1,143 @@
1
+ import { type Builder, Address, Cell, beginCell } from '@ton/core'
2
+ import type { KeyPair } from '@ton/crypto'
3
+ import type { WalletContractV4 } from '@ton/ton'
4
+ import { toBigInt } from 'ethers'
5
+
6
+ import { CCIPDataFormatUnsupportedError } from '../errors/specialized.ts'
7
+ import type { EVMExtraArgsV2 } from '../extra-args.ts'
8
+ import type { CCIPMessage_V1_6, ChainFamily, ExecutionReport } from '../types.ts'
9
+ import { bytesToBuffer } from '../utils.ts'
10
+
11
+ /** TON-specific CCIP v1.6 message type with EVMExtraArgsV2 (GenericExtraArgsV2) */
12
+ export type CCIPMessage_V1_6_TON = CCIPMessage_V1_6 & EVMExtraArgsV2
13
+
14
+ /** Opcode for OffRamp_ManuallyExecute message on TON */
15
+ export const MANUALLY_EXECUTE_OPCODE = 0xa00785cf
16
+
17
+ /**
18
+ * TON wallet with keypair for signing transactions
19
+ */
20
+ export interface TONWallet {
21
+ contract: WalletContractV4
22
+ keyPair: KeyPair
23
+ }
24
+
25
+ /**
26
+ * Unsigned TON transaction data.
27
+ * Contains the payload needed to construct a transaction.
28
+ * Value is determined at execution time, not included here.
29
+ */
30
+ export type UnsignedTONTx = {
31
+ family: typeof ChainFamily.TON
32
+ /** Target contract address */
33
+ to: string
34
+ /** Message payload as BOC-serialized Cell */
35
+ body: Cell
36
+ }
37
+
38
+ /** Typeguard for TON Wallet */
39
+ export function isTONWallet(wallet: unknown): wallet is TONWallet {
40
+ return (
41
+ typeof wallet === 'object' &&
42
+ wallet !== null &&
43
+ 'contract' in wallet &&
44
+ 'keyPair' in wallet &&
45
+ typeof wallet.contract === 'object' &&
46
+ wallet.contract !== null &&
47
+ 'address' in wallet.contract &&
48
+ typeof wallet.keyPair === 'object' &&
49
+ wallet.keyPair !== null &&
50
+ 'secretKey' in wallet.keyPair
51
+ )
52
+ }
53
+
54
+ // asSnakeData helper for encoding variable-length arrays
55
+ function asSnakeData<T>(array: T[], builderFn: (item: T) => Builder): Cell {
56
+ const cells: Builder[] = []
57
+ let builder = beginCell()
58
+
59
+ for (const value of array) {
60
+ const itemBuilder = builderFn(value)
61
+ if (itemBuilder.refs > 3) {
62
+ throw new CCIPDataFormatUnsupportedError(
63
+ 'Cannot pack more than 3 refs per item; store it in a separate ref cell.',
64
+ )
65
+ }
66
+ if (builder.availableBits < itemBuilder.bits || builder.availableRefs <= 1) {
67
+ cells.push(builder)
68
+ builder = beginCell()
69
+ }
70
+ builder.storeBuilder(itemBuilder)
71
+ }
72
+ cells.push(builder)
73
+
74
+ // Build the linked structure from the end
75
+ let current = cells[cells.length - 1].endCell()
76
+ for (let i = cells.length - 2; i >= 0; i--) {
77
+ const b = cells[i]
78
+ b.storeRef(current)
79
+ current = b.endCell()
80
+ }
81
+ return current
82
+ }
83
+
84
+ /**
85
+ * Serializes an execution report into a TON Cell for OffRamp execution.
86
+ * @param execReport - Execution report containing message, proofs, and proof flag bits.
87
+ * @returns BOC-serialized Cell containing the execution report.
88
+ */
89
+ export function serializeExecutionReport(
90
+ execReport: ExecutionReport<CCIPMessage_V1_6_TON>,
91
+ ): Builder {
92
+ return beginCell()
93
+ .storeUint(execReport.message.sourceChainSelector, 64)
94
+ .storeRef(asSnakeData([execReport.message], serializeMessage))
95
+ .storeRef(Cell.EMPTY) // TODO: FIXME: offchainTokenData empty for now, add when implemented
96
+ .storeRef(
97
+ asSnakeData(execReport.proofs.map(toBigInt), (proof: bigint) => {
98
+ return beginCell().storeUint(proof, 256)
99
+ }),
100
+ )
101
+ .storeUint(execReport.proofFlagBits, 256)
102
+ }
103
+
104
+ function serializeMessage(message: CCIPMessage_V1_6_TON): Builder {
105
+ return beginCell()
106
+ .storeUint(BigInt(message.messageId), 256)
107
+ .storeUint(message.sourceChainSelector, 64)
108
+ .storeUint(message.destChainSelector, 64)
109
+ .storeUint(message.sequenceNumber, 64)
110
+ .storeUint(message.nonce, 64)
111
+ .storeRef(
112
+ beginCell()
113
+ .storeUint(bytesToBuffer(message.sender).length, 8)
114
+ .storeBuffer(bytesToBuffer(message.sender))
115
+ .endCell(),
116
+ )
117
+ .storeRef(beginCell().storeBuffer(bytesToBuffer(message.data)).endCell())
118
+ .storeAddress(Address.parse(message.receiver))
119
+ .storeCoins(message.gasLimit)
120
+ .storeMaybeRef(
121
+ message.tokenAmounts?.length > 0 ? serializeTokenAmounts(message.tokenAmounts) : null,
122
+ )
123
+ }
124
+
125
+ function serializeTokenAmounts(tokenAmounts: CCIPMessage_V1_6['tokenAmounts']): Cell {
126
+ const builder = beginCell()
127
+ for (const ta of tokenAmounts) {
128
+ builder.storeRef(
129
+ beginCell()
130
+ .storeRef(serializeSourcePool(ta.sourcePoolAddress))
131
+ .storeAddress(Address.parse(ta.destTokenAddress))
132
+ .storeUint(BigInt(ta.amount), 256)
133
+ .storeRef(beginCell().storeBuffer(bytesToBuffer(ta.extraData)).endCell())
134
+ .endCell(),
135
+ )
136
+ }
137
+ return builder.endCell()
138
+ }
139
+
140
+ function serializeSourcePool(address: string): Cell {
141
+ const bytes = bytesToBuffer(address)
142
+ return beginCell().storeUint(bytes.length, 8).storeBuffer(bytes).endCell()
143
+ }