@aztec/pxe 5.0.0-rc.1 → 5.0.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 (297) hide show
  1. package/dest/block_synchronizer/block_stream_source.d.ts +5 -5
  2. package/dest/block_synchronizer/block_stream_source.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_stream_source.js +4 -29
  4. package/dest/block_synchronizer/block_synchronizer.d.ts +16 -12
  5. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  6. package/dest/block_synchronizer/block_synchronizer.js +49 -15
  7. package/dest/config/index.d.ts +2 -1
  8. package/dest/config/index.d.ts.map +1 -1
  9. package/dest/config/index.js +1 -0
  10. package/dest/contract/contract_class_service.d.ts +31 -0
  11. package/dest/contract/contract_class_service.d.ts.map +1 -0
  12. package/dest/contract/contract_class_service.js +68 -0
  13. package/dest/{contract_sync → contract}/contract_sync_service.d.ts +7 -6
  14. package/dest/contract/contract_sync_service.d.ts.map +1 -0
  15. package/dest/{contract_sync → contract}/contract_sync_service.js +10 -30
  16. package/dest/contract/helpers.d.ts +7 -0
  17. package/dest/contract/helpers.d.ts.map +1 -0
  18. package/dest/contract/helpers.js +20 -0
  19. package/dest/contract_function_simulator/anchored_contract_data.d.ts +36 -0
  20. package/dest/contract_function_simulator/anchored_contract_data.d.ts.map +1 -0
  21. package/dest/contract_function_simulator/anchored_contract_data.js +54 -0
  22. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts +39 -0
  23. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts.map +1 -0
  24. package/dest/contract_function_simulator/aztec_node_read_cache.js +60 -0
  25. package/dest/contract_function_simulator/contract_function_simulator.d.ts +19 -18
  26. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  27. package/dest/contract_function_simulator/contract_function_simulator.js +52 -31
  28. package/dest/contract_function_simulator/execution_note_cache.d.ts +3 -9
  29. package/dest/contract_function_simulator/execution_note_cache.d.ts.map +1 -1
  30. package/dest/contract_function_simulator/execution_note_cache.js +8 -28
  31. package/dest/contract_function_simulator/index.d.ts +17 -9
  32. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  33. package/dest/contract_function_simulator/index.js +4 -7
  34. package/dest/contract_function_simulator/noir-structs/bounded_vec.d.ts +8 -27
  35. package/dest/contract_function_simulator/noir-structs/bounded_vec.d.ts.map +1 -1
  36. package/dest/contract_function_simulator/noir-structs/bounded_vec.js +8 -23
  37. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.d.ts +9 -0
  38. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.d.ts.map +1 -0
  39. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.js +1 -0
  40. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.d.ts +7 -0
  41. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.d.ts.map +1 -0
  42. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.js +1 -0
  43. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
  44. package/dest/contract_function_simulator/noir-structs/fact.d.ts +16 -0
  45. package/dest/contract_function_simulator/noir-structs/fact.d.ts.map +1 -0
  46. package/dest/contract_function_simulator/noir-structs/fact.js +6 -0
  47. package/dest/contract_function_simulator/noir-structs/fact_collection.d.ts +27 -0
  48. package/dest/contract_function_simulator/noir-structs/fact_collection.d.ts.map +1 -0
  49. package/dest/contract_function_simulator/noir-structs/fact_collection.js +31 -0
  50. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts +11 -12
  51. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts.map +1 -1
  52. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.js +6 -49
  53. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +10 -8
  54. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts.map +1 -1
  55. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -60
  56. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +2 -2
  57. package/dest/contract_function_simulator/noir-structs/option.d.ts +9 -11
  58. package/dest/contract_function_simulator/noir-structs/option.d.ts.map +1 -1
  59. package/dest/contract_function_simulator/noir-structs/option.js +18 -13
  60. package/dest/contract_function_simulator/noir-structs/origin_block.d.ts +11 -0
  61. package/dest/contract_function_simulator/noir-structs/origin_block.d.ts.map +1 -0
  62. package/dest/contract_function_simulator/noir-structs/origin_block.js +5 -0
  63. package/dest/contract_function_simulator/noir-structs/pending_tagged_log.d.ts +11 -0
  64. package/dest/contract_function_simulator/noir-structs/pending_tagged_log.d.ts.map +1 -0
  65. package/dest/contract_function_simulator/noir-structs/pending_tagged_log.js +4 -0
  66. package/dest/contract_function_simulator/noir-structs/provided_secret.d.ts +6 -9
  67. package/dest/contract_function_simulator/noir-structs/provided_secret.d.ts.map +1 -1
  68. package/dest/contract_function_simulator/noir-structs/provided_secret.js +1 -14
  69. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts +28 -0
  70. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts.map +1 -0
  71. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.js +50 -0
  72. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts +21 -0
  73. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts.map +1 -0
  74. package/dest/contract_function_simulator/noir-structs/resolved_tx.js +50 -0
  75. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts +14 -0
  76. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts.map +1 -0
  77. package/dest/contract_function_simulator/noir-structs/tx_effect_data.js +5 -0
  78. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts +6 -11
  79. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts.map +1 -1
  80. package/dest/contract_function_simulator/noir-structs/utility_context.js +1 -20
  81. package/dest/contract_function_simulator/oracle/acir_callback.d.ts +7 -2
  82. package/dest/contract_function_simulator/oracle/acir_callback.d.ts.map +1 -1
  83. package/dest/contract_function_simulator/oracle/acir_callback.js +55 -11
  84. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts +39 -0
  85. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts.map +1 -0
  86. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.js +107 -0
  87. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts +3 -14
  88. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts.map +1 -1
  89. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.js +1 -24
  90. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts +86 -8
  91. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
  92. package/dest/contract_function_simulator/oracle/oracle_registry.js +168 -18
  93. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts +123 -40
  94. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts.map +1 -1
  95. package/dest/contract_function_simulator/oracle/oracle_type_mappings.js +947 -264
  96. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +21 -8
  97. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  98. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +126 -16
  99. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +63 -33
  100. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  101. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +175 -90
  102. package/dest/debug/pxe_debug_utils.d.ts +2 -2
  103. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  104. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  105. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  106. package/dest/entrypoints/client/bundle/utils.js +3 -2
  107. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  108. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  109. package/dest/entrypoints/client/lazy/utils.js +3 -2
  110. package/dest/entrypoints/pxe_creation_options.d.ts +8 -2
  111. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  112. package/dest/entrypoints/server/index.d.ts +5 -3
  113. package/dest/entrypoints/server/index.d.ts.map +1 -1
  114. package/dest/entrypoints/server/index.js +3 -2
  115. package/dest/entrypoints/server/utils.d.ts +1 -1
  116. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  117. package/dest/entrypoints/server/utils.js +3 -1
  118. package/dest/error_enriching.d.ts +5 -3
  119. package/dest/error_enriching.d.ts.map +1 -1
  120. package/dest/error_enriching.js +13 -11
  121. package/dest/hooks/execution_hooks.d.ts +27 -7
  122. package/dest/hooks/execution_hooks.d.ts.map +1 -1
  123. package/dest/hooks/execution_hooks.js +3 -3
  124. package/dest/hooks/index.d.ts +4 -3
  125. package/dest/hooks/index.d.ts.map +1 -1
  126. package/dest/hooks/index.js +1 -0
  127. package/dest/hooks/resolve_custom_request.d.ts +23 -0
  128. package/dest/hooks/resolve_custom_request.d.ts.map +1 -0
  129. package/dest/hooks/resolve_custom_request.js +3 -0
  130. package/dest/hooks/resolve_tagging_secret_strategy.d.ts +50 -0
  131. package/dest/hooks/resolve_tagging_secret_strategy.d.ts.map +1 -0
  132. package/dest/hooks/resolve_tagging_secret_strategy.js +3 -0
  133. package/dest/logs/log_service.d.ts +7 -6
  134. package/dest/logs/log_service.d.ts.map +1 -1
  135. package/dest/logs/log_service.js +79 -28
  136. package/dest/messages/tx_resolver_service.d.ts +17 -0
  137. package/dest/messages/tx_resolver_service.d.ts.map +1 -0
  138. package/dest/messages/{message_context_service.js → tx_resolver_service.js} +8 -8
  139. package/dest/oracle_version.d.ts +3 -3
  140. package/dest/oracle_version.js +3 -3
  141. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts +1 -1
  142. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts.map +1 -1
  143. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +6 -2
  144. package/dest/private_kernel/hints/test_utils.js +1 -1
  145. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  146. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  147. package/dest/private_kernel/private_kernel_execution_prover.js +17 -36
  148. package/dest/private_kernel/private_kernel_oracle.d.ts +4 -2
  149. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  150. package/dest/private_kernel/private_kernel_oracle.js +17 -5
  151. package/dest/pxe.d.ts +109 -47
  152. package/dest/pxe.d.ts.map +1 -1
  153. package/dest/pxe.js +222 -139
  154. package/dest/storage/allowed_scopes.d.ts +6 -0
  155. package/dest/storage/allowed_scopes.d.ts.map +1 -0
  156. package/dest/storage/allowed_scopes.js +7 -0
  157. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts +1 -1
  158. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts.map +1 -1
  159. package/dest/storage/backwards_compatibility_tests/schema_tests.js +114 -37
  160. package/dest/storage/capsule_store/capsule_service.d.ts +1 -1
  161. package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -1
  162. package/dest/storage/capsule_store/capsule_service.js +6 -9
  163. package/dest/storage/contract_store/contract_store.d.ts +27 -24
  164. package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
  165. package/dest/storage/contract_store/contract_store.js +64 -75
  166. package/dest/storage/fact_store/fact_service.d.ts +22 -0
  167. package/dest/storage/fact_store/fact_service.d.ts.map +1 -0
  168. package/dest/storage/fact_store/fact_service.js +45 -0
  169. package/dest/storage/fact_store/fact_store.d.ts +95 -0
  170. package/dest/storage/fact_store/fact_store.d.ts.map +1 -0
  171. package/dest/storage/fact_store/fact_store.js +408 -0
  172. package/dest/storage/fact_store/fact_store_keys.d.ts +34 -0
  173. package/dest/storage/fact_store/fact_store_keys.d.ts.map +1 -0
  174. package/dest/storage/fact_store/fact_store_keys.js +50 -0
  175. package/dest/storage/fact_store/index.d.ts +6 -0
  176. package/dest/storage/fact_store/index.d.ts.map +1 -0
  177. package/dest/storage/fact_store/index.js +4 -0
  178. package/dest/storage/fact_store/origin_state.d.ts +57 -0
  179. package/dest/storage/fact_store/origin_state.d.ts.map +1 -0
  180. package/dest/storage/fact_store/origin_state.js +53 -0
  181. package/dest/storage/fact_store/stored_fact.d.ts +32 -0
  182. package/dest/storage/fact_store/stored_fact.d.ts.map +1 -0
  183. package/dest/storage/fact_store/stored_fact.js +64 -0
  184. package/dest/storage/index.d.ts +2 -1
  185. package/dest/storage/index.d.ts.map +1 -1
  186. package/dest/storage/index.js +1 -0
  187. package/dest/storage/metadata.d.ts +2 -2
  188. package/dest/storage/metadata.d.ts.map +1 -1
  189. package/dest/storage/metadata.js +1 -1
  190. package/dest/storage/open_pxe_stores.d.ts +5 -3
  191. package/dest/storage/open_pxe_stores.d.ts.map +1 -1
  192. package/dest/storage/open_pxe_stores.js +5 -3
  193. package/dest/storage/tagging_store/index.d.ts +2 -2
  194. package/dest/storage/tagging_store/index.d.ts.map +1 -1
  195. package/dest/storage/tagging_store/index.js +1 -1
  196. package/dest/storage/tagging_store/tagging_secret_sources_store.d.ts +51 -0
  197. package/dest/storage/tagging_store/tagging_secret_sources_store.d.ts.map +1 -0
  198. package/dest/storage/tagging_store/tagging_secret_sources_store.js +105 -0
  199. package/dest/tagging/constants.d.ts +2 -2
  200. package/dest/tagging/constants.d.ts.map +1 -1
  201. package/dest/tagging/constants.js +18 -9
  202. package/package.json +17 -17
  203. package/src/block_synchronizer/block_stream_source.ts +6 -45
  204. package/src/block_synchronizer/block_synchronizer.ts +65 -24
  205. package/src/config/index.ts +1 -0
  206. package/src/contract/contract_class_service.ts +83 -0
  207. package/src/{contract_sync → contract}/contract_sync_service.ts +18 -37
  208. package/src/contract/helpers.ts +35 -0
  209. package/src/contract_function_simulator/anchored_contract_data.ts +74 -0
  210. package/src/contract_function_simulator/aztec_node_read_cache.ts +89 -0
  211. package/src/contract_function_simulator/contract_function_simulator.ts +86 -43
  212. package/src/contract_function_simulator/execution_note_cache.ts +7 -28
  213. package/src/contract_function_simulator/index.ts +24 -9
  214. package/src/contract_function_simulator/noir-structs/bounded_vec.ts +12 -24
  215. package/src/contract_function_simulator/noir-structs/contract_class_log_data.ts +9 -0
  216. package/src/contract_function_simulator/noir-structs/embedded_curve_point.ts +4 -0
  217. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
  218. package/src/contract_function_simulator/noir-structs/fact.ts +13 -0
  219. package/src/contract_function_simulator/noir-structs/fact_collection.ts +64 -0
  220. package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +20 -46
  221. package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +13 -60
  222. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +2 -2
  223. package/src/contract_function_simulator/noir-structs/option.ts +17 -11
  224. package/src/contract_function_simulator/noir-structs/origin_block.ts +8 -0
  225. package/src/contract_function_simulator/noir-structs/pending_tagged_log.ts +12 -0
  226. package/src/contract_function_simulator/noir-structs/provided_secret.ts +4 -15
  227. package/src/contract_function_simulator/noir-structs/resolved_tagging_strategy.ts +66 -0
  228. package/src/contract_function_simulator/noir-structs/resolved_tx.ts +53 -0
  229. package/src/contract_function_simulator/noir-structs/tx_effect_data.ts +15 -0
  230. package/src/contract_function_simulator/noir-structs/utility_context.ts +5 -17
  231. package/src/contract_function_simulator/oracle/acir_callback.ts +58 -12
  232. package/src/contract_function_simulator/oracle/legacy_oracle_registry.ts +147 -0
  233. package/src/contract_function_simulator/oracle/message_load_oracle_inputs.ts +6 -21
  234. package/src/contract_function_simulator/oracle/oracle_registry.ts +119 -86
  235. package/src/contract_function_simulator/oracle/oracle_type_mappings.ts +659 -248
  236. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +155 -24
  237. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +300 -115
  238. package/src/debug/pxe_debug_utils.ts +1 -1
  239. package/src/entrypoints/client/bundle/utils.ts +3 -2
  240. package/src/entrypoints/client/lazy/utils.ts +3 -2
  241. package/src/entrypoints/pxe_creation_options.ts +7 -1
  242. package/src/entrypoints/server/index.ts +5 -2
  243. package/src/entrypoints/server/utils.ts +3 -1
  244. package/src/error_enriching.ts +27 -11
  245. package/src/hooks/execution_hooks.ts +28 -8
  246. package/src/hooks/index.ts +8 -2
  247. package/src/hooks/resolve_custom_request.ts +24 -0
  248. package/src/hooks/resolve_tagging_secret_strategy.ts +60 -0
  249. package/src/logs/log_service.ts +91 -37
  250. package/src/messages/{message_context_service.ts → tx_resolver_service.ts} +16 -9
  251. package/src/oracle_version.ts +3 -3
  252. package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +11 -1
  253. package/src/private_kernel/hints/test_utils.ts +1 -1
  254. package/src/private_kernel/private_kernel_execution_prover.ts +22 -52
  255. package/src/private_kernel/private_kernel_oracle.ts +23 -4
  256. package/src/pxe.ts +320 -158
  257. package/src/storage/allowed_scopes.ts +14 -0
  258. package/src/storage/backwards_compatibility_tests/__snapshots__/AddressStore.json +6 -6
  259. package/src/storage/backwards_compatibility_tests/__snapshots__/ContractStore.json +1 -1
  260. package/src/storage/backwards_compatibility_tests/__snapshots__/FactStore.json +40 -0
  261. package/src/storage/backwards_compatibility_tests/__snapshots__/KeyStore.json +12 -12
  262. package/src/storage/backwards_compatibility_tests/__snapshots__/L2TipsKVStore.json +1 -1
  263. package/src/storage/backwards_compatibility_tests/__snapshots__/RecipientTaggingStore.json +11 -3
  264. package/src/storage/backwards_compatibility_tests/__snapshots__/SenderTaggingStore.json +12 -4
  265. package/src/storage/backwards_compatibility_tests/__snapshots__/TaggingSecretSourcesStore.json +30 -0
  266. package/src/storage/backwards_compatibility_tests/__snapshots__/opened_stores.json +21 -5
  267. package/src/storage/backwards_compatibility_tests/schema_tests.ts +125 -36
  268. package/src/storage/capsule_store/capsule_service.ts +8 -13
  269. package/src/storage/contract_store/contract_store.ts +86 -93
  270. package/src/storage/fact_store/fact_service.ts +69 -0
  271. package/src/storage/fact_store/fact_store.ts +487 -0
  272. package/src/storage/fact_store/fact_store_keys.ts +75 -0
  273. package/src/storage/fact_store/index.ts +14 -0
  274. package/src/storage/fact_store/origin_state.ts +75 -0
  275. package/src/storage/fact_store/stored_fact.ts +80 -0
  276. package/src/storage/index.ts +1 -0
  277. package/src/storage/metadata.ts +1 -1
  278. package/src/storage/open_pxe_stores.ts +6 -3
  279. package/src/storage/tagging_store/index.ts +1 -1
  280. package/src/storage/tagging_store/tagging_secret_sources_store.ts +138 -0
  281. package/src/tagging/constants.ts +19 -9
  282. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts +0 -6
  283. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts.map +0 -1
  284. package/dest/contract_function_simulator/proxied_contract_data_source.js +0 -51
  285. package/dest/contract_sync/contract_sync_service.d.ts.map +0 -1
  286. package/dest/contract_sync/helpers.d.ts +0 -27
  287. package/dest/contract_sync/helpers.d.ts.map +0 -1
  288. package/dest/contract_sync/helpers.js +0 -53
  289. package/dest/messages/message_context_service.d.ts +0 -17
  290. package/dest/messages/message_context_service.d.ts.map +0 -1
  291. package/dest/storage/tagging_store/sender_address_book_store.d.ts +0 -14
  292. package/dest/storage/tagging_store/sender_address_book_store.d.ts.map +0 -1
  293. package/dest/storage/tagging_store/sender_address_book_store.js +0 -36
  294. package/src/contract_function_simulator/proxied_contract_data_source.ts +0 -60
  295. package/src/contract_sync/helpers.ts +0 -86
  296. package/src/storage/backwards_compatibility_tests/__snapshots__/SenderAddressBookStore.json +0 -16
  297. package/src/storage/tagging_store/sender_address_book_store.ts +0 -48
