From 05558f441fb587be6b31088c4ea10d9ecf9bedee Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 15:40:01 +0100 Subject: [PATCH 1/6] remaining TODOs --- TODO.md | 17 +++++ TODO_MODE_A.md | 74 ------------------- TODO_MODE_B.md | 52 ------------- docs/security.md | 6 -- .../wallet/migration-embedded-wallet.ts | 7 +- 5 files changed, 20 insertions(+), 136 deletions(-) create mode 100644 TODO.md delete mode 100644 TODO_MODE_A.md delete mode 100644 TODO_MODE_B.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..5ccefd5 --- /dev/null +++ b/TODO.md @@ -0,0 +1,17 @@ +# TODO / Improvements + +## Features + +- **Mask NHK**: Currently the TS SDK passes `Fq.ZERO` as the NHK mask (`migration-base-wallet.ts:getMaskedNhk`). The plan is to compute the mask from the new account's app-siloed nullifier hiding key (`newAccount.getNhkApp(newAppAddress)`) so it can be unmasked in the circuit. + +- **Constants codegen**: Noir constants (`constants.nr`) are manually mirrored in `ts/aztec-state-migration/constants.ts`. Add a build step to auto-generate the TS constants from the Noir source. + +## Testing + +- **More coverage**: Test more scenarios and edge cases — multi-note migrations, duplicate migrations, cross-contract migrations, error paths. + +## PoC limitations (documented in `docs/security.md`) + +- No supply cap enforcement on mint +- No access control on `set_snapshot_height()` (first caller wins) +- In-memory key storage (unencrypted) diff --git a/TODO_MODE_A.md b/TODO_MODE_A.md deleted file mode 100644 index 08d9470..0000000 --- a/TODO_MODE_A.md +++ /dev/null @@ -1,74 +0,0 @@ -# Mode A PoC - Known Limitations & Future Work - -## ~~1. Schnorr-Based Authentication~~ (Done) - -- Nullifier uses note `randomness` instead of `msk`, fixing the dummy nullifier problem. -- `msk` removed from `MigrationArgs` — the circuit receives `mpk` directly. -- Schnorr signature authenticates the migrating user. The signed message binds the claim to a specific recipient and app contract, preventing front-running: -``` -// off-chain (TS client): -notes_hash = poseidon2([note_hash_1, ..., note_hash_N]) -msg = poseidon2(CLAIM_DOMAIN_A, old_rollup, new_rollup, notes_hash, recipient, new_app_address) -sig = schnorr_sign(msk, msg) - -// in-circuit (Noir): -schnorr_verify(sig, mpk, msg) -``` -`msk` stays entirely off-chain — only used for deriving `mpk` and signing. - -## 2. Single Note per Migration Transaction (ExampleApp only) - -The Noir circuit (`migrate_notes_mode_a`) already accepts `[MigrationNoteProofData; N]` and loops over all N notes. However the ExampleApp contract hardcodes `N = 1`, and the TS client builds a proof for exactly one note. For the ExampleApp this is sufficient — `lock_migration_notes_mode_a` consolidates multiple balance notes into a single `migration_data` hash (the total amount), producing one MigrationNote per lock call. - -Apps that create multiple MigrationNotes per lock (e.g. locking distinct asset types) would need the TS client to retrieve all migration notes and build an array of `MigrationNoteProofData` proofs. The library circuit is ready; only the app contract's array size and TS client need updating. - -## ~~3. migration_data_hash: Only a Hash is Stored in the Note~~ (Done) - -`MigrationNote` stores `migration_data_hash: Field` — a `poseidon2_hash` of the original data's packed representation. The `MigrationNote::new` constructor accepts any `T: Packable` and hashes it automatically. - -The original data is now delivered via an encrypted `MigrationDataEvent` emitted by `lock_migration_notes` alongside note creation. The event uses `emit_event_in_private` + `deliver_to` for end-to-end encryption (AES128 ECDH). The `#[event]` macro doesn't support generics, so `MigrationDataEvent` implements `EventInterface` manually with `#[derive(Serialize)]`. - -On the TS side, `getMigrationDataEvents()` on the migration wallet retrieves the decrypted events, and `buildMigrationNoteProof(node, blockNumber, noteDao, migrationDataEvent)` combines note proofs with event data. The higher-level `MigrationBaseWallet.buildMigrationNoteProofs(blockNumber, migrationNotes, migrationDataEvents)` wraps this for batch use. Events should be filtered by `txHash` to match them to the correct lock transaction. - -**TODO:** Consider including a note-identifying hash in the event (e.g. `migration_note_hash`) so wallet clients can match events to notes without relying on `txHash` filtering. The full note hash requires randomness from `create_note`, which isn't easily accessible at event emission time. - -## 4. Supply Cap - -**Current:** No supply cap enforced. The new rollup's ExampleMigrationApp mints freely on each successful migration. - -**Production:** Should enforce a `mintable_supply` cap set at deployment, ideally matching the total locked supply on the old rollup. Without this, a bug or compromised archive root could allow unlimited minting. - -## ~~5. Public Balance Migration~~ (Done) - -Public balance migration is implemented for Mode A. The flow mirrors private migration: -1. **Lock:** `lock_public_for_migration` creates a `MigrationNote` (same as private lock) and enqueues a public call to decrement the user's public balance. -2. **Claim:** `migrate_to_public_mode_a` verifies the `MigrationNote` inclusion proof (same circuit as private claim via `migrate_notes_mode_a`) and mints to the caller's public balance on the new rollup. - -The E2E test (`migration-mode-a.test.ts`) covers both private and public balance migration in a single flow. - -## 7. old_app_address is an Unchecked Witness - -**Current:** On the new rollup, `old_app_address` is read from ExampleApp's `PublicImmutable` storage (set at deployment). The migration circuit trusts this value when siloing the reconstructed note hash. - -**Problem:** If `old_app_address` is set incorrectly at deployment, migrations would silently fail (archive root mismatch). There is no on-chain verification that this address actually corresponds to a legitimate app on the old rollup. - -**Production:** Consider an on-chain registry that maps old rollup app addresses to new rollup app addresses, verified via L1 or governance. - -## 8. L1 migrateArchiveRoot is Permissionless - -**Current:** Anyone can call `L1Migrator.migrateArchiveRoot()` to bridge an archive root snapshot. This is by design (users self-serve), but each call consumes an L1-to-L2 message slot. - -**Consideration:** An attacker could spam `migrateArchiveRoot` calls to fill L1-to-L2 message trees or increase costs. Consider rate limiting or requiring a small bond. - -## ~~9. MSK Persistence is Caller's Responsibility~~ (Done) - -`deriveMasterMigrationSecretKey()` in `ts/aztec-state-migration/keys.ts` now derives the MSK deterministically from the account's secret key via `sha512ToGrumpkinScalar([secretKey, MSK_M_GEN])`. No random generation and no explicit persistence needed — the key can be re-derived from the account secret at any time. - -## ~~10. Decompose aztec-state-migration lib into Separate Validation Functions~~ (Done) - -Archive proof verification is now decomposed into separate steps: -- **Block bridging:** `consume_l1_to_l2_message` (stores trusted archive root) + `register_block` (verifies block header against archive root via Merkle proof). -- **Migration verification:** `migrate_notes_mode_a` receives a `BlockHeader` (not a full archive proof), computes the block hash, and enqueues a public call to `verify_migration_mode_a(block_number, block_hash)`. -- **Note verification** is isolated in `migrate_note()` (inclusion proof + nullifier emission). - -The library exposes `lock_migration_notes` and `migrate_notes_mode_a` as composable functions. Proof data types (`MigrationNoteProofData`, `NoteProofData`) are separate modules. App contracts compose only the pieces they need. diff --git a/TODO_MODE_B.md b/TODO_MODE_B.md deleted file mode 100644 index 9b80a5c..0000000 --- a/TODO_MODE_B.md +++ /dev/null @@ -1,52 +0,0 @@ -# Mode B PoC - Known Limitations & Future Work - -## ~~1. Schnorr Signature Authentication~~ (Done) - -`mode_b/ops.nr` uses `schnorr::verify_signature(mpk, signature, msg)` with a domain-separated message: -``` -msg = poseidon2(CLAIM_DOMAIN_B, old_rollup, current_rollup, notes_hash, recipient, new_app) -sig = schnorr_sign(msk, msg) // off-chain -schnorr_verify(sig, mpk, msg) // in-circuit -``` -The message binds the claim to a specific recipient and app contract, preventing front-running. `msk` stays entirely off-chain. - -## ~~2. Unchecked Siloed Nullifier Witness~~ (Done) - -`migrate_note()` in `mode_b/ops.nr` now computes both `inner_nullifier` and `siloed_nullifier` in-circuit from `nhk_app` (derived from the user's nullifier hiding key `nhk`). Address verification also proves `nhk` matches the note owner by deriving `npk_m` via EC scalar mul and recomputing the owner address. - -## ~~3. Single Note Migration~~ (Done) - -`migrate_notes_mode_b` now accepts `[FullNoteProofData; N]` and loops over all N notes in a single proof. The ExampleApp contract still hardcodes `N = 1`, but the library circuit supports arbitrary batch sizes. - -## ~~4. Public State Migration~~ (Done) - -Public state migration is fully implemented for Mode B with four composable functions in `mode_b/ops.nr`: - -- **`migrate_public_state_mode_b`** — Migrate a standalone public storage value (e.g. `PublicImmutable`, `PublicMutable`). Verifies data existed in the public data tree at snapshot height H via `PublicStateProofData`. -- **`migrate_public_map_state_mode_b`** — Migrate a value from a `Map>`. Derives the storage slot from `base_storage_slot` and `map_keys` via `poseidon2_hash`, then delegates to `migrate_public_state_mode_b`. -- **`migrate_public_map_owned_state_mode_b`** — Migrate an owned map entry. Adds Schnorr signature verification (domain `CLAIM_DOMAIN_B_PUBLIC`) and `MigrationKeyNote` inclusion proof to authenticate the old owner. -- **`derive_map_storage_slot`** — Shared helper that derives nested map slots by iterating `poseidon2_hash_with_separator([slot, key], DOM_SEP__PUBLIC_STORAGE_MAP_SLOT)` for each key. - -## 5. Snapshot Height Governance (MigrationArchiveRegistry) - -**Current:** `set_snapshot_height` uses `initialize()` (write-once — can only be called once, subsequent calls revert). However, there is no access control on who can call it. The function does verify the snapshot block header against a stored archive root via Merkle proof, so the caller cannot set an arbitrary height — it must correspond to a real block within a bridged archive. - -**Production:** Should be restricted to governance or a trusted admin role. The snapshot height is a critical security parameter — setting it too early could exclude valid key registrations, and it should only be set in response to an actual emergency. - -## 6. Supply Cap - -**Current:** No supply cap enforced. The new rollup's ExampleMigrationApp mints freely. - -**Production:** Should enforce `mintable_supply` cap set at activation, ideally matching the total supply of the old rollup's token at snapshot height H. - -## ~~7. Make registered_keys Immutable in MigrationKeyRegistry~~ (Done) - -`registered_keys` now uses `Owned>` in `noir/contracts/migration-key-registry/src/main.nr`, enforcing write-once semantics via `initialize()`. A second call to `register()` by the same user reverts. - -## ~~8. Decompose aztec-state-migration lib into Separate Validation Functions~~ (Done) - -The Mode B library is now well-decomposed: - -- **Private note migration** (`migrate_notes_mode_b`) delegates per-note work to `migrate_note()` which handles inclusion proof, non-nullification proof, and nullifier emission independently. -- **Public state migration** is composed from `migrate_public_state_mode_b` → `migrate_public_map_state_mode_b` → `migrate_public_map_owned_state_mode_b`, each adding one concern (slot derivation, ownership authentication). -- **Proof data types** are separate modules: `KeyNoteProofData`, `NonNullificationProofData`, `PublicStateProofData`, `NoteProofData`. diff --git a/docs/security.md b/docs/security.md index 91c98f5..fa1b202 100644 --- a/docs/security.md +++ b/docs/security.md @@ -86,16 +86,10 @@ The current implementation is a proof-of-concept. The following limitations must - **No supply cap enforcement.** The PoC app contract mints freely on each successful migration. A compromised archive root or bug could allow unlimited minting. Production should enforce a `mintable_supply` cap matching the total locked/snapshot supply. -- **`old_rollup_app_address` is a deployment-time configuration.** The migration circuit reads `old_rollup_app_address` from the new app's immutable public storage. This is not an unchecked witness -- it is constrained by the rollup's public state tree. However, if configured incorrectly at deployment, migrations will silently fail (archive root mismatch). Production should verify this address via an on-chain registry. - - **Snapshot height governance has no access control beyond write-once (critical).** The first caller to `set_snapshot_height` wins. The way this should be done in production is that there should be one (not necessarily trusted) party that deploys the contract with correctly set `snapshot_height` -- a value selected by social consensus. The the party posts the details: contract address in a public venue, and community members verify it. Once this is done, there is no trust required anymore because the contract is immutable. -- **The PoC app contract has no access control on `mint()`/`burn()`.** There is no `#[only_self]` on public struct initialization functions. Production apps must restrict minting to verified migration proofs only. - - **In-memory key storage.** The TS client stores migration keys in memory. Production should use secure storage (hardware wallet, encrypted keystore). -- **Identical storage layout assumed.** Migration proofs assume the old and new rollup contracts use identical storage layouts for the migrated state. If layouts diverge, proofs will fail silently. - ## Audit Recommendations diff --git a/ts/aztec-state-migration/wallet/migration-embedded-wallet.ts b/ts/aztec-state-migration/wallet/migration-embedded-wallet.ts index b195489..6365db5 100644 --- a/ts/aztec-state-migration/wallet/migration-embedded-wallet.ts +++ b/ts/aztec-state-migration/wallet/migration-embedded-wallet.ts @@ -84,16 +84,15 @@ export class MigrationEmbeddedWallet extends MigrationBaseWallet { signingKey, ); const account = await accountManager.getAccount(); + if (!account) { + throw new Error(`Account not found in wallet for address: ${address}`); + } const migrationAccount = new MigrationAccountWithSecretKey( account, secretKey, salt, ); - if (!account) { - throw new Error(`Account not found in wallet for address: ${address}`); - } - return migrationAccount; } From 4f8f14739ad0c5f2ef2c9e2dbc7829e0b9361b27 Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 15:42:03 +0100 Subject: [PATCH 2/6] release todo --- TODO.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.md b/TODO.md index 5ccefd5..2689b68 100644 --- a/TODO.md +++ b/TODO.md @@ -6,6 +6,10 @@ - **Constants codegen**: Noir constants (`constants.nr`) are manually mirrored in `ts/aztec-state-migration/constants.ts`. Add a build step to auto-generate the TS constants from the Noir source. +## Release + +- **Publish TS SDK package**: Run the publish workflow (`.github/workflows/publish.yml`) to publish `aztec-state-migration` to npm. + ## Testing - **More coverage**: Test more scenarios and edge cases — multi-note migrations, duplicate migrations, cross-contract migrations, error paths. From 269a6ff07e2dacacce35947d4b5af9c9798521d0 Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 15:56:42 +0100 Subject: [PATCH 3/6] upd RADME --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0025b95..92e18b0 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,6 @@ yarn clean # Remove all compiled and built artifacts ```sh yarn fmt # Format all code (Noir, Solidity, TypeScript) yarn fmt:check # Check formatting without modifying files (CI use) -yarn ts:build # Compile TypeScript ``` Per-language formatting commands: `yarn noir:fmt`, `yarn sol:fmt`, `yarn ts:fmt` (and their `:check` variants). From a780d1d0f77f667b899de546d8f9cce89b8f62b8 Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 15:57:19 +0100 Subject: [PATCH 4/6] rm unused imports --- ts/aztec-state-migration/mode-b/signature.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ts/aztec-state-migration/mode-b/signature.ts b/ts/aztec-state-migration/mode-b/signature.ts index d728e4b..42c6fcf 100644 --- a/ts/aztec-state-migration/mode-b/signature.ts +++ b/ts/aztec-state-migration/mode-b/signature.ts @@ -1,10 +1,5 @@ -import { Fr, GrumpkinScalar } from "@aztec/aztec.js/fields"; -import { sha512ToGrumpkinScalar } from "@aztec/foundation/crypto/sha512"; -import { - DOM_SEP__CLAIM_A, - DOM_SEP__CLAIM_B, - DOM_SEP__MSK_M_GEN, -} from "../constants.js"; +import { Fr } from "@aztec/aztec.js/fields"; +import { DOM_SEP__CLAIM_B } from "../constants.js"; import { AztecAddress } from "@aztec/stdlib/aztec-address"; import { NoteDao } from "@aztec/stdlib/note"; import { poseidon2Hash } from "@aztec/foundation/crypto/poseidon"; From d2abc679159bf46f823e0ec2b9875503bb16020c Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 15:58:28 +0100 Subject: [PATCH 5/6] restrict visibility --- .../src/mode_a/migration_data_event.nr | 4 ++-- .../src/mode_a/migration_note.nr | 8 ++++---- noir/aztec-state-migration/src/mode_a/mod.nr | 4 ++-- .../src/mode_b/key_note_proof_data.nr | 2 +- .../src/mode_b/non_nullification_proof_data.nr | 12 ++++++------ .../src/mode_b/public_state_proof_data.nr | 12 ++++++------ noir/aztec-state-migration/src/note_proof_data.nr | 12 ++++++------ 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/noir/aztec-state-migration/src/mode_a/migration_data_event.nr b/noir/aztec-state-migration/src/mode_a/migration_data_event.nr index cde238c..48873ce 100644 --- a/noir/aztec-state-migration/src/mode_a/migration_data_event.nr +++ b/noir/aztec-state-migration/src/mode_a/migration_data_event.nr @@ -9,8 +9,8 @@ use aztec::protocol::traits::Serialize; /// does not support generic structs. /// See https://github.com/AztecProtocol/aztec-packages/blob/c6b2615d5119cf306e8b9c903fb00dad08560d32/noir-projects/aztec-nr/aztec/src/macros/utils.nr#L154 #[derive(Serialize)] -pub struct MigrationDataEvent { - pub migration_data: T, +pub(crate) struct MigrationDataEvent { + pub(crate) migration_data: T, } impl EventInterface for MigrationDataEvent { diff --git a/noir/aztec-state-migration/src/mode_a/migration_note.nr b/noir/aztec-state-migration/src/mode_a/migration_note.nr index 27f26ff..5159622 100644 --- a/noir/aztec-state-migration/src/mode_a/migration_note.nr +++ b/noir/aztec-state-migration/src/mode_a/migration_note.nr @@ -25,10 +25,10 @@ use std::embedded_curve_ops::EmbeddedCurvePoint as Point; #[derive(Deserialize, Eq, Serialize, Packable)] #[custom_note] pub struct MigrationNote { - pub note_creator: AztecAddress, - pub mpk: Point, - pub destination_rollup: Field, - pub migration_data_hash: Field, + note_creator: AztecAddress, + mpk: Point, + destination_rollup: Field, + migration_data_hash: Field, } impl MigrationNote { diff --git a/noir/aztec-state-migration/src/mode_a/mod.nr b/noir/aztec-state-migration/src/mode_a/mod.nr index c1119a9..637d412 100644 --- a/noir/aztec-state-migration/src/mode_a/mod.nr +++ b/noir/aztec-state-migration/src/mode_a/mod.nr @@ -1,7 +1,7 @@ -mod migration_lock; -pub use migration_lock::MigrationLock; mod builder; pub use builder::MigrationModeA; +mod migration_lock; +pub use migration_lock::MigrationLock; pub(crate) mod migration_note; pub(crate) mod migration_data_event; diff --git a/noir/aztec-state-migration/src/mode_b/key_note_proof_data.nr b/noir/aztec-state-migration/src/mode_b/key_note_proof_data.nr index 4c911b0..693f7b1 100644 --- a/noir/aztec-state-migration/src/mode_b/key_note_proof_data.nr +++ b/noir/aztec-state-migration/src/mode_b/key_note_proof_data.nr @@ -10,7 +10,7 @@ pub type KeyNoteProofData = NoteProofData; impl NoteProofData { /// Verify the key note inclusion in the [KeyNote] hash tree - pub fn verify_key_note_inclusion( + pub(crate) fn verify_key_note_inclusion( self, context: &mut PrivateContext, migration_archive_registry: AztecAddress, diff --git a/noir/aztec-state-migration/src/mode_b/non_nullification_proof_data.nr b/noir/aztec-state-migration/src/mode_b/non_nullification_proof_data.nr index 9c01172..ea0fde9 100644 --- a/noir/aztec-state-migration/src/mode_b/non_nullification_proof_data.nr +++ b/noir/aztec-state-migration/src/mode_b/non_nullification_proof_data.nr @@ -10,15 +10,15 @@ use aztec::protocol::{ /// A nullifier non-inclusion proof data. #[derive(Serialize, Packable)] pub struct NonNullificationProofData { - pub low_nullifier_value: Field, - pub low_nullifier_next_value: Field, - pub low_nullifier_next_index: Field, - pub low_nullifier_leaf_index: Field, - pub low_nullifier_sibling_path: [Field; NULLIFIER_TREE_HEIGHT], + low_nullifier_value: Field, + low_nullifier_next_value: Field, + low_nullifier_next_index: Field, + low_nullifier_leaf_index: Field, + low_nullifier_sibling_path: [Field; NULLIFIER_TREE_HEIGHT], } impl NonNullificationProofData { - pub fn verify_nullifier_non_inclusion( + pub(crate) fn verify_nullifier_non_inclusion( self, nhk_app: Field, old_app: AztecAddress, diff --git a/noir/aztec-state-migration/src/mode_b/public_state_proof_data.nr b/noir/aztec-state-migration/src/mode_b/public_state_proof_data.nr index 383ba15..60c03db 100644 --- a/noir/aztec-state-migration/src/mode_b/public_state_proof_data.nr +++ b/noir/aztec-state-migration/src/mode_b/public_state_proof_data.nr @@ -12,10 +12,10 @@ use aztec::{ #[derive(Packable, Serialize, Deserialize)] pub(crate) struct PublicStateSlotProofData { - pub next_slot: Field, - pub next_index: Field, - pub leaf_index: Field, - pub sibling_path: [Field; PUBLIC_DATA_TREE_HEIGHT], + pub(crate) next_slot: Field, + pub(crate) next_index: Field, + pub(crate) leaf_index: Field, + pub(crate) sibling_path: [Field; PUBLIC_DATA_TREE_HEIGHT], } impl PublicStateSlotProofData { @@ -61,12 +61,12 @@ pub struct PublicStateProofData { } impl PublicStateProofData { - pub fn public_state_hash(self) -> Field { + pub(crate) fn public_state_hash(self) -> Field { poseidon2_hash(self.data.pack()) } /// Verify public data existed in the public data tree - pub fn migrate_public_state( + pub(crate) fn migrate_public_state( self, context: &mut PrivateContext, base_storage_slot: Field, diff --git a/noir/aztec-state-migration/src/note_proof_data.nr b/noir/aztec-state-migration/src/note_proof_data.nr index 3ded9a6..fb5ac89 100644 --- a/noir/aztec-state-migration/src/note_proof_data.nr +++ b/noir/aztec-state-migration/src/note_proof_data.nr @@ -14,10 +14,10 @@ use aztec::{ #[derive(Serialize, Packable)] pub struct NoteProofData { pub data: T, - pub randomness: Field, - pub nonce: Field, - pub leaf_index: Field, - pub sibling_path: [Field; NOTE_HASH_TREE_HEIGHT], + pub(crate) randomness: Field, + nonce: Field, + leaf_index: Field, + sibling_path: [Field; NOTE_HASH_TREE_HEIGHT], } impl NoteProofData { @@ -33,7 +33,7 @@ impl NoteProofData { /// # Returns /// The unique note hash (after siloing and uniqueness transforms), which can be /// used for nullifier computation. - pub fn verify_note_inclusion( + pub(crate) fn verify_note_inclusion( self, old_app: AztecAddress, note_hash: Field, @@ -49,7 +49,7 @@ impl NoteProofData { } impl NoteProofData { - pub fn note_hash(self, note_owner: AztecAddress, expected_storage_slot: Field) -> Field { + pub(crate) fn note_hash(self, note_owner: AztecAddress, expected_storage_slot: Field) -> Field { self.data.compute_note_hash(note_owner, expected_storage_slot, self.randomness) } } From fd42a9d549eece92aa280a3f6c6c85da76bbb8e7 Mon Sep 17 00:00:00 2001 From: JanKuczma Date: Tue, 3 Mar 2026 16:17:20 +0100 Subject: [PATCH 6/6] rm TODOs --- TODO.md | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 2689b68..0000000 --- a/TODO.md +++ /dev/null @@ -1,21 +0,0 @@ -# TODO / Improvements - -## Features - -- **Mask NHK**: Currently the TS SDK passes `Fq.ZERO` as the NHK mask (`migration-base-wallet.ts:getMaskedNhk`). The plan is to compute the mask from the new account's app-siloed nullifier hiding key (`newAccount.getNhkApp(newAppAddress)`) so it can be unmasked in the circuit. - -- **Constants codegen**: Noir constants (`constants.nr`) are manually mirrored in `ts/aztec-state-migration/constants.ts`. Add a build step to auto-generate the TS constants from the Noir source. - -## Release - -- **Publish TS SDK package**: Run the publish workflow (`.github/workflows/publish.yml`) to publish `aztec-state-migration` to npm. - -## Testing - -- **More coverage**: Test more scenarios and edge cases — multi-note migrations, duplicate migrations, cross-contract migrations, error paths. - -## PoC limitations (documented in `docs/security.md`) - -- No supply cap enforcement on mint -- No access control on `set_snapshot_height()` (first caller wins) -- In-memory key storage (unencrypted)