@aztec/pxe 0.0.1-commit.b8a057fa → 0.0.1-commit.be03c316

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 (167) hide show
  1. package/dest/bin/check_oracle_version.js +3 -8
  2. package/dest/bin/index.d.ts +2 -2
  3. package/dest/bin/index.d.ts.map +1 -1
  4. package/dest/bin/index.js +1 -1
  5. package/dest/bin/oracle_version_helpers.d.ts +8 -25
  6. package/dest/bin/oracle_version_helpers.d.ts.map +1 -1
  7. package/dest/bin/oracle_version_helpers.js +11 -219
  8. package/dest/contract/helpers.d.ts +1 -1
  9. package/dest/contract/helpers.d.ts.map +1 -1
  10. package/dest/contract/helpers.js +3 -3
  11. package/dest/contract/skip_sync_contracts.d.ts +11 -0
  12. package/dest/contract/skip_sync_contracts.d.ts.map +1 -0
  13. package/dest/contract/skip_sync_contracts.js +18 -0
  14. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts +39 -0
  15. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts.map +1 -0
  16. package/dest/contract_function_simulator/aztec_node_read_cache.js +60 -0
  17. package/dest/contract_function_simulator/index.d.ts +3 -3
  18. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  19. package/dest/contract_function_simulator/index.js +1 -2
  20. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts +1 -1
  21. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts.map +1 -1
  22. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.js +7 -0
  23. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts +7 -9
  24. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts.map +1 -1
  25. package/dest/contract_function_simulator/noir-structs/resolved_tx.js +3 -44
  26. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts +5 -4
  27. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts.map +1 -1
  28. package/dest/contract_function_simulator/noir-structs/tx_effect_data.js +2 -2
  29. package/dest/contract_function_simulator/oracle/acir_callback.js +1 -1
  30. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts +3 -3
  31. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts.map +1 -1
  32. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.js +34 -1
  33. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts +7 -4
  34. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
  35. package/dest/contract_function_simulator/oracle/oracle_registry.js +40 -13
  36. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts +87 -35
  37. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts.map +1 -1
  38. package/dest/contract_function_simulator/oracle/oracle_type_mappings.js +286 -286
  39. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -1
  40. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  41. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +7 -10
  42. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +14 -8
  43. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  44. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +61 -34
  45. package/dest/entrypoints/client/bundle/index.d.ts +2 -1
  46. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  47. package/dest/entrypoints/client/bundle/index.js +1 -0
  48. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  49. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  50. package/dest/entrypoints/client/bundle/utils.js +10 -4
  51. package/dest/entrypoints/client/lazy/index.d.ts +2 -1
  52. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  53. package/dest/entrypoints/client/lazy/index.js +1 -0
  54. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  55. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  56. package/dest/entrypoints/client/lazy/utils.js +10 -4
  57. package/dest/entrypoints/client/store.d.ts +14 -0
  58. package/dest/entrypoints/client/store.d.ts.map +1 -0
  59. package/dest/entrypoints/client/store.js +42 -0
  60. package/dest/entrypoints/server/index.d.ts +2 -1
  61. package/dest/entrypoints/server/index.d.ts.map +1 -1
  62. package/dest/entrypoints/server/index.js +1 -0
  63. package/dest/entrypoints/server/store.d.ts +18 -0
  64. package/dest/entrypoints/server/store.d.ts.map +1 -0
  65. package/dest/entrypoints/server/store.js +28 -0
  66. package/dest/entrypoints/server/utils.d.ts +1 -1
  67. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  68. package/dest/entrypoints/server/utils.js +8 -2
  69. package/dest/hooks/index.d.ts +2 -2
  70. package/dest/hooks/index.d.ts.map +1 -1
  71. package/dest/hooks/index.js +1 -0
  72. package/dest/hooks/resolve_tagging_secret_strategy.d.ts +3 -1
  73. package/dest/hooks/resolve_tagging_secret_strategy.d.ts.map +1 -1
  74. package/dest/hooks/resolve_tagging_secret_strategy.js +3 -3
  75. package/dest/logs/log_service.d.ts +3 -2
  76. package/dest/logs/log_service.d.ts.map +1 -1
  77. package/dest/logs/log_service.js +12 -3
  78. package/dest/messages/tx_resolver_service.d.ts +2 -2
  79. package/dest/messages/tx_resolver_service.d.ts.map +1 -1
  80. package/dest/messages/tx_resolver_service.js +7 -2
  81. package/dest/notes/note_service.d.ts +1 -1
  82. package/dest/notes/note_service.js +1 -1
  83. package/dest/oracle_version.d.ts +2 -2
  84. package/dest/oracle_version.js +3 -3
  85. package/dest/pxe.d.ts +1 -1
  86. package/dest/pxe.d.ts.map +1 -1
  87. package/dest/pxe.js +8 -5
  88. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts +1 -1
  89. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts.map +1 -1
  90. package/dest/storage/backwards_compatibility_tests/schema_tests.js +26 -2
  91. package/dest/storage/fact_store/index.d.ts +2 -2
  92. package/dest/storage/fact_store/index.d.ts.map +1 -1
  93. package/dest/storage/fact_store/index.js +1 -1
  94. package/dest/storage/fact_store/origin_state.d.ts +3 -1
  95. package/dest/storage/fact_store/origin_state.d.ts.map +1 -1
  96. package/dest/storage/fact_store/origin_state.js +7 -0
  97. package/dest/storage/metadata.d.ts +1 -1
  98. package/dest/storage/metadata.js +1 -1
  99. package/dest/storage/store_identity.d.ts +35 -0
  100. package/dest/storage/store_identity.d.ts.map +1 -0
  101. package/dest/storage/store_identity.js +44 -0
  102. package/dest/storage/tagging_store/sender_tagging_store.d.ts +19 -3
  103. package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
  104. package/dest/storage/tagging_store/sender_tagging_store.js +48 -11
  105. package/dest/tagging/constants.d.ts +3 -2
  106. package/dest/tagging/constants.d.ts.map +1 -1
  107. package/dest/tagging/constants.js +26 -5
  108. package/dest/tagging/index.d.ts +2 -2
  109. package/dest/tagging/index.d.ts.map +1 -1
  110. package/dest/tagging/index.js +1 -1
  111. package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts +9 -4
  112. package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts.map +1 -1
  113. package/dest/tagging/recipient_sync/sync_tagged_private_logs.js +60 -25
  114. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +1 -1
  115. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +1 -1
  116. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
  117. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +6 -2
  118. package/dest/tagging/testing/tag_query_test_utils.d.ts +6 -0
  119. package/dest/tagging/testing/tag_query_test_utils.d.ts.map +1 -0
  120. package/dest/tagging/testing/tag_query_test_utils.js +10 -0
  121. package/package.json +17 -17
  122. package/src/bin/check_oracle_version.ts +3 -10
  123. package/src/bin/index.ts +1 -5
  124. package/src/bin/oracle_version_helpers.ts +11 -268
  125. package/src/contract/helpers.ts +3 -3
  126. package/src/contract/skip_sync_contracts.ts +23 -0
  127. package/src/contract_function_simulator/aztec_node_read_cache.ts +89 -0
  128. package/src/contract_function_simulator/index.ts +23 -3
  129. package/src/contract_function_simulator/noir-structs/resolved_tagging_strategy.ts +8 -0
  130. package/src/contract_function_simulator/noir-structs/resolved_tx.ts +11 -45
  131. package/src/contract_function_simulator/noir-structs/tx_effect_data.ts +4 -3
  132. package/src/contract_function_simulator/oracle/acir_callback.ts +1 -1
  133. package/src/contract_function_simulator/oracle/legacy_oracle_registry.ts +30 -3
  134. package/src/contract_function_simulator/oracle/oracle_registry.ts +32 -11
  135. package/src/contract_function_simulator/oracle/oracle_type_mappings.ts +285 -197
  136. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +17 -12
  137. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +92 -39
  138. package/src/entrypoints/client/bundle/index.ts +1 -0
  139. package/src/entrypoints/client/bundle/utils.ts +15 -3
  140. package/src/entrypoints/client/lazy/index.ts +1 -0
  141. package/src/entrypoints/client/lazy/utils.ts +15 -3
  142. package/src/entrypoints/client/store.ts +54 -0
  143. package/src/entrypoints/server/index.ts +1 -0
  144. package/src/entrypoints/server/store.ts +47 -0
  145. package/src/entrypoints/server/utils.ts +21 -7
  146. package/src/hooks/index.ts +1 -0
  147. package/src/hooks/resolve_tagging_secret_strategy.ts +3 -0
  148. package/src/logs/log_service.ts +11 -2
  149. package/src/messages/tx_resolver_service.ts +8 -8
  150. package/src/notes/note_service.ts +1 -1
  151. package/src/oracle_version.ts +3 -3
  152. package/src/pxe.ts +8 -5
  153. package/src/storage/backwards_compatibility_tests/__snapshots__/RecipientTaggingStore.json +11 -3
  154. package/src/storage/backwards_compatibility_tests/__snapshots__/SenderTaggingStore.json +12 -4
  155. package/src/storage/backwards_compatibility_tests/__snapshots__/opened_stores.json +1 -1
  156. package/src/storage/backwards_compatibility_tests/schema_tests.ts +30 -1
  157. package/src/storage/fact_store/index.ts +1 -0
  158. package/src/storage/fact_store/origin_state.ts +9 -0
  159. package/src/storage/metadata.ts +1 -1
  160. package/src/storage/store_identity.ts +72 -0
  161. package/src/storage/tagging_store/sender_tagging_store.ts +62 -15
  162. package/src/tagging/constants.ts +27 -5
  163. package/src/tagging/index.ts +1 -1
  164. package/src/tagging/recipient_sync/sync_tagged_private_logs.ts +103 -46
  165. package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +1 -1
  166. package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +6 -2
  167. package/src/tagging/testing/tag_query_test_utils.ts +11 -0