@@ -1,6 +1,6 @@
1
1
  import {
2
- BLOCK_HEADER_LENGTH,
3
- KEY_VALIDATION_REQUEST_LENGTH,
2
+ CONTRACT_CLASS_LOG_SIZE_IN_FIELDS,
3
+ FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH,
4
4
  L1_TO_L2_MSG_TREE_HEIGHT,
5
5
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
6
6
  MAX_L2_TO_L1_MSGS_PER_TX,
@@ -8,48 +8,91 @@ import {
8
8
  MAX_NULLIFIERS_PER_TX,
9
9
  MAX_PRIVATE_LOGS_PER_TX,
10
10
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
11
+ NULLIFIER_TREE_HEIGHT,
12
+ PRIVATE_LOG_CIPHERTEXT_LEN,
13
+ PRIVATE_LOG_SIZE_IN_FIELDS,
14
+ PUBLIC_DATA_TREE_HEIGHT,
11
15
  } from '@aztec/constants';
12
- import { BlockNumber } from '@aztec/foundation/branded-types';
16
+ import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
13
17
  import { padArrayEnd } from '@aztec/foundation/collection';
14
18
  import { Fr } from '@aztec/foundation/curves/bn254';
15
- import { Point } from '@aztec/foundation/curves/grumpkin';
19
+ import { EthAddress } from '@aztec/foundation/eth-address';
16
20
  import { FieldReader } from '@aztec/foundation/serialize';
17
- import { MembershipWitness } from '@aztec/foundation/trees';
21
+ import { MembershipWitness, type SiblingPath } from '@aztec/foundation/trees';
18
22
  import { type ACVMField, fromUintArray } from '@aztec/simulator/client';
19
23
  import { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
20
- import { PublicDataWrite } from '@aztec/stdlib/avm';
24
+ import { PublicDataWrite, RevertCode } from '@aztec/stdlib/avm';
21
25
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
22
26
  import { BlockHash } from '@aztec/stdlib/block';
23
- import type { ContractInstance, PartialAddress } from '@aztec/stdlib/contract';
27
+ import type { ContractInstancePreimage, PartialAddress } from '@aztec/stdlib/contract';
28
+ import type { GasFees } from '@aztec/stdlib/gas';
24
29
  import { KeyValidationRequest } from '@aztec/stdlib/kernel';
25
30
  import type { PublicKeys } from '@aztec/stdlib/keys';
26
31
  import {
27
32
  type AppTaggingSecretKind,
28
- ContractClassLog,
29
- ContractClassLogFields,
30
- FlatPublicLogs,
31
- MessageContext,
32
- PendingTaggedLog,
33
+ type FlatPublicLogs,
33
34
  PrivateLog,
34
35
  Tag,
35
36
  appTaggingSecretKindFromDeliveryMode,
36
37
  } from '@aztec/stdlib/logs';
37
- import { NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
38
- import { BlockHeader, TxEffect, TxHash } from '@aztec/stdlib/tx';
39
-
38
+ import {
39
+ type AppendOnlyTreeSnapshot,
40
+ type NullifierLeaf,
41
+ type NullifierLeafPreimage,
42
+ NullifierMembershipWitness,
43
+ type PublicDataTreeLeaf,
44
+ type PublicDataTreeLeafPreimage,
45
+ PublicDataWitness,
46
+ } from '@aztec/stdlib/trees';
47
+ import {
48
+ BlockHeader,
49
+ type GlobalVariables,
50
+ type PartialStateReference,
51
+ type StateReference,
52
+ TxHash,
53
+ } from '@aztec/stdlib/tx';
54
+
55
+ import type { OriginBlock, RetractableFactOrigin } from '../../storage/fact_store/index.js';
40
56
  import { BoundedVec } from '../noir-structs/bounded_vec.js';
57
+ import type { ContractClassLogData } from '../noir-structs/contract_class_log_data.js';
58
+ import type { EmbeddedCurvePoint } from '../noir-structs/embedded_curve_point.js';
41
59
  import { EphemeralArray } from '../noir-structs/ephemeral_array.js';
42
60
  import { EventValidationRequest } from '../noir-structs/event_validation_request.js';
43
- import { LogRetrievalRequest } from '../noir-structs/log_retrieval_request.js';
44
- import { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
61
+ import type { Fact } from '../noir-structs/fact.js';
62
+ import type { FactCollection } from '../noir-structs/fact_collection.js';
63
+ import { type LogRetrievalRequest, type LogSource, logSourceFromField } from '../noir-structs/log_retrieval_request.js';
64
+ import type { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
45
65
  import type { NoteData } from '../noir-structs/note_data.js';
46
66
  import { NoteValidationRequest } from '../noir-structs/note_validation_request.js';
47
67
  import { Option } from '../noir-structs/option.js';
48
- import { ProvidedSecret } from '../noir-structs/provided_secret.js';
49
- import { UtilityContext } from '../noir-structs/utility_context.js';
50
- import { MessageLoadOracleInputs } from './message_load_oracle_inputs.js';
68
+ import type { PendingTaggedLog } from '../noir-structs/pending_tagged_log.js';
69
+ import type { ProvidedSecret } from '../noir-structs/provided_secret.js';
70
+ import {
71
+ type ResolvedTaggingStrategy,
72
+ resolvedTaggingStrategyFromFields,
73
+ resolvedTaggingStrategyToFields,
74
+ } from '../noir-structs/resolved_tagging_strategy.js';
75
+ import type { ResolvedTx } from '../noir-structs/resolved_tx.js';
76
+ import type { TxEffectData } from '../noir-structs/tx_effect_data.js';
77
+ import type { UtilityContext } from '../noir-structs/utility_context.js';
78
+ import type { MessageLoadOracleInputs } from './message_load_oracle_inputs.js';
51
79
  import { packAsHintedNote } from './note_packing_utils.js';
52
80
 
81
+ // `ORACLE_REGISTRY` infers its entry signatures from these mappings, so its emitted declaration (and the oracle
82
+ // interfaces derived from it) names the protocol types below. Re-exporting them gives tsc a portable path to each
83
+ // type instead of falling back to a deep node_modules path that breaks .d.ts portability (TS2742).
84
+ export type {
85
+ AppTaggingSecretKind,
86
+ BlockHash,
87
+ BlockHeader,
88
+ ContractInstancePreimage,
89
+ MembershipWitness,
90
+ NullifierMembershipWitness,
91
+ PendingTaggedLog,
92
+ PublicDataWitness,
93
+ TxHash,
94
+ };
95
+
53
96
  // ─── Core Types ──────────────────────────────────────────────────────────────
54
97
 
55
98
  /** One ACVM input slot: an array of hex-encoded field strings. */
@@ -58,6 +101,18 @@ export type InputSlot = ACVMField[];
58
101
  /** One ACVM output slot: a scalar hex string or an array of hex strings. */
59
102
  export type OutputSlot = ACVMField | ACVMField[];
60
103
 
104
+ /**
105
+ * Wire layout of a single slot:
106
+ * - `'scalar'` — a bare field (one `Fr`); on the ACVM/Noir wire a `Field`.
107
+ * - `{ len }` — an array of exactly `len` fields (`Fr[]`); a `[Field; len]`.
108
+ * - `'variable'` — a slot whose field count is not statically known and cannot be sized on demand (a string, a
109
+ * length-prefixed struct). It contributes to the slot count but can never be zero-filled.
110
+ * - `{ lenFrom: fn }` — like `'variable'`, but its field count can be resolved from a runtime size descriptor. The
111
+ * descriptor's shape is type-specific (e.g. `{ length }`, `{ maxLength }`), so `size` is typed `any`: a single union
112
+ * can't type each mapping's distinct `lenFrom` under parameter contravariance.
113
+ */
114
+ export type SlotShape = 'scalar' | { len: number } | 'variable' | { lenFrom: (size: any) => number };
115
+
61
116
  /**
62
117
  * Describes how to serialize and/or deserialize a single typed value to/from ACVM wire format.
63
118
  * Either side is optional — output-only types omit `deserialization`, input-only types omit `serialization`.
@@ -68,18 +123,18 @@ export interface TypeMapping<T = any> {
68
123
  fn: (value: T) => (Fr | Fr[])[];
69
124
  };
70
125
  deserialization?: {
71
- /** Read a typed value from one FieldReader per consumed slot. */
126
+ /** Read a typed value from its slots — one {@link FieldReader} per slot, as laid out by {@link shape}. */
72
127
  fn: (readers: FieldReader[]) => T;
73
- /**
74
- * Number of InputSlots this type reads from. `deserialization.fn` receives one FieldReader per slot in `readers`.
75
- *
76
- * Examples:
77
- * - `FIELD`, `U32`, `AZTEC_ADDRESS` — single slot → `slots: 1`
78
- * - `OPTION(T)` — discriminant + inner slots → `slots: T.slots + 1`
79
- * - `CONTRACT_CLASS_LOG_INPUT` — [addr], [fields], [len] → `slots: 3`
80
- */
81
- slots: number;
82
128
  };
129
+ /**
130
+ * The type's wire layout, one entry per slot.
131
+ *
132
+ * Examples:
133
+ * - `FIELD` → `['scalar']` // single slot
134
+ * - `OPTION(T)` → `['scalar', ...T.shape]` // [discriminant], [...inner.shape]
135
+ * - `CONTRACT_CLASS_LOG` → `['scalar', { len: N }, 'scalar']` // [addr], [fields], [len]
136
+ */
137
+ shape: SlotShape[];
83
138
  }
84
139
 
85
140
  export type MaybePromise<T> = T | Promise<T>;
@@ -101,12 +156,14 @@ export function assertReadersConsumed(readers: FieldReader[]): void {
101
156
 
102
157
  export const FIELD: TypeMapping<Fr> = {
103
158
  serialization: { fn: v => [v] },
104
- deserialization: { fn: ([reader]) => reader.readField(), slots: 1 },
159
+ deserialization: { fn: ([reader]) => reader.readField() },
160
+ shape: ['scalar'],
105
161
  };
106
162
 
107
163
  export const BOOL: TypeMapping<boolean> = {
108
164
  serialization: { fn: v => [new Fr(v ? 1n : 0n)] },
109
- deserialization: { fn: ([reader]) => !reader.readField().isZero(), slots: 1 },
165
+ deserialization: { fn: ([reader]) => !reader.readField().isZero() },
166
+ shape: ['scalar'],
110
167
  };
111
168
 
112
169
  export const U32: TypeMapping<number> = {
@@ -119,13 +176,14 @@ export const U32: TypeMapping<number> = {
119
176
  }
120
177
  return Number(value);
121
178
  },
122
- slots: 1,
123
179
  },
180
+ shape: ['scalar'],
124
181
  };
125
182
 
126
183
  export const BLOCK_NUMBER: TypeMapping<BlockNumber> = {
127
184
  serialization: { fn: v => [new Fr(v)] },
128
- deserialization: { fn: ([reader]) => BlockNumber(reader.readField().toNumber()), slots: 1 },
185
+ deserialization: { fn: ([reader]) => BlockNumber(reader.readField().toNumber()) },
186
+ shape: ['scalar'],
129
187
  };
130
188
 
131
189
  /** A u8 byte: serializes to a single Fr; deserializes from a single Fr to a number in [0, 255]. */
@@ -139,21 +197,31 @@ export const BYTE: TypeMapping<number> = {
139
197
  }
140
198
  return Number(value);
141
199
  },
142
- slots: 1,
143
200
  },
