|
1 | 1 | # Aztec Virtual Machine (AVM) |
2 | 2 |
|
3 | 3 | :::warning |
4 | | -If you are new developer starting to work on Aztec, feel free to skip this section. It's a quick walkthrough through the AVM, but it is not extremely necessary to read. |
| 4 | +If you are a new developer starting to work on Aztec, feel free to skip this section. It's a quick walkthrough of the AVM and not strictly necessary to read. The most up-to-date version will always be found in the Aztec repository. |
5 | 5 | ::: |
6 | 6 |
|
7 | | -This section is a bottom‑up walkthrough of **how public Aztec code actually runs**. We go from a Noir `fn public …` on your IDE, all the way to an AVM proof that any Ethereum node can check. |
| 7 | +This section is a bottom‑up walkthrough of **how public Aztec code actually runs**. We go from a Noir snippet in your IDE all the way to an AVM proof that any Ethereum node can verify. The goal is to provide quick links to implementations and serve as a handy guide. |
| 8 | + |
| 9 | +At a high level, you write a Noir public function, the transpiler converts Brillig into AVM bytecode, and the sequencer simulates that bytecode, recording side effects and gas. Those side effects feed the public kernel. The transpiler’s entry point is in [`avm-transpiler/src/transpile.rs`](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs) and the instruction encoding is defined in [`avm-transpiler/src/instructions.rs`](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs). |
| 10 | + |
| 11 | +The AVM behaves like a classic fetch -> decode -> execute VM with explicit control flow (`JUMP_32`, `JUMPI_32`, `INTERNALCALL`, `INTERNALRETURN`, `RETURN`, `REVERT_*`) defined in [`avm-transpiler/src/opcodes.rs`](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/opcodes.rs). During transpilation, a Brillig -> AVM program‑counter map is maintained and jump targets are resolved after layout ([PC mapping and resolution](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L445-L449), [resolution pass](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L480-L514)). |
| 12 | + |
| 13 | +Type information is carried on instructions via `AvmTypeTag` (e.g., `SET_*`, `CAST_*`), for reference see [`AvmTypeTag` in instructions.rs](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs#L107-L119) and [SET/CAST generation](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L989-L1061)). Gas is visible at call boundaries and through environment getters: `CALL`/`STATICCALL` take `(l2_gas, da_gas)` operands ([calls](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L602-L644)), the VM exposes `l2GasLeft`/`daGasLeft` via `GETENVVAR_16` ([env getters](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L952-L973)), and the simulator reports L2 gas usage ([e2e assertion](https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts#L98-L109)). |
| 14 | + |
| 15 | +External calls run in forked side‑effect traces, which achieves isolation: on revert, child side effects are discarded. On success they merge into the parent ([fork/merge in SideEffectTrace](https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts#L95-L139)). The modules here support SHA‑256 compression, Poseidon2 permutation, Keccak‑f[1600] permutation, ToRadix (big‑endian), and ECADD directly; MSM is compiled as a procedure during transpilation ([gadget and procedure handling](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L1174-L1319)). This page focuses on the transpiler and simulator, proving happens downstream using the side effects produced here. |
8 | 16 |
|
9 | 17 | ## From Noir Source to AVM Byte‑code |
10 | 18 |
|
11 | | -1. **Compile → ACIR**: `noirc` turns each public function into an ACIR program. |
| 19 | +1. **Compile -> ACIR**: `noirc` turns each public function into an ACIR program. |
12 | 20 |
|
13 | | -2. **Transpile → AVM**: `aztec-avm-transpiler` in |
14 | | - [`src/main.rs`](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/avm-transpiler/src/main.rs) walks every |
15 | | - `BrilligCall` inside the single ACIR function, extracts the Brillig op‑list and replaces it with |
16 | | - AVM instructions: |
| 21 | +2. **Transpile -> AVM**: The transpiler maps Brillig opcodes to AVM opcodes and emits final bytecode via `brillig_to_avm`, also returning a Brillig→AVM PC map for debugging and error attribution: |
| 22 | + - [Transpiler entry](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs) |
| 23 | + - [Instruction encoding](https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs) |
17 | 24 |
|
18 | 25 | ```rust |
19 | 26 | // Pseudocode |
20 | 27 | let brillig = extract_brillig_from_acir(&acir_prog); |
21 | | - let (avm, map) = brillig_to_avm(brillig); // returns Vec<AvmInstruction> |
| 28 | + let (bytecode, pc_map) = brillig_to_avm(&brillig); // returns (Vec<u8>, Vec<usize>) |
22 | 29 | ``` |
23 | 30 |
|
24 | | -3. **Pack & Commit**: The byte‑code is Base‑64 encoded and hashed (Poseidon) into a commitment. The class ID and commitment become part of the “contract class hint”: |
| 31 | +3. **Pack & Commit**: The AVM bytecode comes from the transpiler. Commitment/validation live elsewhere, this page focuses on transpiler and simulator behavior. |
25 | 32 |
|
26 | 33 | ```rust |
27 | 34 | AvmContractClassHint { class_id, artifact_hash, private_functions_root, packed_bytecode } |
28 | 35 | ``` |
29 | 36 |
|
30 | | - That commitment is verified at deploy‑time by the *Bytecode‑Validation Circuit*. |
| 37 | +The bytecode commitment is validated during deployment by protocol circuits. |
31 | 38 |
|
32 | 39 | ## Bootstrapping a Public Call |
33 | 40 |
|
34 | | -When a user asks the sequencer to run `myToken.transferPublic()`, the prover constructs the **Session Input**: |
35 | | - |
36 | | -```text |
37 | | -AvmSessionInputs { |
38 | | - globals, // L1 block data, random seed … |
39 | | - address = contract, // AztecAddress being executed |
40 | | - sender = caller, |
41 | | - l2GasLeft = gasSettings.l2, |
42 | | - daGasLeft = gasSettings.da, |
43 | | - calldata = encoded args, |
44 | | - … |
45 | | -} |
46 | | -``` |
47 | | -Three things are immediately initialised: |
48 | | - |
49 | | -* **Execution Env.**: calldata, sender, fee table. |
50 | | -* **Machine State**: `pc = 0`, `callPtr = 1`, the tagged memory heap. |
51 | | -* **Gas Controller**:`l2GasLeft`, `daGasLeft` (clamped by `clampGasSettingsForAVM`). |
| 41 | +When a user asks the sequencer to run a public function, the AVM simulator receives calldata and reads execution context via environment opcodes (e.g. address, sender, gas left) exposed by `GETENVVAR_16`. See: |
| 42 | +- Env getters map: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L952-L973` |
| 43 | +- Opcode set: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/opcodes.rs` |
52 | 44 |
|
53 | 45 | Everything is now ready for the main loop. |
54 | 46 |
|
55 | | -## One Clock‑Cycle in the AVM |
56 | | - |
57 | | -> Instruction fetch ➜ decode ➜ sub‑ops ➜ commit (repeat until `RETURN` or `REVERT`). |
58 | | -
|
59 | | -1. **Fetch**: `BytecodeTable.lookup(callPtr, pc)` returns an `AvmInstruction`. |
60 | | -2. **Decode**: The static lookup table translates the opcode into a list of *sub‑operations*. |
61 | | -3. **Dispatch**: |
62 | | - * Memory ops → **Memory Controller** (`LOAD`, `STORE`). |
63 | | - * ALU / Hash → dedicated **Chiplet** (e.g. `SHA256COMPRESSION`). |
64 | | - * Storage ↔ **Storage Controller** (`SLOAD`, `SSTORE`). |
65 | | - * Flow → **Control‑Flow Unit** (update `pc`, maybe push/pop call stack). |
66 | | - * Side‑effects → **Accumulator** (`EMITNOTEHASH`, `SENDL2TOL1MSG`). |
67 | | -4. **Update gas**: each op debits `daGas` or `l2Gas` (see `opcodes.yml`). |
68 | | -5. **Increment CLK**: next row in the circuit trace. |
69 | | - |
70 | | -### Worked example: `ADD<u32> a b dst` |
71 | | - |
72 | | -| Sub‑Op | Component | Source | Destination | |
73 | | -| ------- | --------- | ----------- | ----------- | |
74 | | -| `LOAD` | Memory | `M[a]` | `I_a` | |
75 | | -| `LOAD` | Memory | `M[b]` | `I_b` | |
76 | | -| `ADD` | ALU | `I_a`/`I_b` | `I_c` | |
77 | | -| `STORE` | Memory | `I_c` | `M[dst]` | |
| 47 | +## Instruction Encoding & Execution |
78 | 48 |
|
79 | | -All four sub‑ops fit in **one** clock row because no chiplet exceeds row budget. |
| 49 | +AVM instructions are variable‑length, but consistent: opcode -> addressing‑mode (if present) -> operands -> optional type tag -> immediates. Addressing‑mode packs, per operand, an “indirect” bit and a “relative” bit. The word is U8 if $<= 4$ operands, else U16. Operands are encoded as U8/U16/U32/U64/U128 or Field immediates. |
| 50 | +- Encoding order: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs#L61-L80` |
| 51 | +- Addressing‑mode bits: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs#L180-L203` |
| 52 | +- Operand encodings: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs#L121-L156` |
80 | 53 |
|
81 | 54 | ## Memory & Type‑Tags |
82 | 55 |
|
83 | | -* **Address space**: 2³² words, addressed by `u32`. |
84 | | -* **Tag set**: `{uninit,u8,u16,u32,u64,u128,field}`. |
85 | | -* **Rule**: first read of a word after `CALL` sees `0/uninit`; every later read must match the last `STORE`. |
86 | | - |
87 | | -The Memory table columns are: |
88 | | - |
89 | | -``` |
90 | | -CALL_PTR | CLK | ADDR | VAL | TAG | IN_TAG | RW | TAG_ERR |
91 | | -``` |
92 | | - |
93 | | -A mismatch sets `TAG_ERR` ⇒ proof fails. |
| 56 | +Type tags in this layer live on instructions (e.g. `SET_*`, `CAST_*`) via `AvmTypeTag`. |
| 57 | +- `AvmTypeTag`: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/instructions.rs#L107-L119` |
| 58 | +- `SET_*`/`CAST_*` generation: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L989-L1061` |
94 | 59 |
|
95 | 60 | ## Public Storage Access |
96 | 61 |
|
97 | | -High‑level Noir uses `PublicMutable<T>`. |
98 | | -When `storage.admin.write(newAdmin)` is compiled: |
99 | | - |
100 | | -1. Guest code hashes slot with contract address → `siloedSlot`. |
101 | | -2. Compiler emits `SSTORE` with operands `(slotPtr, valPtr)`. |
102 | | -3. Storage Controller translates into two Merkle operations on the **Public Data Tree** and appends a `ContractStorageUpdateRequest` to the side‑effect list. |
103 | | - |
104 | | -Reads (`admin.read()`) create a `ContractStorageRead` object and perform a Merkle *membership* proof instead. |
105 | | - |
106 | | -## Nested Calls & Call Pointers |
107 | | - |
108 | | -`INTERNALCALL` sub‑op does: |
109 | | - |
110 | | -``` |
111 | | -newPtr = nextCallPtr++ // 2,3,4,… in execution order |
112 | | -push {pc+1, curPtr} onto stack |
113 | | -pc = 0 |
114 | | -callPtr = newPtr |
115 | | -``` |
| 62 | +Public storage is accessed via `SLOAD`/`SSTORE` opcodes in the AVM bytecode, produced by the transpiler’s foreign call handlers: |
| 63 | +- Opcodes: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/opcodes.rs#L148-L160` |
| 64 | +- Transpiler handlers: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L1660-L1696` and `#L1564-L1600` |
116 | 65 |
|
117 | | -Each pointer owns its byte‑code slice, memory segment and gas budget. |
118 | | -On `INTERNALRETURN`, the previous context is restored. |
| 66 | +Side effects (including storage writes) are recorded by the simulator’s `SideEffectTrace` with per‑tx limits and a monotonically increasing counter: |
| 67 | +- `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts#L60-L113` |
| 68 | +- Storage write limits and warm/cold tracking: `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts#L153-L194` |
119 | 69 |
|
| 70 | +## Internal Control Flow |
120 | 71 |
|
121 | | -## Gas Accounting in Two Dimensions |
| 72 | +Control flow is explicit: `JUMP_32`, `JUMPI_32`, `INTERNALCALL`, `INTERNALRETURN`, `RETURN`, `REVERT_*`. The transpiler also keeps a Brillig→AVM PC map and resolves jumps once all code (including procedures) is laid out: |
| 73 | +- Opcodes: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/opcodes.rs#L44-L47` |
| 74 | +- Jump resolution and PC mapping: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L445-L449` and `#L480-L514` |
122 | 75 |
|
123 | | -* **l2Gas**: execution work proved in AVM. |
124 | | -* **daGas**: calldata hashed in L1 blobs. |
| 76 | +## Gas |
125 | 77 |
|
126 | | -Every sub‑op carries a `(daCost,l2Cost)` pair. |
127 | | -`clampGasSettingsForAVM` ensures `l2GasUsed_private + l2GasUsed_public ≤ MAX_L2_GAS_PER_TX`. |
| 78 | +- CALL/STATICCALL take explicit `l2_gas` and `da_gas` operands; environment getters expose `l2GasLeft` and `daGasLeft`: |
| 79 | + - Calls: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L602-L644` |
| 80 | + - Env getters (including gas left): `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L952-L973` |
| 81 | +- L2 gas usage is tracked in simulation outputs; see the E2E test assertion: |
| 82 | + - `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts#L98-L109` |
128 | 83 |
|
129 | | -At the end the circuit computes |
| 84 | +## Accrued Sub‑state (Side Effects) |
130 | 85 |
|
131 | | -``` |
132 | | -transactionFee = (gasUsed.da * feePerDaGas) + (gasUsed.l2 * feePerL2Gas) |
133 | | -``` |
| 86 | +The simulator buffers side effects (public data writes, note hashes, nullifiers, L2→L1 messages, public logs) with a counter and enforces protocol limits: |
| 87 | +- `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts#L60-L113` |
| 88 | +- Limits and recorders: `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts#L204-L250` |
134 | 89 |
|
135 | | -and exposes it as a public input. |
| 90 | +## Public Call Phases |
136 | 91 |
|
137 | | -## Accrued Sub‑state |
138 | | - |
139 | | -During execution the Accumulator buffers: |
140 | | - |
141 | | -* **noteHashes**, **nullifiers** |
142 | | -* **L2→L1 messages** (`SENDL2TOL1MSG`) with Eth recipient. |
143 | | -* **Unencrypted logs** for ETH watchers. |
144 | | - |
145 | | -At the end these vectors are packed into |
146 | | -`AvmCircuitPublicInputs.accumulatedData` and passed to the public‑kernel circuit. |
147 | | - |
148 | | -## Circuit Boundary & Public Inputs |
149 | | - |
150 | | -Public columns: |
151 | | - |
152 | | -``` |
153 | | -sessionInputs // one row |
154 | | -calldata[ N ] // fixed length |
155 | | -worldStateAccessTrace.* // many rows |
156 | | -accruedSubstate.* // many rows |
157 | | -sessionResults // one row (gas left, reverted?) |
158 | | -``` |
159 | | - |
160 | | -These are exactly the fields of `AvmCircuitPublicInputs` defined in |
161 | | -`avm_circuit_public_inputs.ts`. A one‑to‑one lookup links each table in the proof to the corresponding column in the public inputs vector. |
| 92 | +Public calls are processed in three phases: Setup (non‑revertible), App Logic (revertible), and Teardown (non‑revertible). See: |
| 93 | +- `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/utils.ts#L3-L16` |
162 | 94 |
|
163 | 95 | ## End‑to‑End Example (cheat‑sheet) |
164 | 96 |
|
165 | | -1. **Dev:** writes: |
166 | | - |
167 | | - ```rust |
168 | | - #[public] |
169 | | - fn set_admin(new_admin: AztecAddress) { |
170 | | - assert(context.msg_sender() == storage.admin.read()); |
171 | | - storage.admin.write(new_admin); |
172 | | - } |
173 | | - ``` |
174 | | - |
175 | | -2. **Client**: compile & transpile → AVM class commitment. |
176 | | - |
177 | | -3. **Tx**: includes calldata `[selector, new_admin]` and gas settings. |
178 | | - |
179 | | -4. **AVM** executes: |
180 | | - |
181 | | - | CLK | callPtr | pc | OP | Gas | |
182 | | - | --: | ------: | -: | ------------------- | ----------------: | |
183 | | - | 0 | 1 | 0 | `CALLDATACOPY` | read arg | |
184 | | - | 1 | 1 | 1 | `SLOAD` (`admin`) | +membership proof | |
185 | | - | 2 | 1 | 2 | `EQ_8` + `REVERT_8` | branch | |
186 | | - | 3 | 1 | 3 | `SSTORE` (`admin`) | +update req | |
187 | | - | 4 | 1 | 4 | `RETURN` | finish | |
188 | | - |
189 | | -5. **Circuit**: proves rows 0‑4 and outputs `accumulatedData` with one |
190 | | - `ContractStorageUpdateRequest`. |
191 | | - |
192 | | -6. **Public‑kernel**: re‑hashes the updated slot, updates the indexed Merkle tree root, and feeds the final proof to the Rollup circuit. |
| 97 | +Put together: calldata is copied in (`CALLDATACOPY`), storage is read or updated (`SLOAD`/`SSTORE`), conditions branch with `JUMPI_32`, external calls use `CALL`/`STATICCALL` (with `(l2_gas, da_gas)` and HeapVector args), and execution terminates with `RETURN` or `REVERT_*`. |
193 | 98 |
|
194 | 99 | ### To keep in mind... |
195 | 100 |
|
196 | | -* AVM byte‑code is generated mechanically from Brillig, committed at deploy time, and proven at runtime. |
197 | | -* Execution is **row‑based**: fetch, decode to sub‑ops, feed to specialised controllers/chiplets. |
198 | | -* Memory and Storage are Merkle‑enforced; type‑tags keep Noir and runtime in lock‑step. |
199 | | -* Two‑dimensional gas model (`da`, `l2`) is baked into every sub‑op. |
200 | | -* The circuit exposes exactly the data the next kernel needs, nothing more, nothing less. |
201 | | - |
202 | | -## References |
203 | | -- [AVM Transpiler](https://github.com/AztecProtocol/aztec-packages/tree/7e505bcd7fcd90a7d5fe893194272157cc9ec848/avm-transpiler) |
204 | | -- [AVM TypeScript](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/avm/avm.ts) |
205 | | -- [AVM Circuit Public Inputs](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/avm/avm_circuit_public_inputs.ts) |
206 | | -- [Contract Storage Read](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/avm/contract_storage_read.ts) |
207 | | -- [Gas](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/avm/gas.ts) |
208 | | -- [Message Pack](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/avm/message_pack.ts) |
209 | | -- [Instruction Set](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/docs/docs/protocol-specs/public-vm/instruction-set.mdx) |
210 | | -- [Type Structs](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/docs/docs/protocol-specs/public-vm/type-structs.md) |
211 | | -- [AVM Circuit](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/docs/docs/protocol-specs/public-vm/avm-circuit.md) |
212 | | -- [Gas Settings](https://github.com/AztecProtocol/aztec-packages/blob/7e505bcd7fcd90a7d5fe893194272157cc9ec848/yarn-project/stdlib/src/gas/gas_settings.ts) |
| 101 | +- AVM bytecode is generated mechanically from Brillig by the transpiler: `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs` |
| 102 | +- Addressing modes: per‑operand indirect/relative bits; instruction layout is opcode -> addressing‑mode -> operands -> optional tag -> immediates. |
| 103 | +- Public storage, logs, messages, note hashes, and nullifiers are recorded via the simulator’s side‑effect trace with per‑tx limits: `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/side_effect_trace.ts` |
| 104 | +- Public calls execute across Setup/App‑Logic/Teardown phases: `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/simulator/src/public/utils.ts#L3-L16` |
| 105 | +- L2 gas usage is observable in simulation outputs; CALL/STATICCALL take `(l2_gas, da_gas)` operands: |
| 106 | + - `https://github.com/AztecProtocol/aztec-packages/blob/next/avm-transpiler/src/transpile.rs#L602-L644` |
| 107 | + - `https://github.com/AztecProtocol/aztec-packages/blob/next/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts#L98-L109` |
0 commit comments