@@ -19,9 +19,9 @@ import { Fr } from '@aztec/foundation/curves/bn254';
19
19
  import { EthAddress } from '@aztec/foundation/eth-address';
20
20
  import { FieldReader } from '@aztec/foundation/serialize';
21
21
  import { MembershipWitness, type SiblingPath } from '@aztec/foundation/trees';
22
- import { type ACVMField, fromUintArray } from '@aztec/simulator/client';
22
+ import type { ACVMField } from '@aztec/simulator/client';
23
23
  import { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
24
- import { PublicDataWrite, RevertCode } from '@aztec/stdlib/avm';
24
+ import { PublicDataWrite } from '@aztec/stdlib/avm';
25
25
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
26
26
  import { BlockHash } from '@aztec/stdlib/block';
27
27
  import type { ContractInstancePreimage, PartialAddress } from '@aztec/stdlib/contract';
@@ -52,7 +52,12 @@ import {
52
52
  TxHash,
53
53
  } from '@aztec/stdlib/tx';
54
54
 
55
- import type { OriginBlock, RetractableFactOrigin } from '../../storage/fact_store/index.js';
55
+ import {
56
+ type OriginBlock,
57
+ type OriginBlockState,
58
+ type RetractableFactOrigin,
59
+ originBlockStateFromNumber,
60
+ } from '../../storage/fact_store/index.js';
56
61
  import { BoundedVec } from '../noir-structs/bounded_vec.js';
57
62
  import type { ContractClassLogData } from '../noir-structs/contract_class_log_data.js';
58
63
  import type { EmbeddedCurvePoint } from '../noir-structs/embedded_curve_point.js';
@@ -118,6 +123,23 @@ export type SlotShape = 'scalar' | { len: number } | 'variable' | { lenFrom: (si
118
123
  * Either side is optional — output-only types omit `deserialization`, input-only types omit `serialization`.
119
124
  */
120
125
  export interface TypeMapping<T = any> {
126
+ /**
127
+ * Discriminant for this mapping's shape: which scalar or combinator it is. The `is*Mapping` guards switch on it, and
128
+ * the combinators tag it (`'array'`, `'option'`, `'struct'`, ...). For a scalar it also names the Noir-declared type
129
+ * (`'field'`, `'u32'`), which is then its {@link label}.
130
+ */
131
+ kind: string;
132
+ /**
133
+ * The wire-structural Noir type string the oracle interface hash is computed from:
134
+ * - a scalar's is its bare `kind` (`'field'`);
135
+ * - a combinator's is built from its inner mappings' labels (`'array(field,4)'`, `'option(u32)'`);
136
+ * - a struct's is a nameless `'{field,u32}'`, with nested struct labels spliced into the parent.
137
+ *
138
+ * The label encodes exactly what the wire does, so anything the wire tolerates (field names, struct-in-struct
139
+ * nesting, a TS wrapper over a Noir primitive like `TX_HASH` over `Field`) shares a label — and mappings sharing a
140
+ * label must be wire-equivalent.
141
+ */
142
+ label: string;
121
143
  serialization?: {
122
144
  /** Convert a typed value to ACVM output slot(s). */
123
145
  fn: (value: T) => (Fr | Fr[])[];
@@ -154,78 +176,91 @@ export function assertReadersConsumed(readers: FieldReader[]): void {
154
176
 
155
177
  // ─── Scalar Type Mappings ────────────────────────────────────────────────────
156
178
 
157
- export const FIELD: TypeMapping<Fr> = {
179
+ /**
180
+ * A leaf mapping whose {@link TypeMapping.label} is just its bare {@link TypeMapping.kind}. Its wire shape is arbitrary
181
+ * (several fields, or a variable-width run); a single-field scalar uses the shorter {@link SCALAR} instead.
182
+ */
183
+ export function LEAF<T>(mapping: Omit<TypeMapping<T>, 'label'>): TypeMapping<T> {
184
+ return { ...mapping, label: mapping.kind };
185
+ }
186
+
187
+ /** A {@link LEAF} occupying a single `'scalar'` wire slot, so callers omit the shape. */
188
+ export function SCALAR<T>(mapping: Omit<TypeMapping<T>, 'label' | 'shape'>): TypeMapping<T> {
189
+ return LEAF({ ...mapping, shape: ['scalar'] });
190
+ }
191
+
192
+ export const FIELD: TypeMapping<Fr> = SCALAR({
193
+ kind: 'field',
158
194
  serialization: { fn: v => [v] },
159
195
  deserialization: { fn: ([reader]) => reader.readField() },
160
- shape: ['scalar'],
161
- };
196
+ });
162
197
 
163
- export const BOOL: TypeMapping<boolean> = {
198
+ export const BOOL: TypeMapping<boolean> = SCALAR({
199
+ kind: 'bool',
164
200
  serialization: { fn: v => [new Fr(v ? 1n : 0n)] },
165
201
  deserialization: { fn: ([reader]) => !reader.readField().isZero() },
166
- shape: ['scalar'],
167
- };
202
+ });
168
203
 
169
- export const U32: TypeMapping<number> = {
204
+ export const U32: TypeMapping<number> = SCALAR({
205
+ kind: 'u32',
170
206
  serialization: { fn: v => [new Fr(v)] },
171
- deserialization: {
172
- fn: ([reader]) => {
173
- const value = reader.readField().toBigInt();
174
- if (value > 0xffffffffn) {
175
- throw new Error(`U32 overflow: value ${value} exceeds u32 max (${0xffffffffn})`);
176
- }
177
- return Number(value);
178
- },
179
- },
180
- shape: ['scalar'],
181
- };
207
+ deserialization: { fn: ([reader]) => Number(uintFromField(reader.readField(), 32)) },
208
+ });
182
209
 
183
- export const BLOCK_NUMBER: TypeMapping<BlockNumber> = {
184
- serialization: { fn: v => [new Fr(v)] },
185
- deserialization: { fn: ([reader]) => BlockNumber(reader.readField().toNumber()) },
186
- shape: ['scalar'],
187
- };
210
+ export const BLOCK_NUMBER: TypeMapping<BlockNumber> = ALIAS(U32, {
211
+ wrap: v => BlockNumber(v),
212
+ unwrap: v => v,
213
+ });
188
214
 
189
- /** A u8 byte: serializes to a single Fr; deserializes from a single Fr to a number in [0, 255]. */
190
- export const BYTE: TypeMapping<number> = {
215
+ export const U8: TypeMapping<number> = SCALAR({
216
+ kind: 'u8',
191
217
  serialization: { fn: byte => [new Fr(byte)] },
192
- deserialization: {
193
- fn: ([reader]) => {
194
- const value = reader.readField().toBigInt();
195
- if (value > 0xffn) {
196
- throw new Error(`BYTE overflow: value ${value} exceeds u8 max (255)`);
197
- }
198
- return Number(value);
199
- },
200
- },
201
- shape: ['scalar'],
202
- };
218
+ deserialization: { fn: ([reader]) => Number(uintFromField(reader.readField(), 8)) },
219
+ });
203
220
 
204
221
  // Noir passes `MessageDelivery` onchain variants here.
205
- export const DELIVERY_MODE: TypeMapping<AppTaggingSecretKind> = {
222
+ export const DELIVERY_MODE: TypeMapping<AppTaggingSecretKind> = SCALAR({
223
+ kind: 'onchain-delivery-mode',
206
224
  deserialization: {
207
- fn: readers => appTaggingSecretKindFromDeliveryMode(BYTE.deserialization!.fn(readers)),
225
+ fn: readers => appTaggingSecretKindFromDeliveryMode(U8.deserialization!.fn(readers)),
208
226
  },
209
- shape: BYTE.shape,
210
- };
227
+ });
211
228
 
212
- export const RESOLVED_TAGGING_STRATEGY: TypeMapping<ResolvedTaggingStrategy> = {
229
+ export const RESOLVED_TAGGING_STRATEGY: TypeMapping<ResolvedTaggingStrategy> = LEAF({
230
+ kind: 'resolved-tagging-strategy',
213
231
  serialization: { fn: resolved => resolvedTaggingStrategyToFields(resolved) },
214
232
  deserialization: {
215
233
  fn: ([kindReader, secretReader]) =>
216
234
  resolvedTaggingStrategyFromFields(kindReader.readField().toNumber(), secretReader.readField()),
217
235
  },
218
236
  shape: ['scalar', 'scalar'],
219
- };
237
+ });
220
238
 
221
- export const BIGINT: TypeMapping<bigint> = {
239
+ export const BIGINT: TypeMapping<bigint> = ALIAS(FIELD, {
240
+ wrap: f => f.toBigInt(),
241
+ unwrap: v => new Fr(v),
242
+ });
243
+
244
+ export const U64: TypeMapping<bigint> = SCALAR({
245
+ kind: 'u64',
222
246
  serialization: { fn: v => [new Fr(v)] },
223
- deserialization: { fn: ([reader]) => reader.readField().toBigInt() },
224
- shape: ['scalar'],
225
- };
247
+ deserialization: { fn: ([reader]) => uintFromField(reader.readField(), 64) },
248
+ });
249
+
250
+ export const U128: TypeMapping<bigint> = SCALAR({
251
+ kind: 'u128',
252
+ serialization: { fn: v => [new Fr(v)] },
253
+ deserialization: { fn: ([reader]) => uintFromField(reader.readField(), 128) },
254
+ });
255
+
256
+ export const LEAF_INDEX: TypeMapping<number> = ALIAS(FIELD, {
257
+ wrap: f => f.toNumber(),
258
+ unwrap: v => new Fr(v),
259
+ });
226
260
 
227
261
  /** Reads every field in the slot as a UTF-8 character code. */
228
- export const STR: TypeMapping<string> = {
262
+ export const STR: TypeMapping<string> = LEAF({
263
+ kind: 'str',
229
264
  serialization: { fn: str => [Array.from(Buffer.from(str, 'utf-8')).map(b => new Fr(b))] },
230
265
  deserialization: {
231
266
  fn: ([reader]) => {
@@ -237,69 +272,64 @@ export const STR: TypeMapping<string> = {
237
272
  },
238
273
  },
239
274
  shape: ['variable'],
240
- };
275
+ });
241
276
 
242
- export const AZTEC_ADDRESS: TypeMapping<AztecAddress> = {
277
+ export const AZTEC_ADDRESS: TypeMapping<AztecAddress> = SCALAR({
278
+ kind: 'aztec-address',
243
279
  serialization: { fn: v => [v.toField()] },
244
280
  deserialization: { fn: ([reader]) => AztecAddress.fromFieldUnsafe(reader.readField()) },
245
- shape: ['scalar'],
246
- };
281
+ });
247
282
 
248
- export const BLOCK_HASH: TypeMapping<BlockHash> = {
249
- serialization: { fn: v => [new Fr(v.toBuffer())] },
250
- deserialization: { fn: ([reader]) => new BlockHash(reader.readField()) },
251
- shape: ['scalar'],
252
- };
283
+ export const BLOCK_HASH: TypeMapping<BlockHash> = ALIAS(FIELD, {
284
+ wrap: f => new BlockHash(f),
285
+ unwrap: v => new Fr(v.toBuffer()),
286
+ });
253
287
 
254
- export const FUNCTION_SELECTOR: TypeMapping<FunctionSelector> = {
288
+ export const FUNCTION_SELECTOR: TypeMapping<FunctionSelector> = SCALAR({
289
+ kind: 'function-selector',
255
290
  serialization: { fn: v => [v.toField()] },
256
291
  deserialization: { fn: ([reader]) => FunctionSelector.fromField(reader.readField()) },
257
- shape: ['scalar'],
258
- };
292
+ });
259
293
 
260
- export const NOTE_SELECTOR: TypeMapping<NoteSelector> = {
261
- serialization: { fn: v => [v.toField()] },
262
- deserialization: { fn: ([reader]) => NoteSelector.fromField(reader.readField()) },
263
- shape: ['scalar'],
264
- };
294
+ export const NOTE_SELECTOR: TypeMapping<NoteSelector> = ALIAS(FIELD, {
295
+ wrap: f => NoteSelector.fromField(f),
296
+ unwrap: v => v.toField(),
297
+ });
265
298
 
266
- export const TX_HASH: TypeMapping<TxHash> = {
267
- serialization: { fn: v => [v.hash] },
268
- deserialization: { fn: ([reader]) => TxHash.fromField(reader.readField()) },
269
- shape: ['scalar'],
270
- };
299
+ export const TX_HASH: TypeMapping<TxHash> = ALIAS(FIELD, {
300
+ wrap: f => TxHash.fromField(f),
301
+ unwrap: v => v.hash,
302
+ });
271
303
 
272
- const TAG: TypeMapping<Tag> = {
273
- serialization: { fn: v => [v.value] },
274
- deserialization: { fn: ([reader]) => new Tag(reader.readField()) },
275
- shape: ['scalar'],
276
- };
304
+ const TAG: TypeMapping<Tag> = ALIAS(FIELD, {
305
+ wrap: f => new Tag(f),
306
+ unwrap: v => v.value,
307
+ });
277
308
 
278
309
  export const POINT: TypeMapping<EmbeddedCurvePoint> = STRUCT([
279
310
  { name: 'x', type: FIELD },
280
311
  { name: 'y', type: FIELD },
281
312
  ]);
282
313
 
283
- const LOG_SOURCE: TypeMapping<LogSource> = {
314
+ const LOG_SOURCE: TypeMapping<LogSource> = SCALAR({
315
+ kind: 'log-source',
284
316
  serialization: { fn: v => [new Fr(v)] },
285
317
  deserialization: { fn: ([reader]) => logSourceFromField(reader.readField()) },
286
- shape: ['scalar'],
287
- };
318
+ });
288
319
 
289
- export const ETH_ADDRESS: TypeMapping<EthAddress> = {
320
+ export const ETH_ADDRESS: TypeMapping<EthAddress> = SCALAR({
321
+ kind: 'eth-address',
290
322
  serialization: { fn: v => [v.toField()] },
291
323
  deserialization: { fn: ([reader]) => EthAddress.fromField(reader.readField()) },
292
- shape: ['scalar'],
293
- };
324
+ });
294
325
 
295
- export const SLOT_NUMBER: TypeMapping<SlotNumber> = {
296
- serialization: { fn: v => [new Fr(v)] },
297
- shape: ['scalar'],
298
- };
326
+ export const SLOT_NUMBER: TypeMapping<SlotNumber> = ALIAS(FIELD, {
327
+ unwrap: v => new Fr(v),
328
+ });
299
329
 
300
330
  const APPEND_ONLY_TREE_SNAPSHOT: TypeMapping<AppendOnlyTreeSnapshot> = STRUCT<AppendOnlyTreeSnapshot>([
301
331
  { name: 'root', type: FIELD },
302
- { name: 'nextAvailableLeafIndex', type: U32 },
332
+ { name: 'nextAvailableLeafIndex', type: LEAF_INDEX },
303
333
  ]);
304
334
 
305
335
  const PARTIAL_STATE_REFERENCE: TypeMapping<PartialStateReference> = STRUCT<PartialStateReference>([
@@ -314,8 +344,8 @@ const STATE_REFERENCE: TypeMapping<StateReference> = STRUCT<StateReference>([
314
344
  ]);
315
345
 
316
346
  const GAS_FEES: TypeMapping<GasFees> = STRUCT<GasFees>([
317
- { name: 'feePerDaGas', type: BIGINT },
318
- { name: 'feePerL2Gas', type: BIGINT },
347
+ { name: 'feePerDaGas', type: U128 },
348
+ { name: 'feePerL2Gas', type: U128 },
319
349
  ]);
320
350
 
321
351
  const GLOBAL_VARIABLES: TypeMapping<GlobalVariables> = STRUCT<GlobalVariables>([
@@ -323,7 +353,7 @@ const GLOBAL_VARIABLES: TypeMapping<GlobalVariables> = STRUCT<GlobalVariables>([
323
353
  { name: 'version', type: FIELD },
324
354
  { name: 'blockNumber', type: BLOCK_NUMBER },
325
355
  { name: 'slotNumber', type: SLOT_NUMBER },
326
- { name: 'timestamp', type: BIGINT },
356
+ { name: 'timestamp', type: U64 },
327
357
  { name: 'coinbase', type: ETH_ADDRESS },
328
358
  { name: 'feeRecipient', type: AZTEC_ADDRESS },
329
359
  { name: 'gasFees', type: GAS_FEES },
@@ -427,11 +457,6 @@ export const CONTRACT_CLASS_LOG: TypeMapping<ContractClassLogData> = STRUCT([
427
457
  { name: 'emittedLength', type: U32 },
428
458
  ]);
429
459
 
430
- const REVERT_CODE: TypeMapping<RevertCode> = {
431
- serialization: { fn: rc => [rc.toField()] },
432
- shape: ['scalar'],
433
- };
434
-
435
460
  const PUBLIC_DATA_WRITE: TypeMapping<PublicDataWrite> = STRUCT<PublicDataWrite>([
436
461
  { name: 'leafSlot', type: FIELD },
437
462
  { name: 'value', type: FIELD },
@@ -459,7 +484,7 @@ const CONTRACT_CLASS_LOGS: TypeMapping<ContractClassLogData[]> = FIXED_ARRAY(
459
484
  );
460
485
 
461
486
  export const TX_EFFECT: TypeMapping<TxEffectData> = STRUCT<TxEffectData>([
462
- { name: 'revertCode', type: REVERT_CODE },
487
+ { name: 'revertCode', type: U8 },
463
488
  { name: 'txHash', type: TX_HASH },
464
489
  { name: 'transactionFee', type: FIELD },
465
490
  { name: 'noteHashes', type: FIXED_ARRAY(FIELD, MAX_NOTE_HASHES_PER_TX) },
@@ -471,7 +496,8 @@ export const TX_EFFECT: TypeMapping<TxEffectData> = STRUCT<TxEffectData>([
471
496
  { name: 'contractClassLogs', type: CONTRACT_CLASS_LOGS },
472
497
  ]);
473
498
 
474
- export const NOTE: TypeMapping<NoteData> = {
499
+ export const NOTE: TypeMapping<NoteData> = LEAF({
500
+ kind: 'note',
475
501
  serialization: {
476
502
  fn: noteData =>
477
503
  packAsHintedNote({
@@ -487,21 +513,23 @@ export const NOTE: TypeMapping<NoteData> = {
487
513
  // A packed note is the note's (variable-count) field items followed by 6 metadata scalars, emitted as one field
488
514
  // output per element. Its length depends on the note, so it is described as a single variable-width run.
489
515
  shape: ['variable'],
490
- };
516
+ });
491
517
 
492
- export const NOTE_VALIDATION_REQUEST: TypeMapping<NoteValidationRequest> = {
518
+ export const NOTE_VALIDATION_REQUEST: TypeMapping<NoteValidationRequest> = LEAF({
519
+ kind: 'note-validation-request',
493
520
  deserialization: {
494
521
  fn: ([reader]) => NoteValidationRequest.fromFields(reader),
495
522
  },
496
523
  shape: ['variable'],
497
- };
524
+ });
498
525
 
499
- export const EVENT_VALIDATION_REQUEST: TypeMapping<EventValidationRequest> = {
526
+ export const EVENT_VALIDATION_REQUEST: TypeMapping<EventValidationRequest> = LEAF({
527
+ kind: 'event-validation-request',
500
528
  deserialization: {
501
529
  fn: ([reader]) => EventValidationRequest.fromFields(reader),
502
530
  },
503
531
  shape: ['variable'],
504
- };
532
+ });
505
533
 
506
534
  export const LOG_RETRIEVAL_REQUEST: TypeMapping<LogRetrievalRequest> = STRUCT<LogRetrievalRequest>([
507
535
  { name: 'contractAddress', type: AZTEC_ADDRESS },
@@ -517,82 +545,88 @@ export const LOG_RETRIEVAL_RESPONSE: TypeMapping<LogRetrievalResponse> = STRUCT<
517
545
  { name: 'uniqueNoteHashesInTx', type: FIXED_BOUNDED_VEC(FIELD, MAX_NOTE_HASHES_PER_TX) },
518
546
  { name: 'firstNullifierInTx', type: FIELD },
519
547
  { name: 'blockNumber', type: BLOCK_NUMBER },
520
- { name: 'blockTimestamp', type: BIGINT },
548
+ { name: 'blockTimestamp', type: U64 },
521
549
  { name: 'blockHash', type: BLOCK_HASH },
522
550
  ]);
523
551
 
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
- };
552
+ export const RESOLVED_TX: TypeMapping<ResolvedTx> = STRUCT([
553
+ { name: 'txHash', type: TX_HASH },
554
+ { name: 'uniqueNoteHashesInTx', type: FIXED_BOUNDED_VEC(FIELD, MAX_NOTE_HASHES_PER_TX) },
555
+ { name: 'firstNullifierInTx', type: FIELD },
556
+ { name: 'blockNumber', type: U32 },
557
+ { name: 'blockHash', type: FIELD },
558
+ ]);
530
559
 
531
560
  export const PENDING_TAGGED_LOG: TypeMapping<PendingTaggedLog> = STRUCT([
532
561
  { name: 'log', type: FIXED_BOUNDED_VEC(FIELD, PRIVATE_LOG_SIZE_IN_FIELDS) },
533
562
  { name: 'context', type: RESOLVED_TX },
534
563
  ]);
535
564
 
536
- export const ORIGIN_BLOCK: TypeMapping<OriginBlock> = {
537
- serialization: { fn: ob => [new Fr(ob.blockNumber), ob.blockHash] },
538
- deserialization: {
539
- fn: ([blockNumberReader, blockHashReader]) => ({
540
- blockNumber: blockNumberReader.readField().toNumber(),
541
- blockHash: blockHashReader.readField(),
542
- }),
543
- },
544
- shape: ['scalar', 'scalar'],
545
- };
565
+ export const ORIGIN_BLOCK: TypeMapping<OriginBlock> = STRUCT([
566
+ { name: 'blockNumber', type: U32 },
567
+ { name: 'blockHash', type: FIELD },
568
+ ]);
569
+
570
+ const ORIGIN_BLOCK_STATE: TypeMapping<OriginBlockState> = SCALAR({
571
+ kind: 'origin-block-state',
572
+ serialization: { fn: v => [new Fr(v)] },
573
+ deserialization: { fn: ([reader]) => originBlockStateFromNumber(reader.readField().toNumber()) },
574
+ });
546
575
 
547
576
  /** 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'],
551
- };
577
+ export const RETRACTABLE_FACT_ORIGIN: TypeMapping<RetractableFactOrigin> = STRUCT([
578
+ { name: 'blockNumber', type: U32 },
579
+ { name: 'blockHash', type: FIELD },
580
+ { name: 'blockState', type: ORIGIN_BLOCK_STATE },
581
+ ]);
552
582
 
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'],
564
- };
583
+ export const FACT: TypeMapping<Fact> = STRUCT([
584
+ { name: 'factTypeId', type: FIELD },
585
+ { name: 'payload', type: EPHEMERAL_ARRAY(FIELD) },
586
+ { name: 'originBlock', type: OPTION(RETRACTABLE_FACT_ORIGIN) },
587
+ ]);
565
588
 
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'],
577
- };
589
+ export const FACT_COLLECTION: TypeMapping<FactCollection> = STRUCT([
590
+ { name: 'contractAddress', type: AZTEC_ADDRESS },
591
+ { name: 'scope', type: AZTEC_ADDRESS },
592
+ { name: 'factCollectionTypeId', type: FIELD },
593
+ { name: 'factCollectionId', type: FIELD },
594
+ { name: 'facts', type: EPHEMERAL_ARRAY(FACT) },
595
+ ]);
578
596
 
579
- export const PROVIDED_SECRET: TypeMapping<ProvidedSecret> = {
580
- deserialization: {
581
- fn: ([reader]) => ({
582
- secret: reader.readField(),
583
- mode: appTaggingSecretKindFromDeliveryMode(BYTE.deserialization!.fn([reader])),
584
- }),
585
- },
586
- shape: [{ len: 2 }],
587
- };
597
+ export const PROVIDED_SECRET: TypeMapping<ProvidedSecret> = STRUCT([
598
+ { name: 'secret', type: FIELD },
599
+ { name: 'mode', type: DELIVERY_MODE },
600
+ ]);
588
601
 
589
602
  // ─── Combinator Type Mappings ────────────────────────────────────────────────
590
603
 
591
- function SIBLING_PATH<N extends number>(height: N): TypeMapping<SiblingPath<N>> {
604
+ /**
605
+ * A TS-side alias of `base`: the same Noir type on the wire (it inherits `base`'s `kind`, `label`, and `shape`) but a
606
+ * richer TS value. `wrap` maps a base value to the alias, `unwrap` back; a serialize-only alias passes only `unwrap`.
607
+ */
608
+ export function ALIAS<B, T>(
609
+ base: TypeMapping<B>,
610
+ conversions: { wrap?: (value: B) => T; unwrap?: (value: T) => B },
611
+ ): TypeMapping<T> {
612
+ const { wrap, unwrap } = conversions;
592
613
  return {
614
+ kind: base.kind,
615
+ label: base.label,
616
+ serialization: base.serialization && unwrap ? { fn: value => base.serialization!.fn(unwrap(value)) } : undefined,
617
+ deserialization:
618
+ base.deserialization && wrap ? { fn: readers => wrap(base.deserialization!.fn(readers)) } : undefined,
619
+ shape: base.shape,
620
+ };
621
+ }
622
+
623
+ function SIBLING_PATH<N extends number>(height: N): TypeMapping<SiblingPath<N>> {
624
+ return LEAF({
625
+ // On the wire (and in Noir) a sibling path is a plain `[Field; height]`, so it shares the fixed-array kind.
626
+ kind: `array(field,${height})`,
593
627
  serialization: { fn: sp => [sp.toFields()] },
594
628
  shape: [{ len: height }],
595
- };
629
+ });
596
630
  }
597
631
 
598
632
  export function MEMBERSHIP_WITNESS<N extends number>(height: N): TypeMapping<MembershipWitness<N>> {
@@ -602,9 +636,10 @@ export function MEMBERSHIP_WITNESS<N extends number>(height: N): TypeMapping<Mem
602
636
  ]);
603
637
  }
604
638
 
605
- export function ARRAY<T>(inner: TypeMapping<T>): TypeMapping<T[]> & { kind: 'array'; inner: TypeMapping<T> } {
639
+ export function ARRAY<T>(inner: TypeMapping<T>): ArrayMapping<T> {
606
640
  return {
607
641
  kind: 'array',
642
+ label: `array(${inner.label})`,
608
643
  inner,
609
644
  serialization: inner.serialization ? { fn: values => [packElements(inner, values)] } : undefined,
610
645
  deserialization: inner.deserialization
@@ -623,13 +658,11 @@ export function ARRAY<T>(inner: TypeMapping<T>): TypeMapping<T[]> & { kind: 'arr
623
658
  * zero-padded to exactly `length * elementWidth` fields, and deserializes all `length` elements back. An absent
624
659
  * element is the zero encoding, so the padding is derived from the shape.
625
660
  */
626
- export function FIXED_ARRAY<T>(
627
- element: TypeMapping<T>,
628
- length: number,
629
- ): TypeMapping<T[]> & { kind: 'fixed-array'; inner: TypeMapping<T>; length: number } {
661
+ export function FIXED_ARRAY<T>(element: TypeMapping<T>, length: number): FixedArrayMapping<T> {
630
662
  const elementWidth = fieldWidth(element.shape);
631
663
  return {
632
664
  kind: 'fixed-array',
665
+ label: `array(${element.label},${length})`,
633
666
  inner: element,
634
667
  length,
635
668
  serialization: element.serialization
@@ -649,17 +682,16 @@ export function FIXED_ARRAY<T>(
649
682
  *
650
683
  * Both directions are derived from `element`: bidirectional iff `element` has both serialization and deserialization.
651
684
  *
652
- * @example Serializing `BoundedVec.from({ data: [0x41, 0x42], maxLength: 4 })` with `BOUNDED_VEC(BYTE)`:
685
+ * @example Serializing `BoundedVec.from({ data: [0x41, 0x42], maxLength: 4 })` with `BOUNDED_VEC(U8)`:
653
686
  * ```
654
687
  * slot 0: [Fr(0x41), Fr(0x42), Fr(0), Fr(0)] // data padded to maxLength
655
688
  * slot 1: Fr(2) // actual length
656
689
  * ```
657
690
  */
658
- export function BOUNDED_VEC<T>(
659
- inner: TypeMapping<T>,
660
- ): TypeMapping<BoundedVec<T>> & { kind: 'bounded-vec'; inner: TypeMapping<T> } {
691
+ export function BOUNDED_VEC<T>(inner: TypeMapping<T>): BoundedVecMapping<T> {
661
692
  return {
662
693
  kind: 'bounded-vec',
694
+ label: `bounded-vec(${inner.label})`,
663
695
  inner,
664
696
  serialization: inner.serialization
665
697
  ? {
@@ -698,13 +730,11 @@ export function BOUNDED_VEC<T>(
698
730
  * (zero-padded) followed by the actual length, with no length prefix, so the width is statically known. Serialize-only.
699
731
  * Throws if the input exceeds `maxLength`.
700
732
  */
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 } {
733
+ export function FIXED_BOUNDED_VEC<T>(element: TypeMapping<T>, maxLength: number): FixedBoundedVecMapping<T> {
705
734
  const width = fieldWidth(element.shape);
706
735
  return {
707
736
  kind: 'fixed-bounded-vec',
737
+ label: `bounded-vec(${element.label},${maxLength})`,
708
738
  inner: element,
709
739
  maxLength,
710
740
  serialization: element.serialization
@@ -740,9 +770,10 @@ export function FIXED_BOUNDED_VEC<T>(
740
770
  * slot 1: Fr(0) // zero-filled from AZTEC_ADDRESS.shape
741
771
  * ```
742
772
  */
743
- export function OPTION<T>(inner: TypeMapping<T>): TypeMapping<Option<T>> & { kind: 'option'; inner: TypeMapping<T> } {
773
+ export function OPTION<T>(inner: TypeMapping<T>): OptionMapping<T> {
744
774
  return {
745
775
  kind: 'option',
776
+ label: `option(${inner.label})`,
746
777
  inner,
747
778
  serialization: inner.serialization
748
779
  ? {
@@ -770,32 +801,14 @@ export function OPTION<T>(inner: TypeMapping<T>): TypeMapping<Option<T>> & { kin
770
801
  };
771
802
  }
772
803
 
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> {
778
- return {
779
- serialization: {
780
- fn: buf => [Array.from(buf).map(b => new Fr(b))],
781
- },
782
- deserialization: {
783
- fn: ([reader]) =>
784
- fromUintArray(
785
- reader.readFieldArray(length).map(f => f.toString()),
786
- bitSize,
787
- ),
788
- },
789
- shape: [{ len: length }],
790
- };
791
- }
792
-
793
- export function EPHEMERAL_ARRAY<T>(element: TypeMapping<T>): TypeMapping<EphemeralArray<T>> {
804
+ export function EPHEMERAL_ARRAY<T>(element: TypeMapping<T>): EphemeralArrayMapping<T> {
794
805
  // EphemeralArray.readAll hands each row's flat fields in as a single reader; reconstruct the element's per-slot
795
806
  // readers from its shape, deserialize, and assert the row was fully consumed so a row with trailing fields is
796
807
  // rejected.
797
808
  const rowElement: TypeMapping<T> | undefined = element.deserialization
798
809
  ? {
810
+ kind: element.kind,
811
+ label: element.label,
799
812
  deserialization: {
800
813
  fn: ([rowReader]) => deserializeElement(element, rowReader.readFieldArray(rowReader.remainingFields())),
801
814
  },
@@ -805,6 +818,9 @@ export function EPHEMERAL_ARRAY<T>(element: TypeMapping<T>): TypeMapping<Ephemer
805
818
  }
806
819
  : undefined;
807
820
  return {
821
+ kind: 'ephemeral-array',
822
+ label: `ephemeral-array(${element.label})`,
823
+ inner: element,
808
824
  serialization: element.serialization
809
825
  ? { fn: ea => [ea.materializeSlot(v => serializeElement(element, v))] }
810
826
  : undefined,
@@ -824,11 +840,10 @@ export type StructField<TName extends string = string, T = any> = { name: TName;
824
840
  * `shape`. `T` is the struct's TS value type and must match the field layout — serialization reads each field by name
825
841
  * off the value, deserialization returns the decoded bag as `T`; convert in the handler, not here, when `T` differs.
826
842
  */
827
- export function STRUCT<T>(
828
- fields: readonly StructField[],
829
- ): TypeMapping<T> & { kind: 'struct'; fields: readonly StructField[] } {
843
+ export function STRUCT<T>(fields: readonly StructField[]): StructMapping<T> {
830
844
  return {
831
845
  kind: 'struct',
846
+ label: `{${structFieldLabels(fields)}}`,
832
847
  fields,
833
848
  serialization: fields.every(f => f.type.serialization)
834
849
  ? {
@@ -856,6 +871,79 @@ export function STRUCT<T>(
856
871
  };
857
872
  }
858
873
 
874
+ /**
875
+ * The composite `TypeMapping`s (`ARRAY`/`BOUNDED_VEC`/`OPTION`/`STRUCT`/`FIXED_ARRAY`/`FIXED_BOUNDED_VEC`/
876
+ * `EPHEMERAL_ARRAY`), discriminated by `kind`. The combinators attach `kind` plus the inner mapping(s) at construction;
877
+ * the registry erases params to the base `TypeMapping`, so the guards below recover the structure for recursion.
878
+ */
879
+ export type ArrayMapping<T = any> = TypeMapping<T[]> & { kind: 'array'; inner: TypeMapping<T> };
880
+ export type BoundedVecMapping<T = any> = TypeMapping<BoundedVec<T>> & { kind: 'bounded-vec'; inner: TypeMapping<T> };
881
+ export type OptionMapping<T = any> = TypeMapping<Option<T>> & { kind: 'option'; inner: TypeMapping<T> };
882
+ export type StructMapping<T = any> = TypeMapping<T> & { kind: 'struct'; fields: readonly StructField[] };
883
+ export type FixedArrayMapping<T = any> = TypeMapping<T[]> & {
884
+ kind: 'fixed-array';
885
+ inner: TypeMapping<T>;
886
+ length: number;
887
+ };
888
+ export type FixedBoundedVecMapping<T = any> = TypeMapping<T[]> & {
889
+ kind: 'fixed-bounded-vec';
890
+ inner: TypeMapping<T>;
891
+ maxLength: number;
892
+ };
893
+ export type EphemeralArrayMapping<T = any> = TypeMapping<EphemeralArray<T>> & {
894
+ kind: 'ephemeral-array';
895
+ inner: TypeMapping<T>;
896
+ };
897
+ export type CompositeMapping =
898
+ | ArrayMapping
899
+ | BoundedVecMapping
900
+ | OptionMapping
901
+ | StructMapping
902
+ | FixedArrayMapping
903
+ | FixedBoundedVecMapping
904
+ | EphemeralArrayMapping;
905
+
906
+ export function isArrayMapping(type: TypeMapping<any>): type is ArrayMapping {
907
+ return type.kind === 'array';
908
+ }
909
+ export function isBoundedVecMapping(type: TypeMapping<any>): type is BoundedVecMapping {
910
+ return type.kind === 'bounded-vec';
911
+ }
912
+ export function isOptionMapping(type: TypeMapping<any>): type is OptionMapping {
913
+ return type.kind === 'option';
914
+ }
915
+ export function isStructMapping(type: TypeMapping<any>): type is StructMapping {
916
+ return type.kind === 'struct';
917
+ }
918
+ export function isFixedArrayMapping(type: TypeMapping<any>): type is FixedArrayMapping {
919
+ return type.kind === 'fixed-array';
920
+ }
921
+ export function isFixedBoundedVecMapping(type: TypeMapping<any>): type is FixedBoundedVecMapping {
922
+ return type.kind === 'fixed-bounded-vec';
923
+ }
924
+ export function isEphemeralArrayMapping(type: TypeMapping<any>): type is EphemeralArrayMapping {
925
+ return type.kind === 'ephemeral-array';
926
+ }
927
+
928
+ /**
929
+ * The comma-joined labels of a struct's fields, with nested struct labels spliced into the parent: nesting affects
930
+ * neither the wire (struct slots concatenate) nor the interface, so the label treats nested and flat declarations as
931
+ * the same type.
932
+ */
933
+ function structFieldLabels(fields: readonly StructField[]): string {
934
+ return fields.map(f => (isStructMapping(f.type) ? structFieldLabels(f.type.fields) : f.type.label)).join(',');
935
+ }
936
+
937
+ /** The field's value as a bigint, asserted to fit a `bits`-wide uint. */
938
+ function uintFromField(field: Fr, bits: number): bigint {
939
+ const max = 2n ** BigInt(bits) - 1n;
940
+ const value = field.toBigInt();
941
+ if (value > max) {
942
+ throw new Error(`u${bits} overflow: value ${value} exceeds max (${max})`);
943
+ }
944
+ return value;
945
+ }
946
+
859
947
  /** Number of InputSlots a deserializable type spans, derived from its {@link TypeMapping.shape}. */
860
948
  export function slotsOf(mapping: TypeMapping): number {
861
949
  return mapping.shape.length;