201
+ shape: ['scalar'],
144
202
  };
145
203
 
146
204
  // Noir passes `MessageDelivery` onchain variants here.
147
205
  export const DELIVERY_MODE: TypeMapping<AppTaggingSecretKind> = {
148
206
  deserialization: {
149
207
  fn: readers => appTaggingSecretKindFromDeliveryMode(BYTE.deserialization!.fn(readers)),
150
- slots: BYTE.deserialization!.slots,
151
208
  },
209
+ shape: BYTE.shape,
210
+ };
211
+
212
+ export const RESOLVED_TAGGING_STRATEGY: TypeMapping<ResolvedTaggingStrategy> = {
213
+ serialization: { fn: resolved => resolvedTaggingStrategyToFields(resolved) },
214
+ deserialization: {
215
+ fn: ([kindReader, secretReader]) =>
216
+ resolvedTaggingStrategyFromFields(kindReader.readField().toNumber(), secretReader.readField()),
217
+ },
218
+ shape: ['scalar', 'scalar'],
152
219
  };
153
220
 
154
221
  export const BIGINT: TypeMapping<bigint> = {
155
222
  serialization: { fn: v => [new Fr(v)] },
156
- deserialization: { fn: ([reader]) => reader.readField().toBigInt(), slots: 1 },
223
+ deserialization: { fn: ([reader]) => reader.readField().toBigInt() },
224
+ shape: ['scalar'],
157
225
  };
158
226
 
159
227
  /** Reads every field in the slot as a UTF-8 character code. */
@@ -167,163 +235,241 @@ export const STR: TypeMapping<string> = {
167
235
  }
168
236
  return chars.join('');
169
237
  },
170
- slots: 1,
171
238
  },
239
+ shape: ['variable'],
172
240
  };
173
241
 
174
242
  export const AZTEC_ADDRESS: TypeMapping<AztecAddress> = {
175
243
  serialization: { fn: v => [v.toField()] },
176
- deserialization: { fn: ([reader]) => AztecAddress.fromField(reader.readField()), slots: 1 },
244
+ deserialization: { fn: ([reader]) => AztecAddress.fromFieldUnsafe(reader.readField()) },
245
+ shape: ['scalar'],
177
246
  };
178
247
 
179
248
  export const BLOCK_HASH: TypeMapping<BlockHash> = {
180
249
  serialization: { fn: v => [new Fr(v.toBuffer())] },
181
- deserialization: { fn: ([reader]) => new BlockHash(reader.readField()), slots: 1 },
250
+ deserialization: { fn: ([reader]) => new BlockHash(reader.readField()) },
251
+ shape: ['scalar'],
182
252
  };
183
253
 
184
254
  export const FUNCTION_SELECTOR: TypeMapping<FunctionSelector> = {
185
255
  serialization: { fn: v => [v.toField()] },
186
- deserialization: { fn: ([reader]) => FunctionSelector.fromField(reader.readField()), slots: 1 },
256
+ deserialization: { fn: ([reader]) => FunctionSelector.fromField(reader.readField()) },
257
+ shape: ['scalar'],
187
258
  };
188
259
 
189
260
  export const NOTE_SELECTOR: TypeMapping<NoteSelector> = {
190
261
  serialization: { fn: v => [v.toField()] },
191
- deserialization: { fn: ([reader]) => NoteSelector.fromField(reader.readField()), slots: 1 },
262
+ deserialization: { fn: ([reader]) => NoteSelector.fromField(reader.readField()) },
263
+ shape: ['scalar'],
192
264
  };
193
265
 
194
266
  export const TX_HASH: TypeMapping<TxHash> = {
195
267
  serialization: { fn: v => [v.hash] },
196
- deserialization: { fn: ([reader]) => TxHash.fromField(reader.readField()), slots: 1 },
268
+ deserialization: { fn: ([reader]) => TxHash.fromField(reader.readField()) },
269
+ shape: ['scalar'],
197
270
  };
198
271
 
199
- export const TAG: TypeMapping<Tag> = {
272
+ const TAG: TypeMapping<Tag> = {
200
273
  serialization: { fn: v => [v.value] },
201
- deserialization: { fn: ([reader]) => new Tag(reader.readField()), slots: 1 },
202
- };
203
-
204
- export const POINT: TypeMapping<Point> = {
205
- serialization: { fn: p => [p.toFields()] },
206
- deserialization: {
207
- fn: ([reader]) => Point.fromFields([reader.readField(), reader.readField()]),
208
- slots: 1,
209
- },
210
- };
211
-
212
- // ─── Struct Type Mappings ────────────────────────────────────────────────────
213
-
214
- export const BLOCK_HEADER: TypeMapping<BlockHeader> = {
215
- serialization: { fn: v => v.toFields() },
216
- deserialization: { fn: ([reader]) => BlockHeader.fromFields(reader.readFieldArray(BLOCK_HEADER_LENGTH)), slots: 1 },
274
+ deserialization: { fn: ([reader]) => new Tag(reader.readField()) },
275
+ shape: ['scalar'],
217
276
  };
218
277
 
219
- export const KEY_VALIDATION_REQUEST: TypeMapping<KeyValidationRequest> = {
220
- serialization: { fn: v => v.toFields() },
221
- deserialization: {
222
- fn: ([reader]) => KeyValidationRequest.fromFields(reader.readFieldArray(KEY_VALIDATION_REQUEST_LENGTH)),
223
- slots: 1,
224
- },
225
- };
278
+ export const POINT: TypeMapping<EmbeddedCurvePoint> = STRUCT([
279
+ { name: 'x', type: FIELD },
280
+ { name: 'y', type: FIELD },
281
+ ]);
226
282
 
227
- export const CONTRACT_INSTANCE: TypeMapping<ContractInstance> = {
228
- serialization: {
229
- fn: v => [
230
- v.salt,
231
- v.deployer.toField(),
232
- v.currentContractClassId,
233
- v.initializationHash,
234
- v.immutablesHash,
235
- ...v.publicKeys.toFields(),
236
- ],
237
- },
238
- };
239
-
240
- export const NULLIFIER_MEMBERSHIP_WITNESS: TypeMapping<NullifierMembershipWitness> = {
241
- serialization: {
242
- fn: (w: NullifierMembershipWitness) =>
243
- w
244
- .toNoirRepresentation()
245
- .map(slot => (Array.isArray(slot) ? slot.map(s => Fr.fromString(s)) : Fr.fromString(slot as string))),
246
- },
247
- };
248
-
249
- export const PUBLIC_DATA_WITNESS: TypeMapping<PublicDataWitness> = {
250
- serialization: {
251
- fn: (w: PublicDataWitness) =>
252
- w
253
- .toNoirRepresentation()
254
- .map(slot => (Array.isArray(slot) ? slot.map(s => Fr.fromString(s)) : Fr.fromString(slot as string))),
255
- },
256
- };
257
-
258
- export const MESSAGE_LOAD_ORACLE_INPUTS: TypeMapping<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> = {
259
- serialization: {
260
- fn: (m: MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>) =>
261
- m
262
- .toNoirRepresentation()
263
- .map(slot => (Array.isArray(slot) ? slot.map(s => Fr.fromString(s)) : Fr.fromString(slot as string))),
264
- },
283
+ const LOG_SOURCE: TypeMapping<LogSource> = {
284
+ serialization: { fn: v => [new Fr(v)] },
285
+ deserialization: { fn: ([reader]) => logSourceFromField(reader.readField()) },
286
+ shape: ['scalar'],
265
287
  };
266
288
 
267
- export const UTILITY_CONTEXT: TypeMapping<UtilityContext> = {
268
- serialization: {
269
- fn: (ctx: UtilityContext) => [...ctx.blockHeader.toFields(), ctx.contractAddress.toField()],
270
- },
289
+ export const ETH_ADDRESS: TypeMapping<EthAddress> = {
290
+ serialization: { fn: v => [v.toField()] },
291
+ deserialization: { fn: ([reader]) => EthAddress.fromField(reader.readField()) },
292
+ shape: ['scalar'],
271
293
  };
272
294
 
273
- export const CALL_PRIVATE_RESULT: TypeMapping<{ endSideEffectCounter: Fr; returnsHash: Fr }> = {
274
- serialization: { fn: v => [[v.endSideEffectCounter, v.returnsHash]] },
275
- };
295
+ export const SLOT_NUMBER: TypeMapping<SlotNumber> = {
296
+ serialization: { fn: v => [new Fr(v)] },
297
+ shape: ['scalar'],
298
+ };
299
+
300
+ const APPEND_ONLY_TREE_SNAPSHOT: TypeMapping<AppendOnlyTreeSnapshot> = STRUCT<AppendOnlyTreeSnapshot>([
301
+ { name: 'root', type: FIELD },
302
+ { name: 'nextAvailableLeafIndex', type: U32 },
303
+ ]);
304
+
305
+ const PARTIAL_STATE_REFERENCE: TypeMapping<PartialStateReference> = STRUCT<PartialStateReference>([
306
+ { name: 'noteHashTree', type: APPEND_ONLY_TREE_SNAPSHOT },
307
+ { name: 'nullifierTree', type: APPEND_ONLY_TREE_SNAPSHOT },
308
+ { name: 'publicDataTree', type: APPEND_ONLY_TREE_SNAPSHOT },
309
+ ]);
310
+
311
+ const STATE_REFERENCE: TypeMapping<StateReference> = STRUCT<StateReference>([
312
+ { name: 'l1ToL2MessageTree', type: APPEND_ONLY_TREE_SNAPSHOT },
313
+ { name: 'partial', type: PARTIAL_STATE_REFERENCE },
314
+ ]);
315
+
316
+ const GAS_FEES: TypeMapping<GasFees> = STRUCT<GasFees>([
317
+ { name: 'feePerDaGas', type: BIGINT },
318
+ { name: 'feePerL2Gas', type: BIGINT },
319
+ ]);
320
+
321
+ const GLOBAL_VARIABLES: TypeMapping<GlobalVariables> = STRUCT<GlobalVariables>([
322
+ { name: 'chainId', type: FIELD },
323
+ { name: 'version', type: FIELD },
324
+ { name: 'blockNumber', type: BLOCK_NUMBER },
325
+ { name: 'slotNumber', type: SLOT_NUMBER },
326
+ { name: 'timestamp', type: BIGINT },
327
+ { name: 'coinbase', type: ETH_ADDRESS },
328
+ { name: 'feeRecipient', type: AZTEC_ADDRESS },
329
+ { name: 'gasFees', type: GAS_FEES },
330
+ ]);
331
+
332
+ export const BLOCK_HEADER: TypeMapping<BlockHeader> = STRUCT<BlockHeader>([
333
+ { name: 'lastArchive', type: APPEND_ONLY_TREE_SNAPSHOT },
334
+ { name: 'state', type: STATE_REFERENCE },
335
+ { name: 'spongeBlobHash', type: FIELD },
336
+ { name: 'globalVariables', type: GLOBAL_VARIABLES },
337
+ { name: 'totalFees', type: FIELD },
338
+ { name: 'totalManaUsed', type: FIELD },
339
+ ]);
340
+
341
+ export const KEY_VALIDATION_REQUEST: TypeMapping<KeyValidationRequest> = STRUCT<KeyValidationRequest>([
342
+ { name: 'pkMHash', type: FIELD },
343
+ { name: 'skApp', type: FIELD },
344
+ ]);
345
+
346
+ const PUBLIC_KEYS: TypeMapping<PublicKeys> = STRUCT<PublicKeys>([
347
+ { name: 'npkMHash', type: FIELD },
348
+ { name: 'ivpkM', type: POINT },
349
+ { name: 'ovpkMHash', type: FIELD },
350
+ { name: 'tpkMHash', type: FIELD },
351
+ { name: 'mspkMHash', type: FIELD },
352
+ { name: 'fbpkMHash', type: FIELD },
353
+ ]);
354
+
355
+ export const CONTRACT_INSTANCE: TypeMapping<ContractInstancePreimage> = STRUCT<ContractInstancePreimage>([
356
+ { name: 'salt', type: FIELD },
357
+ { name: 'deployer', type: AZTEC_ADDRESS },
358
+ // Note that the nr side of this struct does not contain the current class, only original
359
+ { name: 'originalContractClassId', type: FIELD },
360
+ { name: 'initializationHash', type: FIELD },
361
+ { name: 'immutablesHash', type: FIELD },
362
+ { name: 'publicKeys', type: PUBLIC_KEYS },
363
+ ]);
364
+
365
+ const NULLIFIER_LEAF: TypeMapping<NullifierLeaf> = STRUCT<NullifierLeaf>([{ name: 'nullifier', type: FIELD }]);
366
+
367
+ const NULLIFIER_LEAF_PREIMAGE: TypeMapping<NullifierLeafPreimage> = STRUCT<NullifierLeafPreimage>([
368
+ { name: 'leaf', type: NULLIFIER_LEAF },
369
+ { name: 'nextKey', type: FIELD },
370
+ { name: 'nextIndex', type: BIGINT },
371
+ ]);
372
+
373
+ export const NULLIFIER_MEMBERSHIP_WITNESS: TypeMapping<NullifierMembershipWitness> = STRUCT<NullifierMembershipWitness>(
374
+ [
375
+ { name: 'leafPreimage', type: NULLIFIER_LEAF_PREIMAGE },
376
+ { name: 'index', type: BIGINT },
377
+ { name: 'siblingPath', type: SIBLING_PATH(NULLIFIER_TREE_HEIGHT) },
378
+ ],
379
+ );
380
+
381
+ const PUBLIC_DATA_LEAF: TypeMapping<PublicDataTreeLeaf> = STRUCT<PublicDataTreeLeaf>([
382
+ { name: 'slot', type: FIELD },
383
+ { name: 'value', type: FIELD },
384
+ ]);
385
+
386
+ const PUBLIC_DATA_LEAF_PREIMAGE: TypeMapping<PublicDataTreeLeafPreimage> = STRUCT<PublicDataTreeLeafPreimage>([
387
+ { name: 'leaf', type: PUBLIC_DATA_LEAF },
388
+ { name: 'nextKey', type: FIELD },
389
+ { name: 'nextIndex', type: BIGINT },
390
+ ]);
391
+
392
+ export const PUBLIC_DATA_WITNESS: TypeMapping<PublicDataWitness> = STRUCT<PublicDataWitness>([
393
+ { name: 'index', type: BIGINT },
394
+ { name: 'leafPreimage', type: PUBLIC_DATA_LEAF_PREIMAGE },
395
+ { name: 'siblingPath', type: SIBLING_PATH(PUBLIC_DATA_TREE_HEIGHT) },
396
+ ]);
397
+
398
+ export const MESSAGE_LOAD_ORACLE_INPUTS: TypeMapping<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> = STRUCT<
399
+ MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>
400
+ >([
401
+ { name: 'index', type: BIGINT },
402
+ { name: 'siblingPath', type: SIBLING_PATH(L1_TO_L2_MSG_TREE_HEIGHT) },
403
+ ]);
404
+
405
+ export const UTILITY_CONTEXT: TypeMapping<UtilityContext> = STRUCT<UtilityContext>([
406
+ { name: 'blockHeader', type: BLOCK_HEADER },
407
+ { name: 'contractAddress', type: AZTEC_ADDRESS },
408
+ { name: 'msgSender', type: AZTEC_ADDRESS },
409
+ ]);
410
+
411
+ export const CALL_PRIVATE_RESULT: TypeMapping<{ endSideEffectCounter: Fr; returnsHash: Fr }> = STRUCT([
412
+ { name: 'endSideEffectCounter', type: FIELD },
413
+ { name: 'returnsHash', type: FIELD },
414
+ ]);
276
415
 
277
416
  export const PUBLIC_KEYS_AND_PARTIAL_ADDRESS: TypeMapping<{
278
417
  publicKeys: PublicKeys;
279
418
  partialAddress: PartialAddress;
280
- }> = {
281
- serialization: {
282
- fn: v => [[...v.publicKeys.toFields(), v.partialAddress]],
283
- },
284
- };
285
-
286
- export const CONTRACT_CLASS_LOG_INPUT: TypeMapping<ContractClassLog> = {
287
- deserialization: {
288
- fn: ([addrReader, fieldsReader, lengthReader]) => {
289
- const addr = AztecAddress.fromField(addrReader.readField());
290
- const fields = new ContractClassLogFields([...fieldsReader.readFieldArray(fieldsReader.remainingFields())]);
291
- const length = lengthReader.readField().toNumber();
292
- return new ContractClassLog(addr, fields, length);
293
- },
294
- // ContractClassLog input occupies 3 ACVM slots: [contractAddress], [message fields...], [length].
295
- slots: 3,
296
- },
297
- };
298
-
299
- export const TX_EFFECT: TypeMapping<TxEffect> = {
300
- serialization: {
301
- fn: (effect: TxEffect) => {
302
- const flatPublicLogs = FlatPublicLogs.fromLogs(effect.publicLogs);
303
- return [
304
- effect.revertCode.toField(),
305
- effect.txHash.hash,
306
- effect.transactionFee,
307
- padArrayEnd(effect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
308
- padArrayEnd(effect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
309
- padArrayEnd(effect.l2ToL1Msgs, Fr.ZERO, MAX_L2_TO_L1_MSGS_PER_TX),
310
- padArrayEnd(
311
- effect.publicDataWrites,
312
- PublicDataWrite.empty(),
313
- MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
314
- ).flatMap(w => w.toFields()),
315
- padArrayEnd(effect.privateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX).flatMap(l => l.toFields()),
316
- new Fr(flatPublicLogs.length),
317
- flatPublicLogs.payload,
318
- padArrayEnd(effect.contractClassLogs, ContractClassLog.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX).flatMap(l => [
319
- ...l.fields.toFields(),
320
- new Fr(l.emittedLength),
321
- l.contractAddress.toField(),
322
- ]),
323
- ] as (Fr | Fr[])[];
324
- },
325
- },
326
- };
419
+ }> = STRUCT([
420
+ { name: 'publicKeys', type: PUBLIC_KEYS },
421
+ { name: 'partialAddress', type: FIELD },
422
+ ]);
423
+
424
+ export const CONTRACT_CLASS_LOG: TypeMapping<ContractClassLogData> = STRUCT([
425
+ { name: 'contractAddress', type: AZTEC_ADDRESS },
426
+ { name: 'fields', type: FIXED_ARRAY(FIELD, CONTRACT_CLASS_LOG_SIZE_IN_FIELDS) },
427
+ { name: 'emittedLength', type: U32 },
428
+ ]);
429
+
430
+ const REVERT_CODE: TypeMapping<RevertCode> = {
431
+ serialization: { fn: rc => [rc.toField()] },
432
+ shape: ['scalar'],
433
+ };
434
+
435
+ const PUBLIC_DATA_WRITE: TypeMapping<PublicDataWrite> = STRUCT<PublicDataWrite>([
436
+ { name: 'leafSlot', type: FIELD },
437
+ { name: 'value', type: FIELD },
438
+ ]);
439
+
440
+ const PRIVATE_LOG: TypeMapping<PrivateLog> = STRUCT<PrivateLog>([
441
+ { name: 'fields', type: FIXED_ARRAY(FIELD, PRIVATE_LOG_SIZE_IN_FIELDS) },
442
+ { name: 'emittedLength', type: U32 },
443
+ ]);
444
+
445
+ const FLAT_PUBLIC_LOGS: TypeMapping<FlatPublicLogs> = STRUCT<FlatPublicLogs>([
446
+ { name: 'length', type: U32 },
447
+ { name: 'payload', type: FIXED_ARRAY(FIELD, FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH) },
448
+ ]);
449
+
450
+ const CONTRACT_CLASS_LOG_ENTRY: TypeMapping<ContractClassLogData> = STRUCT<ContractClassLogData>([
451
+ { name: 'fields', type: FIXED_ARRAY(FIELD, CONTRACT_CLASS_LOG_SIZE_IN_FIELDS) },
452
+ { name: 'emittedLength', type: U32 },
453
+ { name: 'contractAddress', type: AZTEC_ADDRESS },
454
+ ]);
455
+
456
+ const CONTRACT_CLASS_LOGS: TypeMapping<ContractClassLogData[]> = FIXED_ARRAY(
457
+ CONTRACT_CLASS_LOG_ENTRY,
458
+ MAX_CONTRACT_CLASS_LOGS_PER_TX,
459
+ );
460
+
461
+ export const TX_EFFECT: TypeMapping<TxEffectData> = STRUCT<TxEffectData>([
462
+ { name: 'revertCode', type: REVERT_CODE },
463
+ { name: 'txHash', type: TX_HASH },
464
+ { name: 'transactionFee', type: FIELD },
465
+ { name: 'noteHashes', type: FIXED_ARRAY(FIELD, MAX_NOTE_HASHES_PER_TX) },
466
+ { name: 'nullifiers', type: FIXED_ARRAY(FIELD, MAX_NULLIFIERS_PER_TX) },
467
+ { name: 'l2ToL1Msgs', type: FIXED_ARRAY(FIELD, MAX_L2_TO_L1_MSGS_PER_TX) },
468
+ { name: 'publicDataWrites', type: FIXED_ARRAY(PUBLIC_DATA_WRITE, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX) },
469
+ { name: 'privateLogs', type: FIXED_ARRAY(PRIVATE_LOG, MAX_PRIVATE_LOGS_PER_TX) },
470
+ { name: 'publicLogs', type: FLAT_PUBLIC_LOGS },
471
+ { name: 'contractClassLogs', type: CONTRACT_CLASS_LOGS },
472
+ ]);
327
473
 
328
474
  export const NOTE: TypeMapping<NoteData> = {
329
475
  serialization: {
@@ -338,77 +484,161 @@ export const NOTE: TypeMapping<NoteData> = {
338
484
  note: noteData.note,
339
485
  }),
340
486
  },
341
- };
342
-
343
- export const PENDING_TAGGED_LOG: TypeMapping<PendingTaggedLog> = {
344
- serialization: { fn: log => [log.toFields()] },
487
+ // A packed note is the note's (variable-count) field items followed by 6 metadata scalars, emitted as one field
488
+ // output per element. Its length depends on the note, so it is described as a single variable-width run.
489
+ shape: ['variable'],
345
490
  };
346
491
 
347
492
  export const NOTE_VALIDATION_REQUEST: TypeMapping<NoteValidationRequest> = {
348
493
  deserialization: {
349
494
  fn: ([reader]) => NoteValidationRequest.fromFields(reader),
350
- slots: 1,
351
495
  },
496
+ shape: ['variable'],
352
497
  };
353
498
 
354
499
  export const EVENT_VALIDATION_REQUEST: TypeMapping<EventValidationRequest> = {
355
500
  deserialization: {
356
501
  fn: ([reader]) => EventValidationRequest.fromFields(reader),
357
- slots: 1,
358
502
  },
359
- };
360
-
361
- export const LOG_RETRIEVAL_REQUEST: TypeMapping<LogRetrievalRequest> = {
362
- serialization: { fn: req => [req.toFields()] },
503
+ shape: ['variable'],
504
+ };
505
+
506
+ export const LOG_RETRIEVAL_REQUEST: TypeMapping<LogRetrievalRequest> = STRUCT<LogRetrievalRequest>([
507
+ { name: 'contractAddress', type: AZTEC_ADDRESS },
508
+ { name: 'tag', type: TAG },
509
+ { name: 'source', type: LOG_SOURCE },
510
+ { name: 'fromBlock', type: OPTION(BLOCK_NUMBER) },
511
+ { name: 'toBlock', type: OPTION(BLOCK_NUMBER) },
512
+ ]);
513
+
514
+ export const LOG_RETRIEVAL_RESPONSE: TypeMapping<LogRetrievalResponse> = STRUCT<LogRetrievalResponse>([
515
+ { name: 'logPayload', type: FIXED_BOUNDED_VEC(FIELD, PRIVATE_LOG_CIPHERTEXT_LEN) },
516
+ { name: 'txHash', type: TX_HASH },
517
+ { name: 'uniqueNoteHashesInTx', type: FIXED_BOUNDED_VEC(FIELD, MAX_NOTE_HASHES_PER_TX) },
518
+ { name: 'firstNullifierInTx', type: FIELD },
519
+ { name: 'blockNumber', type: BLOCK_NUMBER },
520
+ { name: 'blockTimestamp', type: BIGINT },
521
+ { name: 'blockHash', type: BLOCK_HASH },
522
+ ]);
523
+
524
+ // `ResolvedTx.toFields()` packs the whole struct into a single slot: txHash, the uniqueNoteHashesInTx BoundedVec
525
+ // (MAX_NOTE_HASHES_PER_TX storage fields + length), firstNullifierInTx, blockNumber and blockHash.
526
+ export const RESOLVED_TX: TypeMapping<ResolvedTx> = {
527
+ serialization: { fn: resolved => [resolved.toFields()] },
528
+ shape: [{ len: MAX_NOTE_HASHES_PER_TX + 5 }],
529
+ };
530
+
531
+ export const PENDING_TAGGED_LOG: TypeMapping<PendingTaggedLog> = STRUCT([
532
+ { name: 'log', type: FIXED_BOUNDED_VEC(FIELD, PRIVATE_LOG_SIZE_IN_FIELDS) },
533
+ { name: 'context', type: RESOLVED_TX },
534
+ ]);
535
+
536
+ export const ORIGIN_BLOCK: TypeMapping<OriginBlock> = {
537
+ serialization: { fn: ob => [new Fr(ob.blockNumber), ob.blockHash] },
363
538
  deserialization: {
364
- fn: ([reader]) => LogRetrievalRequest.fromFields(reader),
365
- slots: 1,
539
+ fn: ([blockNumberReader, blockHashReader]) => ({
540
+ blockNumber: blockNumberReader.readField().toNumber(),
541
+ blockHash: blockHashReader.readField(),
542
+ }),
366
543
  },
544
+ shape: ['scalar', 'scalar'],
545
+ };
546
+
547
+ /** Read-side origin of a retractable fact, carrying the chain state of its origin block. */
548
+ export const RETRACTABLE_FACT_ORIGIN: TypeMapping<RetractableFactOrigin> = {
549
+ serialization: { fn: o => [new Fr(o.blockNumber), o.blockHash, new Fr(o.blockState)] },
550
+ shape: ['scalar', 'scalar', 'scalar'],
367
551
  };
368
552
 
369
- export const LOG_RETRIEVAL_RESPONSE: TypeMapping<LogRetrievalResponse> = {
370
- serialization: { fn: resp => [resp.toFields()] },
553
+ // `facts` and `payload` each materialize to a single service-slot id, so a Fact occupies: factTypeId, the payload
554
+ // array slot, and `OPTION(RETRACTABLE_FACT_ORIGIN)` (its discriminant plus RETRACTABLE_FACT_ORIGIN's three slots).
555
+ export const FACT: TypeMapping<Fact> = {
556
+ serialization: {
557
+ fn: f => [
558
+ f.factTypeId,
559
+ f.payload.materializeSlot(v => FIELD.serialization!.fn(v).flat() as Fr[]),
560
+ ...OPTION(RETRACTABLE_FACT_ORIGIN).serialization!.fn(f.originBlock),
561
+ ],
562
+ },
563
+ shape: ['scalar', 'scalar', 'scalar', 'scalar', 'scalar', 'scalar'],
371
564
  };
372
565
 
373
- export const MESSAGE_CONTEXT: TypeMapping<MessageContext> = {
374
- serialization: { fn: mc => [mc.toFields()] },
566
+ export const FACT_COLLECTION: TypeMapping<FactCollection> = {
567
+ serialization: {
568
+ fn: c => [
569
+ c.contractAddress.toField(),
570
+ c.scope.toField(),
571
+ c.factCollectionTypeId,
572
+ c.factCollectionId,
573
+ c.facts.materializeSlot(v => FACT.serialization!.fn(v).flat() as Fr[]),
574
+ ],
575
+ },
576
+ shape: ['scalar', 'scalar', 'scalar', 'scalar', 'scalar'],
375
577
  };
376
578
 
377
579
  export const PROVIDED_SECRET: TypeMapping<ProvidedSecret> = {
378
580
  deserialization: {
379
- fn: ([reader]) => ProvidedSecret.fromFields(reader),
380
- slots: 1,
581
+ fn: ([reader]) => ({
582
+ secret: reader.readField(),
583
+ mode: appTaggingSecretKindFromDeliveryMode(BYTE.deserialization!.fn([reader])),
584
+ }),
381
585
  },
586
+ shape: [{ len: 2 }],
382
587
  };
383
588
 
384
589
  // ─── Combinator Type Mappings ────────────────────────────────────────────────
385
590
 
386
- /** `_height` is unused at runtime but lets TypeScript infer the exact `N` for `MembershipWitness<N>`. */
387
- export function MEMBERSHIP_WITNESS<N extends number>(_height: N): TypeMapping<MembershipWitness<N>> {
591
+ function SIBLING_PATH<N extends number>(height: N): TypeMapping<SiblingPath<N>> {
388
592
  return {
389
- serialization: {
390
- fn: (witness: MembershipWitness<N>) => [new Fr(witness.leafIndex), [...witness.siblingPath]],
391
- },
593
+ serialization: { fn: sp => [sp.toFields()] },
594
+ shape: [{ len: height }],
595
+ };
596
+ }
597
+
598
+ export function MEMBERSHIP_WITNESS<N extends number>(height: N): TypeMapping<MembershipWitness<N>> {
599
+ return STRUCT<MembershipWitness<N>>([
600
+ { name: 'leafIndex', type: BIGINT },
601
+ { name: 'siblingPath', type: FIXED_ARRAY(FIELD, height) },
602
+ ]);
603
+ }
604
+
605
+ export function ARRAY<T>(inner: TypeMapping<T>): TypeMapping<T[]> & { kind: 'array'; inner: TypeMapping<T> } {
606
+ return {
607
+ kind: 'array',
608
+ inner,
609
+ serialization: inner.serialization ? { fn: values => [packElements(inner, values)] } : undefined,
610
+ deserialization: inner.deserialization
611
+ ? {
612
+ // The whole slot is the array, so read as many elements as its fields hold.
613
+ fn: ([reader]) => unpackElements(inner, reader, reader.remainingFields() / fieldWidth(inner.shape)),
614
+ }
615
+ : undefined,
616
+ // One slot of variable length (all elements flattened into it).
617
+ shape: [{ lenFrom: (size: { length: number }) => size.length * fieldWidth(inner.shape) }],
392
618
  };
393
619
  }
394
620
 
395
- export function ARRAY<T>(element: TypeMapping<T>): TypeMapping<T[]> {
621
+ /**
622
+ * Noir's fixed-length array `[T; length]` in one slot: serializes `values` (each flattened via `element`)
623
+ * zero-padded to exactly `length * elementWidth` fields, and deserializes all `length` elements back. An absent
624
+ * element is the zero encoding, so the padding is derived from the shape.
625
+ */
626
+ export function FIXED_ARRAY<T>(
627
+ element: TypeMapping<T>,
628
+ length: number,
629
+ ): TypeMapping<T[]> & { kind: 'fixed-array'; inner: TypeMapping<T>; length: number } {
630
+ const elementWidth = fieldWidth(element.shape);
396
631
  return {
632
+ kind: 'fixed-array',
633
+ inner: element,
634
+ length,
397
635
  serialization: element.serialization
398
- ? { fn: values => [values.flatMap(v => element.serialization!.fn(v).flat())] }
636
+ ? { fn: values => [padArrayEnd(packElements(element, values), Fr.ZERO, length * elementWidth)] }
399
637
  : undefined,
400
638
  deserialization: element.deserialization
401
- ? {
402
- fn: ([reader]) => {
403
- const result: T[] = [];
404
- while (!reader.isFinished()) {
405
- result.push(element.deserialization!.fn([reader]));
406
- }
407
- return result;
408
- },
409
- slots: 1,
410
- }
639
+ ? { fn: ([reader]) => unpackElements(element, reader, length) }
411
640
  : undefined,
641
+ shape: [{ len: length * elementWidth }],
412
642
  };
413
643
  }
414
644
 
@@ -425,129 +655,310 @@ export function ARRAY<T>(element: TypeMapping<T>): TypeMapping<T[]> {
425
655
  * slot 1: Fr(2) // actual length
426
656
  * ```
427
657
  */
428
- export function BOUNDED_VEC<T>(element: TypeMapping<T>): TypeMapping<BoundedVec<T>> {
658
+ export function BOUNDED_VEC<T>(
659
+ inner: TypeMapping<T>,
660
+ ): TypeMapping<BoundedVec<T>> & { kind: 'bounded-vec'; inner: TypeMapping<T> } {
429
661
  return {
430
- serialization: element.serialization
662
+ kind: 'bounded-vec',
663
+ inner,
664
+ serialization: inner.serialization
431
665
  ? {
432
666
  fn: bv => {
433
667
  if (bv.data.length > bv.maxLength) {
434
668
  throw new Error(`Got ${bv.data.length} items, but maxLength is ${bv.maxLength}`);
435
669
  }
436
- const flat = bv.data.flatMap(item => element.serialization!.fn(item).flat());
437
- return [padArrayEnd(flat, Fr.ZERO, bv.maxLength * bv.elementSize), new Fr(bv.data.length)];
670
+ // Fixed-width elements take their width from the shape (consistent with deserialization); only a
671
+ // variable-width element (e.g. a packed note) falls back to the runtime `elementSize` the value carries.
672
+ const elementWidth = tryFieldWidth(inner.shape) ?? bv.elementSize;
673
+ const flat = padArrayEnd(packElements(inner, bv.data), Fr.ZERO, bv.maxLength * elementWidth);
674
+ return [flat, new Fr(bv.data.length)];
438
675
  },
439
676
  }
440
677
  : undefined,
441
- deserialization: element.deserialization
678
+ deserialization: inner.deserialization
442
679
  ? {
443
680
  fn: ([storageReader, lengthReader]) => {
444
- const maxLength = storageReader.remainingFields();
681
+ // slot 0 is the padded storage, slot 1 the actual length. Parse only the first `length` elements out of
682
+ // storage, then drain the trailing zero-padding so the storage reader is fully consumed.
683
+ const maxLength = storageReader.remainingFields() / fieldWidth(inner.shape);
445
684
  const length = lengthReader.readField().toNumber();
446
- const elements: T[] = [];
447
- for (let i = 0; i < length; i++) {
448
- elements.push(element.deserialization!.fn([storageReader]));
449
- }
450
- // Drain the trailing zero-padding (maxLength - length unused element slots) so the storage reader is
451
- // fully consumed.
685
+ const elements = unpackElements(inner, storageReader, length);
452
686
  storageReader.skip(storageReader.remainingFields());
453
687
  return BoundedVec.from<T>({ data: elements, maxLength });
454
688
  },
455
- slots: 2,
456
689
  }
457
690
  : undefined,
691
+ // slot 0: variable-length storage; slot 1: the length scalar.
692
+ shape: [{ lenFrom: (size: { maxLength: number }) => size.maxLength * fieldWidth(inner.shape) }, 'scalar'],
693
+ };
694
+ }
695
+
696
+ /**
697
+ * Noir's `BoundedVec<T, MaxLen>` in its padded form (one fixed-width slot): `maxLength * elementWidth` storage fields
698
+ * (zero-padded) followed by the actual length, with no length prefix, so the width is statically known. Serialize-only.
699
+ * Throws if the input exceeds `maxLength`.
700
+ */
701
+ export function FIXED_BOUNDED_VEC<T>(
702
+ element: TypeMapping<T>,
703
+ maxLength: number,
704
+ ): TypeMapping<T[]> & { kind: 'fixed-bounded-vec'; inner: TypeMapping<T>; maxLength: number } {
705
+ const width = fieldWidth(element.shape);
706
+ return {
707
+ kind: 'fixed-bounded-vec',
708
+ inner: element,
709
+ maxLength,
710
+ serialization: element.serialization
711
+ ? {
712
+ fn: values => {
713
+ if (values.length > maxLength) {
714
+ throw new Error(`Got ${values.length} items, but maxLength is ${maxLength}`);
715
+ }
716
+ const flat = padArrayEnd(packElements(element, values), Fr.ZERO, maxLength * width);
717
+ return [[...flat, new Fr(values.length)]];
718
+ },
719
+ }
720
+ : undefined,
721
+ shape: [{ len: maxLength * width + 1 }],
458
722
  };
459
723
  }
460
724
 
461
725
  /**
462
- * Wraps an inner TypeMapping in Noir-style `Option<T>`. Adds a discriminant slot and uses the handler-provided
463
- * `Option.none(shape)` template to produce a correctly-sized zero-filled output for the None case.
726
+ * Wraps an inner TypeMapping in Noir-style `Option<T>`, adding a leading discriminant slot.
464
727
  *
465
- * @example Serializing `Option.some(AztecAddress.fromField(Fr(42)))` with `OPTION(AZTEC_ADDRESS)`:
728
+ * For the `None` case, the inner's slots must still be present on the wire as zero-padding (so `Some` and `None` have
729
+ * identical size). That padding is derived entirely from `inner.shape`.
730
+ *
731
+ * @example Serializing `Option.some(AztecAddress.fromFieldUnsafe(Fr(42)))` with `OPTION(AZTEC_ADDRESS)`:
466
732
  * ```
467
733
  * slot 0: Fr(1) // discriminant: Some
468
734
  * slot 1: Fr(42) // inner value
469
735
  * ```
470
736
  *
471
- * @example Serializing `Option.empty(AztecAddress.ZERO)` with `OPTION(AZTEC_ADDRESS)`:
737
+ * @example Serializing `Option.none()` with `OPTION(AZTEC_ADDRESS)`:
472
738
  * ```
473
739
  * slot 0: Fr(0) // discriminant: None
474
- * slot 1: Fr(0) // zero-filled using shape
740
+ * slot 1: Fr(0) // zero-filled from AZTEC_ADDRESS.shape
475
741
  * ```
476
742
  */
477
- export function OPTION<T>(inner: TypeMapping<T>): TypeMapping<Option<T>> {
743
+ export function OPTION<T>(inner: TypeMapping<T>): TypeMapping<Option<T>> & { kind: 'option'; inner: TypeMapping<T> } {
478
744
  return {
745
+ kind: 'option',
746
+ inner,
479
747
  serialization: inner.serialization
480
748
  ? {
481
- fn: opt => {
482
- if (opt.isSome()) {
483
- return [Fr.ONE, ...inner.serialization!.fn(opt.value)];
484
- }
485
- if (opt.template === undefined) {
486
- throw new Error(
487
- 'Cannot serialize Option.empty() without an emptyTemplate — provide one via Option.empty(emptyTemplate)',
488
- );
489
- }
490
- const zeroSlots = inner
491
- .serialization!.fn(opt.template)
492
- .map(s => (Array.isArray(s) ? Array(s.length).fill(Fr.ZERO) : Fr.ZERO));
493
- return [Fr.ZERO, ...zeroSlots];
494
- },
749
+ fn: opt =>
750
+ opt.isSome()
751
+ ? [Fr.ONE, ...inner.serialization!.fn(opt.value)]
752
+ : [Fr.ZERO, ...zeroSlotsFromShape(inner.shape, opt.size)],
495
753
  }
496
754
  : undefined,
497
755
  deserialization: inner.deserialization
498
756
  ? {
499
757
  fn: ([discriminant, ...innerReaders]) => {
500
758
  if (discriminant.readField().isZero()) {
501
- // None still carries zero-filled inner slots on the wire; drain them so the inner readers are fully
502
- // consumed.
759
+ // None still carries the inner's zero-padded slots; consume them without parsing, since an inner that
760
+ // validates its fields would reject the zeros.
503
761
  innerReaders.forEach(reader => reader.skip(reader.remainingFields()));
504
- return Option.none<T>(undefined as unknown as T);
762
+ return Option.none<T>();
505
763
  }
506
764
  return Option.some(inner.deserialization!.fn(innerReaders));
507
765
  },
508
- slots: inner.deserialization.slots + 1,
509
766
  }
510
767
  : undefined,
768
+ // A leading discriminant slot followed by the inner's slots.
769
+ shape: ['scalar', ...inner.shape],
511
770
  };
512
771
  }
513
772
 
514
- /** A packed uint buffer (e.g. `[u8; N]` in Noir): 1 slot of packed uint values ↔ `Buffer`. */
515
- export function BUFFER(bitSize: number): TypeMapping<Buffer> {
773
+ /**
774
+ * A fixed packed uint buffer (Noir `[u8; length]` at `bitSize` 8): one slot of `length` packed uint values ↔ `Buffer`.
775
+ * `length` is the field count, which equals the byte count at `bitSize` 8.
776
+ */
777
+ export function BUFFER(bitSize: number, length: number): TypeMapping<Buffer> {
516
778
  return {
517
779
  serialization: {
518
780
  fn: buf => [Array.from(buf).map(b => new Fr(b))],
519
781
  },
520
782
  deserialization: {
521
- fn: ([reader]) => {
522
- const fields = reader.readFieldArray(reader.remainingFields()).map(f => f.toString());
523
- return fromUintArray(fields, bitSize);
524
- },
525
- slots: 1,
783
+ fn: ([reader]) =>
784
+ fromUintArray(
785
+ reader.readFieldArray(length).map(f => f.toString()),
786
+ bitSize,
787
+ ),
526
788
  },
789
+ shape: [{ len: length }],
527
790
  };
528
791
  }
529
792
 
530
793
  export function EPHEMERAL_ARRAY<T>(element: TypeMapping<T>): TypeMapping<EphemeralArray<T>> {
531
- // An EphemeralArray param is a single slot; the per-param assert covers that slot but never sees the
532
- // per-row readers materialized in readAll(). Assert full consumption per row here.
794
+ // EphemeralArray.readAll hands each row's flat fields in as a single reader; reconstruct the element's per-slot
795
+ // readers from its shape, deserialize, and assert the row was fully consumed so a row with trailing fields is
796
+ // rejected.
533
797
  const rowElement: TypeMapping<T> | undefined = element.deserialization
534
798
  ? {
535
799
  deserialization: {
536
- fn: readers => {
537
- const value = element.deserialization!.fn(readers);
538
- assertReadersConsumed(readers);
539
- return value;
540
- },
541
- slots: element.deserialization.slots,
800
+ fn: ([rowReader]) => deserializeElement(element, rowReader.readFieldArray(rowReader.remainingFields())),
542
801
  },
802
+ // `fn` reads the whole row from one reader, so this is one variable-width slot, not the element's multi-slot
803
+ // shape.
804
+ shape: ['variable'],
543
805
  }
544
806
  : undefined;
545
807
  return {
546
808
  serialization: element.serialization
547
- ? { fn: ea => [ea.materializeSlot(v => element.serialization!.fn(v).flat() as Fr[])] }
809
+ ? { fn: ea => [ea.materializeSlot(v => serializeElement(element, v))] }
548
810
  : undefined,
549
811
  deserialization: rowElement
550
- ? { fn: ([reader]) => EphemeralArray.fromSlot(reader.readField(), rowElement), slots: 1 }
812
+ ? { fn: ([reader]) => EphemeralArray.fromSlot(reader.readField(), rowElement) }
551
813
  : undefined,
814
+ // A single slot carrying the array's service-slot id.
815
+ shape: ['scalar'],
552
816
  };
553
817
  }
818
+
819
+ /** A named field within a {@link STRUCT}: it owns however many wire slots its {@link TypeMapping} declares. */
820
+ export type StructField<TName extends string = string, T = any> = { name: TName; type: TypeMapping<T> };
821
+
822
+ /**
823
+ * A Noir struct: its `shape` and (de)serialization are the concatenation of its fields', so callers never hand-write a
824
+ * `shape`. `T` is the struct's TS value type and must match the field layout — serialization reads each field by name
825
+ * off the value, deserialization returns the decoded bag as `T`; convert in the handler, not here, when `T` differs.
826
+ */
827
+ export function STRUCT<T>(
828
+ fields: readonly StructField[],
829
+ ): TypeMapping<T> & { kind: 'struct'; fields: readonly StructField[] } {
830
+ return {
831
+ kind: 'struct',
832
+ fields,
833
+ serialization: fields.every(f => f.type.serialization)
834
+ ? {
835
+ fn: (value: T) => {
836
+ const props = value as any;
837
+ return fields.flatMap(f => f.type.serialization!.fn(props[f.name]));
838
+ },
839
+ }
840
+ : undefined,
841
+ deserialization: fields.every(f => f.type.deserialization)
842
+ ? {
843
+ fn: readers => {
844
+ const props: Record<string, unknown> = {};
845
+ let slot = 0;
846
+ for (const f of fields) {
847
+ const slotCount = f.type.shape.length;
848
+ props[f.name] = f.type.deserialization!.fn(readers.slice(slot, slot + slotCount));
849
+ slot += slotCount;
850
+ }
851
+ return props as T;
852
+ },
853
+ }
854
+ : undefined,
855
+ shape: fields.flatMap(f => f.type.shape),
856
+ };
857
+ }
858
+
859
+ /** Number of InputSlots a deserializable type spans, derived from its {@link TypeMapping.shape}. */
860
+ export function slotsOf(mapping: TypeMapping): number {
861
+ return mapping.shape.length;
862
+ }
863
+
864
+ /** Number of fields a fully-static shape occupies, or `undefined` if any slot is variable-width. */
865
+ export function tryFieldWidth(shape: SlotShape[]): number | undefined {
866
+ let total = 0;
867
+ for (const slot of shape) {
868
+ if (slot === 'scalar') {
869
+ total += 1;
870
+ } else if (typeof slot === 'object' && 'len' in slot) {
871
+ total += slot.len;
872
+ } else {
873
+ return undefined;
874
+ }
875
+ }
876
+ return total;
877
+ }
878
+
879
+ /** Number of fields a fully-static shape occupies. Throws on a variable-width shape, whose field count isn't known. */
880
+ function fieldWidth(shape: SlotShape[]): number {
881
+ const width = tryFieldWidth(shape);
882
+ if (width === undefined) {
883
+ throw new Error('Cannot compute a fixed field width for a variable-width shape');
884
+ }
885
+ return width;
886
+ }
887
+
888
+ /** Reconstructs a value's per-slot readers from a flat run of fields, using its shape (inverse of slot-flattening). */
889
+ function splitByShape(fields: Fr[], shape: SlotShape[]): FieldReader[] {
890
+ const readers: FieldReader[] = [];
891
+ let cursor = 0;
892
+ shape.forEach((slot, i) => {
893
+ if (slot === 'scalar' || (typeof slot === 'object' && 'len' in slot)) {
894
+ const width = slot === 'scalar' ? 1 : slot.len;
895
+ if (cursor + width > fields.length) {
896
+ throw new Error(`Not enough fields to reconstruct shape: needed ${width}, had ${fields.length - cursor}`);
897
+ }
898
+ readers.push(new FieldReader(fields.slice(cursor, cursor + width)));
899
+ cursor += width;
900
+ } else {
901
+ // A variable slot (sized or not) takes whatever remains, so it must be last.
902
+ if (i !== shape.length - 1) {
903
+ throw new Error('A variable-width slot must be last to be reconstructed from a flat field array');
904
+ }
905
+ readers.push(new FieldReader(fields.slice(cursor)));
906
+ cursor = fields.length;
907
+ }
908
+ });
909
+ if (cursor !== fields.length) {
910
+ throw new Error(`Malformed flattened value: ${fields.length - cursor} unexpected trailing field(s)`);
911
+ }
912
+ return readers;
913
+ }
914
+
915
+ /** Serializes one element to its flat fields. Element must be serializable. */
916
+ function serializeElement<T>(element: TypeMapping<T>, value: T): Fr[] {
917
+ return element.serialization!.fn(value).flat();
918
+ }
919
+
920
+ /**
921
+ * Deserializes one element from its exact flat fields, reconstructing its per-slot readers from its shape and asserting
922
+ * they are fully consumed (so trailing fields are rejected). Element must be deserializable.
923
+ */
924
+ function deserializeElement<T>(element: TypeMapping<T>, fields: Fr[]): T {
925
+ const readers = splitByShape(fields, element.shape);
926
+ const value = element.deserialization!.fn(readers);
927
+ assertReadersConsumed(readers);
928
+ return value;
929
+ }
930
+
931
+ /** Flattens `values` into one contiguous run of fields by serializing each element. Element must be serializable. */
932
+ function packElements<T>(element: TypeMapping<T>, values: T[]): Fr[] {
933
+ return values.flatMap(v => serializeElement(element, v));
934
+ }
935
+
936
+ /**
937
+ * Reads `count` fixed-width elements out of a packed run (the inverse of {@link packElements}). Element must be
938
+ * deserializable.
939
+ */
940
+ function unpackElements<T>(element: TypeMapping<T>, reader: FieldReader, count: number): T[] {
941
+ const elementWidth = fieldWidth(element.shape);
942
+ return Array.from({ length: count }, () => deserializeElement(element, reader.readFieldArray(elementWidth)));
943
+ }
944
+
945
+ /** Builds the zero-filled slots for a `None`, matching a `Some`'s wire shape (variable slots sized from `size`). */
946
+ function zeroSlotsFromShape(shape: SlotShape[], size: unknown): (Fr | Fr[])[] {
947
+ return shape.map(slot => {
948
+ if (slot === 'scalar') {
949
+ return Fr.ZERO;
950
+ }
951
+ if (slot === 'variable') {
952
+ throw new Error('Cannot zero-fill an unsized variable-width slot');
953
+ }
954
+ if ('len' in slot) {
955
+ return Array<Fr>(slot.len).fill(Fr.ZERO);
956
+ }
957
+ if (size === undefined) {
958
+ throw new Error(
959
+ 'Serializing Option.none() over a variable-size inner needs a size, e.g. Option.none({ length: n })',
960
+ );
961
+ }
962
+ return Array<Fr>(slot.lenFrom(size)).fill(Fr.ZERO);
963
+ });
964
+ }