From 8b7c2a017c8453925e8ab2e2292bdef9854f58e2 Mon Sep 17 00:00:00 2001 From: josh crites Date: Thu, 16 Apr 2026 18:14:47 +0000 Subject: [PATCH 1/2] docs: backfill v4.2.0 migration notes (#22612) ## Summary Move four breaking-change migration notes from the unreleased area into the `## 4.2.0` section of the live developer docs, and add them to the v4.2.0 versioned snapshot: - `GasSettings.default()` renamed to `GasSettings.fallback()` (plus removal of `DEFAULT_GAS_LIMIT` / `DEFAULT_TEARDOWN_GAS_LIMIT`) - `simulateTx` / `executeUtility` / `profileTx` / `proveTx` no longer accept `scopes: 'ALL_SCOPES'` - PXE now scope-enforces capsule operations - `EphemeralArray` replaces `CapsuleArray` in PXE oracle interfaces These notes were written after the v4.2.0 cut but document breaking changes that shipped in 4.2.0, so they belong in the 4.2.0 section of both the live and versioned docs. ## Test plan - [ ] Migration notes render correctly on the docs site - [ ] v4.2.0 versioned docs show the backfilled entries under `## 4.2.0` - [ ] Live developer docs no longer list these entries as unreleased # Conflicts: # docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md # docs/docs-developers/docs/resources/migration_notes.md --- .../docs/resources/migration_notes.md | 445 ++++++++++++++++++ .../docs/resources/migration_notes.md | 180 +++++++ 2 files changed, 625 insertions(+) diff --git a/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md b/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md index 0e7ff3460506..3a01604a1163 100644 --- a/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md +++ b/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md @@ -7,7 +7,452 @@ tags: [migration, updating, sandbox, local network] Aztec is in active development. Each version may introduce breaking changes that affect compatibility with previous versions. This page documents common errors and difficulties you might encounter when upgrading, along with guidance on how to resolve them. +<<<<<<< HEAD:docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md ## TBD +======= +## 4.2.0 + +### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` + +`GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. + +The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. + +A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. + +**Migration:** + +```diff +- import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; +- const settings = GasSettings.default({ maxFeesPerGas }); ++ const settings = GasSettings.fallback({ maxFeesPerGas }); +``` + +**Impact**: Any code referencing `GasSettings.default()`, `DEFAULT_GAS_LIMIT`, or `DEFAULT_TEARDOWN_GAS_LIMIT` will fail to compile. + +### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'` + +The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`, +`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed +`'ALL_SCOPES'` must now specify which addresses will be in scope for the call. + +**Migration:** + +```diff ++ const accounts = await pxe.getRegisteredAccounts(); ++ const scopes = accounts.map(a => a.address); + + // simulateTx +- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' }); ++ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes }); + + // executeUtility +- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' }); ++ await pxe.executeUtility(call, { scopes }); + + // profileTx +- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' }); ++ await pxe.profileTx(txRequest, { profileMode: 'full', scopes }); + + // proveTx +- await pxe.proveTx(txRequest, 'ALL_SCOPES'); ++ await pxe.proveTx(txRequest, scopes); +``` + +**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses. + +### [PXE] Capsule operations are now scope-enforced at the PXE level + +The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error: + +``` +Scope 0x1234... is not in the allowed scopes list: [0xabcd...]. +``` + +The zero address (`AztecAddress::zero()`) is always allowed regardless of the scopes list, preserving backwards compatibility for contracts using the global scope. + +**Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. + +### [aztec.js] `EmbeddedWalletOptions` now uses a unified `pxe` field + +The `pxeConfig` and `pxeOptions` fields on `EmbeddedWalletOptions` have been deprecated in favor of a single `pxe` field that accepts both PXE configuration and dependency overrides (custom prover, store, simulator): + +```diff +const wallet = await EmbeddedWallet.create(nodeUrl, { +- pxeConfig: { proverEnabled: true }, +- pxeOptions: { proverOrOptions: myCustomProver }, ++ pxe: { ++ proverEnabled: true, ++ proverOrOptions: myCustomProver, ++ }, +}); +``` + +The old fields still work but will be removed in a future release. + +### [Aztec.nr] Ephemeral arrays replace capsule arrays in PXE oracle interfaces + +Oracle interfaces between Aztec.nr and PXE now use a new `EphemeralArray` type (`aztec::ephemeral::EphemeralArray`) instead of `CapsuleArray`. Ephemeral arrays live in memory and are scoped by contract call frame, so they no longer need to be addressed by `(contract_address, scope)`. Several public message-discovery and validation functions lost their `recipient`, `scope`, and `contract_address` parameters as a result. + +Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle these APIs automatically. Only contracts that call these functions directly need to update. + +**Migration:** + +```diff + attempt_note_discovery( + contract_address, + tx_hash, + unique_note_hashes_in_tx, + first_nullifier_in_tx, +- recipient, + compute_note_hash, + compute_note_nullifier, + owner, + storage_slot, + randomness, + note_type_id, + packed_note, + ); + +- enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash, scope); ++ enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash); + +- enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash, scope); ++ enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash); + +- validate_and_store_enqueued_notes_and_events(contract_address, scope); ++ validate_and_store_enqueued_notes_and_events(scope); +``` + +The `sync_inbox` function and the `OffchainInboxSync` type now return `EphemeralArray` instead of `CapsuleArray`. Custom message handlers that bind the returned array to an explicit type must update the type annotation. + +**Impact**: Contracts that call the above functions directly (rather than relying on macro-generated code) will fail to compile until the trailing `recipient`, `scope`, and `contract_address` parameters are removed. + +## 4.2.0-aztecnr-rc.2 + +### [Aztec.js] Removed `SingleKeyAccountContract` + +The `SchnorrSingleKeyAccount` contract and its TypeScript wrapper `SingleKeyAccountContract` have been removed. This contract was insecure: it used `ivpk_m` (incoming viewing public key) as its Schnorr signing key, meaning anyone who received a user's viewing key could sign transactions on their behalf. + +**Migration:** + +```diff +- import { SingleKeyAccountContract } from '@aztec/accounts/single_key'; +- const contract = new SingleKeyAccountContract(signingKey); ++ import { SchnorrAccountContract } from '@aztec/accounts/schnorr'; ++ const contract = new SchnorrAccountContract(signingKey); +``` + +**Impact**: If you were using `@aztec/accounts/single_key`, switch to `@aztec/accounts/schnorr` which uses separate keys for encryption and authentication. + +### Custom token FPCs removed from default public setup allowlist + +Token contract functions (like `transfer_in_public` and `_increase_public_balance`) have been removed from the default public setup allowlist. FPCs that accept custom tokens (like the reference `FPC` contract) will not work on public networks, because their setup-phase calls to these functions will be rejected. Token class IDs change with each aztec-nr release, making it impractical to maintain them in the allowlist. + +FPCs that use only Fee Juice still work on all networks, since FeeJuice is a protocol contract with a fixed address in the allowlist. Custom FPCs should only call protocol contract functions (AuthRegistry, FeeJuice) during setup. + +`PublicFeePaymentMethod` and `PrivateFeePaymentMethod` in aztec.js are affected, since they use the reference `FPC` contract which calls Token functions during setup. Switch to `FeeJuicePaymentMethodWithClaim` (after [bridging Fee Juice from L1](../aztec-js/how_to_pay_fees.md#bridge-fee-juice-from-l1)) or write an FPC that uses Fee Juice natively. + +**Migration:** + +```diff +- import { PublicFeePaymentMethod } from '@aztec/aztec.js/fee'; +- const paymentMethod = new PublicFeePaymentMethod(fpcAddress, senderAddress, wallet, gasSettings); ++ import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee'; ++ const paymentMethod = new FeeJuicePaymentMethodWithClaim(senderAddress, claim); +``` + +Similarly, the `fpc-public` and `fpc-private` CLI wallet payment methods use the reference Token-based FPC and will not work on public networks. Use `fee_juice` for direct Fee Juice payment, or `fpc-sponsored` on devnet and local network. + +### [Aztec.nr] Domain-separated tags on log emission + +All logs emitted through the Aztec.nr framework now include a domain-separated tag at `fields[0]`. Each log category uses its own domain separator via `compute_log_tag(raw_tag, dom_sep)`: + +- **Events** (`DOM_SEP__EVENT_LOG_TAG`): the event type ID is the raw tag. +- **Message delivery** (`DOM_SEP__UNCONSTRAINED_MSG_LOG_TAG`): the discovery tag is the raw tag. +- **Partial note completion logs** (`DOM_SEP__NOTE_COMPLETION_LOG_TAG`): the partial note's `commitment` field is the raw tag. + +The low-level emit methods now take `tag` as an explicit first parameter and have been renamed with an `_unsafe` suffix. Previously the tag was included as `log[0]` — it has now been extracted into its own parameter, and `log` no longer contains it: + +```diff +- context.emit_private_log(log, length); ++ context.emit_private_log_unsafe(tag, log, length); +- context.emit_raw_note_log(log, length, note_hash_counter); ++ context.emit_raw_note_log_unsafe(tag, log, length, note_hash_counter); +- context.emit_public_log(log); ++ context.emit_public_log_unsafe(tag, log); +``` + +Prefer the higher-level APIs (`emit` for events, `MessageDelivery` for messages) which handle tagging automatically. + +### [Aztec.nr] Public events no longer include the event type selector at the end of the payload + +`emit_event_in_public` previously appended the event type selector as the last field. It now prepends a domain-separated tag at `fields[0]` instead. The payload after the tag contains only the serialized event fields. + +If you were reading public event directly from node logs (i.e. via `node.getPublicLogs` and not via `wallet.getPublicEvents`), update your parsing: + +```diff +- // Old: fields = [serialized_event..., event_type_selector] +- const selector = EventSelector.fromField(fields[fields.length - 1]); +- const event = decodeFromAbi([abiType], fields); ++ // New: fields = [domain_separated_tag, serialized_event...] ++ const eventFields = log.getEmittedFieldsWithoutTag(); ++ const event = decodeFromAbi([abiType], eventFields); +``` + +### [Aztec.nr] Capsule operations are now addressed by scope + +All capsule operations (`store`, `load`, `delete`, `copy`) and `CapsuleArray` now require a `scope: AztecAddress` parameter. This scopes capsule storage by address, providing isolation between different accounts within the same PXE. + +Contracts that use `CapsuleArray` directly also need to update. + +**Migration:** + +```diff +- let array: CapsuleArray = CapsuleArray::at(contract_address, slot); ++ let array: CapsuleArray = CapsuleArray::at(contract_address, slot, scope); +``` + +The low-level capsule functions are similarly affected: + +```diff +- capsules::store(contract_address, slot, value); ++ capsules::store(contract_address, slot, value, scope); + +- capsules::load(contract_address, slot); ++ capsules::load(contract_address, slot, scope); + +- capsules::delete(contract_address, slot); ++ capsules::delete(contract_address, slot, scope); + +- capsules::copy(contract_address, src_slot, dst_slot, num_entries); ++ capsules::copy(contract_address, src_slot, dst_slot, num_entries, scope); +``` + +If you need to stick the old, scope-less behavior, and you are really sure that that's what you need to use, you can use `scope = AztecAddress::zero()`. + +### [Aztec.nr] `process_message` utility function removed + +The auto-generated `process_message` utility function has been removed. If you need to deliver offchain messages (messages not broadcast via onchain logs), use the `offchain_receive` utility function instead. This function is automatically injected by the `#[aztec]` macro and accepts messages into a persistent inbox scoped by recipient. These messages are then picked up and processed during `sync_state`. + +**Impact**: Contracts that explicitly called `process_message` must switch to delivering messages via `offchain_receive` and letting `sync_state` handle processing. + +### [Aztec.nr] `CustomMessageHandler` type signature changed + +The `CustomMessageHandler` function type now receives an additional `scope: AztecAddress` parameter: + +```diff + type CustomMessageHandler = unconstrained fn( + AztecAddress, // contract_address + u64, // msg_type_id + u64, // msg_metadata + BoundedVec, // msg_content + MessageContext, // message_context ++ AztecAddress, // scope + ); +``` + +**Impact**: Contracts that implement a custom message handler must update the function signature. + +### [aztec.js] `isContractInitialized` is now `initializationStatus` tri-state enum + +`ContractMetadata.isContractInitialized` has been renamed to `ContractMetadata.initializationStatus` and changed from `boolean | undefined` to a `ContractInitializationStatus` enum with values `INITIALIZED`, `UNINITIALIZED`, and `UNKNOWN`. + +- `INITIALIZED`: the contract has been initialized (initialization nullifier found) +- `UNINITIALIZED`: the contract instance is registered but has not been initialized +- `UNKNOWN`: the instance is not registered and no public initialization nullifier was found + +When the instance is not registered, the wallet now attempts to check the public initialization nullifier (computed from address alone) before returning `UNKNOWN`. Previously this case returned `undefined`. + +**Migration:** + +```diff ++ import { ContractInitializationStatus } from '@aztec/aztec.js/wallet'; + + const metadata = await wallet.getContractMetadata(address); +- if (metadata.isContractInitialized) { ++ if (metadata.initializationStatus === ContractInitializationStatus.INITIALIZED) { + // contract is initialized + } +``` + +### [Aztec.js] Use `NO_FROM` instead of `AztecAddress.ZERO` to bypass account contract entrypoint + +When sending transactions that should not be mediated by an account contract (e.g., account contract self-deployments), use the explicit `NO_FROM` sentinel instead of `AztecAddress.ZERO`. + +`NO_FROM` signals that the transaction should be executed directly via the `DefaultEntrypoint`. This replaces the brittle convention of passing `AztecAddress.ZERO` as the `from` field. + +**Migration:** + +```diff +- import { AztecAddress } from '@aztec/aztec.js'; ++ import { NO_FROM } from '@aztec/aztec.js/account'; + + await contract.methods.my_method().send({ +- from: AztecAddress.ZERO, ++ from: NO_FROM, + }); +``` + +Note that `DefaultEntrypoint` only accepts a single call. If you need to execute multiple calls without account contract mediation (e.g., deploying an account contract and paying a fee in the same transaction), wrap them through `DefaultMultiCallEntrypoint` on the app side before sending: + +```typescript +import { NO_FROM } from "@aztec/aztec.js/account"; +import { DefaultMultiCallEntrypoint } from "@aztec/entrypoints/multicall"; +import { mergeExecutionPayloads } from "@aztec/stdlib/tx"; + +// Merge multiple execution payloads into one +const merged = mergeExecutionPayloads([deployPayload, feePayload]); + +// Wrap through multicall so it becomes a single call for DefaultEntrypoint +const multicall = new DefaultMultiCallEntrypoint(); +const chainInfo = await wallet.getChainInfo(); +const wrappedPayload = await multicall.wrapExecutionPayload(merged, chainInfo); + +// Send without account contract mediation +await wallet.sendTx(wrappedPayload, { from: NO_FROM }); +``` + +Using other contracts for wrapping (for example, supporting more calls) is also supported, as long as the contract is registered in the wallet. This opens the door to different flows that do not use account entrypoints as the first call in the chain, including app sponsored FPCs. + +**Impact**: Any code that passes `AztecAddress.ZERO` as the `from` option in `.send()`, `.simulate()`, or deploy options must switch to `NO_FROM`. Wallets use `DefaultEntrypoint` directly for `NO_FROM` transactions, instead of the `DefaultMultiCallEntrypoint` that was used internally before when specifying `AztecAddress.ZERO`. + +### [Aztec.js] `ExecuteUtilityOptions.scope` renamed to `scopes` and type changed to `AztecAddress[]` + +The `scope` field in `ExecuteUtilityOptions` has been renamed to `scopes` and changed from a single `AztecAddress` to `AztecAddress[]`. This aligns the wallet's `executeUtility` API with the PXE API and `sendTx` in `Wallet`, which both accept an array of scopes. + +**Migration:** + +```diff + wallet.executeUtility(call, { +- scope: myAddress, ++ scopes: [myAddress], + }); +``` + +**Impact**: Any code that calls `wallet.executeUtility` directly must update the options object. Wallets must update to adapt to the new interface + +### [Aztec.nr] `attempt_note_discovery` now takes two separate functions instead of one + +The `attempt_note_discovery` function (and related discovery functions like `do_sync_state`, `process_message_ciphertext`) now takes separate `compute_note_hash` and `compute_note_nullifier` arguments instead of a single combined `compute_note_hash_and_nullifier`. The corresponding type aliases are now `ComputeNoteHash` and `ComputeNoteNullifier` (instead of `ComputeNoteHashAndNullifier`). + +This split improves performance during nonce discovery: the note hash only needs to be computed once, while the old combined function recomputed it for every candidate nonce. + +Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle this automatically. Only contracts that call `attempt_note_discovery` directly need to update. + +**Migration:** + +```diff + attempt_note_discovery( + contract_address, + tx_hash, + unique_note_hashes_in_tx, + first_nullifier_in_tx, + recipient, +- _compute_note_hash_and_nullifier, ++ _compute_note_hash, ++ _compute_note_nullifier, + owner, + storage_slot, + randomness, + note_type_id, + packed_note, + ); +``` + +**Impact**: Contracts that call `attempt_note_discovery` or related discovery functions directly with a custom `_compute_note_hash_and_nullifier` argument. The old combined function is still generated (deprecated) but is no longer used by the framework. Additionally, if you had a custom `_compute_note_hash_and_nullifier` function then compilation will now fail as you'll need to also produce the corresponding `_compute_note_hash` and `_compute_note_nullifier` functions. + +### Private initialization nullifier now includes `init_hash` + +The private initialization nullifier is no longer derived from just the contract address. It is now computed as a Poseidon2 hash of `[address, init_hash]` using a dedicated domain separator. This prevents observers from determining whether a fully private contract has been initialized by simply knowing its address. + +Note that `Wallet.getContractMetadata` now returns `initializationStatus: ContractInitializationStatus.UNKNOWN` when the wallet does not have the contract instance registered, since `init_hash` is needed to compute the nullifier and initialization status cannot be determined. Previously, this check worked for any address. Callers should check the enum value before branching on the initialization state. + +If you use `assert_contract_was_initialized_by` or `assert_contract_was_not_initialized_by` from `aztec::history::deployment`, these now require an additional `init_hash: Field` parameter: + +```diff ++ let instance = get_contract_instance(contract_address); + assert_contract_was_initialized_by( + block_header, + contract_address, ++ instance.initialization_hash, + ); +``` + +### Two separate init nullifiers for private and public + +Contract initialization now emits two separate nullifiers instead of one: a **private init nullifier** and a **public init nullifier**. Each nullifier gates its respective execution domain: + +- Private external functions check the private init nullifier. +- Public external functions check the public init nullifier. + +**How initializers work:** + +- **Private initializers** emit the private init nullifier. If the contract has any external public functions, the protocol auto-enqueues a public call to emit the public init nullifier. +- **Public initializers** emit both nullifiers directly. +- Contracts with no public functions only emit the private init nullifier. + +**`only_self` functions no longer have init checks.** They behave as if marked `noinitcheck`. + +**External functions called during private initialization must be `#[only_self]`.** Init nullifiers are emitted at the end of the initializer, so any external functions called on the initializing contract (e.g. via `enqueue_self` or `call_self`) during initialization will fail the init check unless they skip it. + +**Breaking change for deployment:** If your contract has external public functions and a private initializer, the class must be registered onchain before initialization. You can no longer pass `skipClassPublication: true`, because the auto-enqueued public call requires the class to be available. + +```diff + const deployed = await MyContract.deploy(wallet, ...args).send({ +- skipClassPublication: true, + }).deployed(); +``` + +### [Aztec.nr] Made `compute_note_hash_for_nullification` unconstrained + +This function shouldn't have been constrained in the first place, as constrained computation of `HintedNote` nullifiers is dangerous (constrained computation of nullifiers can be performed only on the `ConfirmedNote` type). If you were calling this from a constrained function, consider using `compute_confirmed_note_hash_for_nullification` instead. Unconstrained usage is safe. + +### [Aztec.nr] Changes to standard note hash computation + +Note hashes used to be computed with the storage slot being the last value of the preimage, it is now the first. This is to make it easier to ensure all note hashes have proper domain separation. + +This change requires no input from your side unless you were testing or relying on hardcoded note hashes. + +## 4.1.3 + +### [Aztec.js] `TxReceipt` now includes `epochNumber` + +`TxReceipt` now includes an `epochNumber` field that indicates which epoch the transaction was included in. + +### [Aztec.js] `computeL2ToL1MembershipWitness` signature changed + +The function signature has changed to resolve the epoch internally from a transaction hash, rather than requiring the caller to pass the epoch number. + +**Migration:** + +```diff +- const witness = await computeL2ToL1MembershipWitness(aztecNode, epochNumber, messageHash); +- // epoch was passed in by the caller ++ const witness = await computeL2ToL1MembershipWitness(aztecNode, messageHash, txHash); ++ // epoch is now available on the returned witness ++ const epoch = witness.epochNumber; +``` + +The return type `L2ToL1MembershipWitness` now includes `epochNumber`. An optional `messageIndexInTx` parameter can be passed as the fourth argument to disambiguate when a transaction emits multiple identical L2-to-L1 messages. + +**Impact**: All call sites that compute L2-to-L1 membership witnesses must update to the new argument order and extract `epochNumber` from the result instead of passing it in. + +### [Aztec.js] `getPublicEvents` now returns an object instead of an array + +`getPublicEvents` now returns a `GetPublicEventsResult` object with `events` and `maxLogsHit` fields instead of a plain array. This enables pagination through large result sets using the new `afterLog` filter option. + +```diff +- const events = await getPublicEvents(node, MyContract.events.MyEvent, filter); ++ const { events } = await getPublicEvents(node, MyContract.events.MyEvent, filter); +``` + +The `maxLogsHit` flag indicates whether the log limit was reached, meaning more results may be available. You can use `afterLog` in the filter to fetch the next page. + +### [Aztec.nr] Removed `get_random_bytes` + +The `get_random_bytes` unconstrained function has been removed from `aztec::utils::random`. If you were using it, you can replace it with direct calls to the `random` oracle from `aztec::oracle::random` and convert to bytes yourself. +>>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)):docs/developer_versioned_docs/version-v4.2.0/docs/resources/migration_notes.md ## 4.1.0-rc.2 diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index e5b668106696..2ead2ddd7f04 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -29,6 +29,7 @@ If you were using these oracle functions directly (e.g. in `schnorr_account_cont Note the field renames: `index` is now `leaf_index`, and `path` is now `sibling_path` (matching the protocol circuit's `MembershipWitness` type). This has been done because this is the format expected by the functionality in protocol circuits and given that this is sensitive security-wise it made sense to reuse that functionality in Aztec.nr. +<<<<<<< HEAD ### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` `GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. @@ -36,10 +37,54 @@ This has been done because this is the format expected by the functionality in p The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. +======= + +### [L1 Contracts] Empire slasher removed, slasher config simplified + +The empire slashing model has been removed. Only the tally-based slashing model remains, and it has been renamed from `TallySlashingProposer` to `SlashingProposer`. + +**L1 contract changes:** +- `SlasherFlavor` enum removed from `ISlasher.sol` +- `RollupConfigInput.slasherFlavor` (enum) replaced with `slasherEnabled` (bool) +- `TallySlashingProposer` contract renamed to `SlashingProposer` +- `TallySlasherDeploymentExtLib` library renamed to `SlasherDeploymentExtLib` +- `SlashFactory` periphery contract removed +- `SLASHING_PROPOSER_TYPE` constant removed from `SlashingProposer` +- All `TallySlashingProposer__` error prefixes renamed to `SlashingProposer__` + +**Environment variable changes:** +```diff +- AZTEC_SLASHER_FLAVOR=tally # was: "tally" | "empire" | "none" ++ AZTEC_SLASHER_ENABLED=true # now a boolean +``` + +**Removed environment variables:** `SLASH_MIN_PENALTY_PERCENTAGE`, `SLASH_MAX_PENALTY_PERCENTAGE` + +**Removed from deploy outputs:** `slashFactoryAddress` + +**Node admin API:** `getSlashPayloads()` method removed. + +**TypeScript config changes:** +```diff +- slasherFlavor: 'tally' | 'none' ++ slasherEnabled: boolean +``` + +`slashMinPenaltyPercentage` and `slashMaxPenaltyPercentage` removed from `SlasherConfig`. + +## Unreleased (v5) + +### [aztec.js] `DeployMethod.send()` always returns `{ contract, receipt, instance }` + +The `returnReceipt` option in deploy wait options has been removed. `DeployMethod.send()` now always returns an object with `contract`, `receipt`, and `instance` at the top level, provided the user waits for the transaction to be included. + +The `DeployTxReceipt` and `DeployWaitOptions` types have been removed. +>>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) **Migration:** ```diff +<<<<<<< HEAD - import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; - const settings = GasSettings.default({ maxFeesPerGas }); + const settings = GasSettings.fallback({ maxFeesPerGas }); @@ -90,6 +135,20 @@ The zero address (`AztecAddress::zero()`) is always allowed regardless of the sc **Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. +======= +- const { +- receipt: { contract, instance }, +- } = await MyContract.deploy(wallet, ...args).send({ +- from: address, +- wait: { returnReceipt: true }, +- }); + ++ const { contract, instance } = await MyContract.deploy(wallet, ...args).send({ ++ from: address, ++ }); +``` + +>>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) ### `aztec new` and `aztec init` now create a 2-crate workspace `aztec new` and `aztec init` now create a workspace with two crates instead of a single contract crate: @@ -159,6 +218,127 @@ The `--name` flag has been removed from both `aztec new` and `aztec init`. For ` **Impact**: If you were using `--name` to set a contract name different from the directory name, rename your directory or use `aztec new` with the desired contract name directly. +<<<<<<< HEAD +======= +## 4.2.0 + +### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` + +`GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. + +The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. + +A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. + +**Migration:** + +```diff +- import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; +- const settings = GasSettings.default({ maxFeesPerGas }); ++ const settings = GasSettings.fallback({ maxFeesPerGas }); +``` + +**Impact**: Any code referencing `GasSettings.default()`, `DEFAULT_GAS_LIMIT`, or `DEFAULT_TEARDOWN_GAS_LIMIT` will fail to compile. + +### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'` + +The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`, +`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed +`'ALL_SCOPES'` must now specify which addresses will be in scope for the call. + +**Migration:** + +```diff ++ const accounts = await pxe.getRegisteredAccounts(); ++ const scopes = accounts.map(a => a.address); + + // simulateTx +- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' }); ++ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes }); + + // executeUtility +- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' }); ++ await pxe.executeUtility(call, { scopes }); + + // profileTx +- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' }); ++ await pxe.profileTx(txRequest, { profileMode: 'full', scopes }); + + // proveTx +- await pxe.proveTx(txRequest, 'ALL_SCOPES'); ++ await pxe.proveTx(txRequest, scopes); +``` + +**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses. + +### [PXE] Capsule operations are now scope-enforced at the PXE level + +The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error: + +``` +Scope 0x1234... is not in the allowed scopes list: [0xabcd...]. +``` + +The zero address (`AztecAddress::zero()`) is always allowed regardless of the scopes list, preserving backwards compatibility for contracts using the global scope. + +**Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. + +### [aztec.js] `EmbeddedWalletOptions` now uses a unified `pxe` field + +The `pxeConfig` and `pxeOptions` fields on `EmbeddedWalletOptions` have been deprecated in favor of a single `pxe` field that accepts both PXE configuration and dependency overrides (custom prover, store, simulator): + +```diff +const wallet = await EmbeddedWallet.create(nodeUrl, { +- pxeConfig: { proverEnabled: true }, +- pxeOptions: { proverOrOptions: myCustomProver }, ++ pxe: { ++ proverEnabled: true, ++ proverOrOptions: myCustomProver, ++ }, +}); +``` + +The old fields still work but will be removed in a future release. + +### [Aztec.nr] Ephemeral arrays replace capsule arrays in PXE oracle interfaces + +Oracle interfaces between Aztec.nr and PXE now use a new `EphemeralArray` type (`aztec::ephemeral::EphemeralArray`) instead of `CapsuleArray`. Ephemeral arrays live in memory and are scoped by contract call frame, so they no longer need to be addressed by `(contract_address, scope)`. Several public message-discovery and validation functions lost their `recipient`, `scope`, and `contract_address` parameters as a result. + +Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle these APIs automatically. Only contracts that call these functions directly need to update. + +**Migration:** + +```diff + attempt_note_discovery( + contract_address, + tx_hash, + unique_note_hashes_in_tx, + first_nullifier_in_tx, +- recipient, + compute_note_hash, + compute_note_nullifier, + owner, + storage_slot, + randomness, + note_type_id, + packed_note, + ); + +- enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash, scope); ++ enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash); + +- enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash, scope); ++ enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash); + +- validate_and_store_enqueued_notes_and_events(contract_address, scope); ++ validate_and_store_enqueued_notes_and_events(scope); +``` + +The `sync_inbox` function and the `OffchainInboxSync` type now return `EphemeralArray` instead of `CapsuleArray`. Custom message handlers that bind the returned array to an explicit type must update the type annotation. + +**Impact**: Contracts that call the above functions directly (rather than relying on macro-generated code) will fail to compile until the trailing `recipient`, `scope`, and `contract_address` parameters are removed. + +>>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) ## 4.2.0-aztecnr-rc.2 ### Custom token FPCs removed from default public setup allowlist From fa1627d288a304ba9861f2254ac7cfa4e4dafb00 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 16 Apr 2026 18:58:38 +0000 Subject: [PATCH 2/2] fix: resolve cherry-pick conflicts in migration_notes.md Keep HEAD content for both migration notes files: - version-v4.1.0-rc.2 snapshot is a locked published doc, do not modify - v4.2.0 versioned snapshot does not exist on v4-next yet Add only the missing EphemeralArray migration note to the ## TBD section of the live developer migration notes. The other three notes the PR moves (GasSettings.default, simulateTx scopes, capsule scope enforcement) are already present in ## TBD on v4-next (see commit 42ecd02a34). --- .../docs/resources/migration_notes.md | 445 ------------------ .../docs/resources/migration_notes.md | 212 ++------- 2 files changed, 35 insertions(+), 622 deletions(-) diff --git a/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md b/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md index 3a01604a1163..0e7ff3460506 100644 --- a/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md +++ b/docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md @@ -7,452 +7,7 @@ tags: [migration, updating, sandbox, local network] Aztec is in active development. Each version may introduce breaking changes that affect compatibility with previous versions. This page documents common errors and difficulties you might encounter when upgrading, along with guidance on how to resolve them. -<<<<<<< HEAD:docs/developer_versioned_docs/version-v4.1.0-rc.2/docs/resources/migration_notes.md ## TBD -======= -## 4.2.0 - -### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` - -`GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. - -The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. - -A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. - -**Migration:** - -```diff -- import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; -- const settings = GasSettings.default({ maxFeesPerGas }); -+ const settings = GasSettings.fallback({ maxFeesPerGas }); -``` - -**Impact**: Any code referencing `GasSettings.default()`, `DEFAULT_GAS_LIMIT`, or `DEFAULT_TEARDOWN_GAS_LIMIT` will fail to compile. - -### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'` - -The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`, -`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed -`'ALL_SCOPES'` must now specify which addresses will be in scope for the call. - -**Migration:** - -```diff -+ const accounts = await pxe.getRegisteredAccounts(); -+ const scopes = accounts.map(a => a.address); - - // simulateTx -- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' }); -+ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes }); - - // executeUtility -- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' }); -+ await pxe.executeUtility(call, { scopes }); - - // profileTx -- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' }); -+ await pxe.profileTx(txRequest, { profileMode: 'full', scopes }); - - // proveTx -- await pxe.proveTx(txRequest, 'ALL_SCOPES'); -+ await pxe.proveTx(txRequest, scopes); -``` - -**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses. - -### [PXE] Capsule operations are now scope-enforced at the PXE level - -The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error: - -``` -Scope 0x1234... is not in the allowed scopes list: [0xabcd...]. -``` - -The zero address (`AztecAddress::zero()`) is always allowed regardless of the scopes list, preserving backwards compatibility for contracts using the global scope. - -**Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. - -### [aztec.js] `EmbeddedWalletOptions` now uses a unified `pxe` field - -The `pxeConfig` and `pxeOptions` fields on `EmbeddedWalletOptions` have been deprecated in favor of a single `pxe` field that accepts both PXE configuration and dependency overrides (custom prover, store, simulator): - -```diff -const wallet = await EmbeddedWallet.create(nodeUrl, { -- pxeConfig: { proverEnabled: true }, -- pxeOptions: { proverOrOptions: myCustomProver }, -+ pxe: { -+ proverEnabled: true, -+ proverOrOptions: myCustomProver, -+ }, -}); -``` - -The old fields still work but will be removed in a future release. - -### [Aztec.nr] Ephemeral arrays replace capsule arrays in PXE oracle interfaces - -Oracle interfaces between Aztec.nr and PXE now use a new `EphemeralArray` type (`aztec::ephemeral::EphemeralArray`) instead of `CapsuleArray`. Ephemeral arrays live in memory and are scoped by contract call frame, so they no longer need to be addressed by `(contract_address, scope)`. Several public message-discovery and validation functions lost their `recipient`, `scope`, and `contract_address` parameters as a result. - -Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle these APIs automatically. Only contracts that call these functions directly need to update. - -**Migration:** - -```diff - attempt_note_discovery( - contract_address, - tx_hash, - unique_note_hashes_in_tx, - first_nullifier_in_tx, -- recipient, - compute_note_hash, - compute_note_nullifier, - owner, - storage_slot, - randomness, - note_type_id, - packed_note, - ); - -- enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash, scope); -+ enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash); - -- enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash, scope); -+ enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash); - -- validate_and_store_enqueued_notes_and_events(contract_address, scope); -+ validate_and_store_enqueued_notes_and_events(scope); -``` - -The `sync_inbox` function and the `OffchainInboxSync` type now return `EphemeralArray` instead of `CapsuleArray`. Custom message handlers that bind the returned array to an explicit type must update the type annotation. - -**Impact**: Contracts that call the above functions directly (rather than relying on macro-generated code) will fail to compile until the trailing `recipient`, `scope`, and `contract_address` parameters are removed. - -## 4.2.0-aztecnr-rc.2 - -### [Aztec.js] Removed `SingleKeyAccountContract` - -The `SchnorrSingleKeyAccount` contract and its TypeScript wrapper `SingleKeyAccountContract` have been removed. This contract was insecure: it used `ivpk_m` (incoming viewing public key) as its Schnorr signing key, meaning anyone who received a user's viewing key could sign transactions on their behalf. - -**Migration:** - -```diff -- import { SingleKeyAccountContract } from '@aztec/accounts/single_key'; -- const contract = new SingleKeyAccountContract(signingKey); -+ import { SchnorrAccountContract } from '@aztec/accounts/schnorr'; -+ const contract = new SchnorrAccountContract(signingKey); -``` - -**Impact**: If you were using `@aztec/accounts/single_key`, switch to `@aztec/accounts/schnorr` which uses separate keys for encryption and authentication. - -### Custom token FPCs removed from default public setup allowlist - -Token contract functions (like `transfer_in_public` and `_increase_public_balance`) have been removed from the default public setup allowlist. FPCs that accept custom tokens (like the reference `FPC` contract) will not work on public networks, because their setup-phase calls to these functions will be rejected. Token class IDs change with each aztec-nr release, making it impractical to maintain them in the allowlist. - -FPCs that use only Fee Juice still work on all networks, since FeeJuice is a protocol contract with a fixed address in the allowlist. Custom FPCs should only call protocol contract functions (AuthRegistry, FeeJuice) during setup. - -`PublicFeePaymentMethod` and `PrivateFeePaymentMethod` in aztec.js are affected, since they use the reference `FPC` contract which calls Token functions during setup. Switch to `FeeJuicePaymentMethodWithClaim` (after [bridging Fee Juice from L1](../aztec-js/how_to_pay_fees.md#bridge-fee-juice-from-l1)) or write an FPC that uses Fee Juice natively. - -**Migration:** - -```diff -- import { PublicFeePaymentMethod } from '@aztec/aztec.js/fee'; -- const paymentMethod = new PublicFeePaymentMethod(fpcAddress, senderAddress, wallet, gasSettings); -+ import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee'; -+ const paymentMethod = new FeeJuicePaymentMethodWithClaim(senderAddress, claim); -``` - -Similarly, the `fpc-public` and `fpc-private` CLI wallet payment methods use the reference Token-based FPC and will not work on public networks. Use `fee_juice` for direct Fee Juice payment, or `fpc-sponsored` on devnet and local network. - -### [Aztec.nr] Domain-separated tags on log emission - -All logs emitted through the Aztec.nr framework now include a domain-separated tag at `fields[0]`. Each log category uses its own domain separator via `compute_log_tag(raw_tag, dom_sep)`: - -- **Events** (`DOM_SEP__EVENT_LOG_TAG`): the event type ID is the raw tag. -- **Message delivery** (`DOM_SEP__UNCONSTRAINED_MSG_LOG_TAG`): the discovery tag is the raw tag. -- **Partial note completion logs** (`DOM_SEP__NOTE_COMPLETION_LOG_TAG`): the partial note's `commitment` field is the raw tag. - -The low-level emit methods now take `tag` as an explicit first parameter and have been renamed with an `_unsafe` suffix. Previously the tag was included as `log[0]` — it has now been extracted into its own parameter, and `log` no longer contains it: - -```diff -- context.emit_private_log(log, length); -+ context.emit_private_log_unsafe(tag, log, length); -- context.emit_raw_note_log(log, length, note_hash_counter); -+ context.emit_raw_note_log_unsafe(tag, log, length, note_hash_counter); -- context.emit_public_log(log); -+ context.emit_public_log_unsafe(tag, log); -``` - -Prefer the higher-level APIs (`emit` for events, `MessageDelivery` for messages) which handle tagging automatically. - -### [Aztec.nr] Public events no longer include the event type selector at the end of the payload - -`emit_event_in_public` previously appended the event type selector as the last field. It now prepends a domain-separated tag at `fields[0]` instead. The payload after the tag contains only the serialized event fields. - -If you were reading public event directly from node logs (i.e. via `node.getPublicLogs` and not via `wallet.getPublicEvents`), update your parsing: - -```diff -- // Old: fields = [serialized_event..., event_type_selector] -- const selector = EventSelector.fromField(fields[fields.length - 1]); -- const event = decodeFromAbi([abiType], fields); -+ // New: fields = [domain_separated_tag, serialized_event...] -+ const eventFields = log.getEmittedFieldsWithoutTag(); -+ const event = decodeFromAbi([abiType], eventFields); -``` - -### [Aztec.nr] Capsule operations are now addressed by scope - -All capsule operations (`store`, `load`, `delete`, `copy`) and `CapsuleArray` now require a `scope: AztecAddress` parameter. This scopes capsule storage by address, providing isolation between different accounts within the same PXE. - -Contracts that use `CapsuleArray` directly also need to update. - -**Migration:** - -```diff -- let array: CapsuleArray = CapsuleArray::at(contract_address, slot); -+ let array: CapsuleArray = CapsuleArray::at(contract_address, slot, scope); -``` - -The low-level capsule functions are similarly affected: - -```diff -- capsules::store(contract_address, slot, value); -+ capsules::store(contract_address, slot, value, scope); - -- capsules::load(contract_address, slot); -+ capsules::load(contract_address, slot, scope); - -- capsules::delete(contract_address, slot); -+ capsules::delete(contract_address, slot, scope); - -- capsules::copy(contract_address, src_slot, dst_slot, num_entries); -+ capsules::copy(contract_address, src_slot, dst_slot, num_entries, scope); -``` - -If you need to stick the old, scope-less behavior, and you are really sure that that's what you need to use, you can use `scope = AztecAddress::zero()`. - -### [Aztec.nr] `process_message` utility function removed - -The auto-generated `process_message` utility function has been removed. If you need to deliver offchain messages (messages not broadcast via onchain logs), use the `offchain_receive` utility function instead. This function is automatically injected by the `#[aztec]` macro and accepts messages into a persistent inbox scoped by recipient. These messages are then picked up and processed during `sync_state`. - -**Impact**: Contracts that explicitly called `process_message` must switch to delivering messages via `offchain_receive` and letting `sync_state` handle processing. - -### [Aztec.nr] `CustomMessageHandler` type signature changed - -The `CustomMessageHandler` function type now receives an additional `scope: AztecAddress` parameter: - -```diff - type CustomMessageHandler = unconstrained fn( - AztecAddress, // contract_address - u64, // msg_type_id - u64, // msg_metadata - BoundedVec, // msg_content - MessageContext, // message_context -+ AztecAddress, // scope - ); -``` - -**Impact**: Contracts that implement a custom message handler must update the function signature. - -### [aztec.js] `isContractInitialized` is now `initializationStatus` tri-state enum - -`ContractMetadata.isContractInitialized` has been renamed to `ContractMetadata.initializationStatus` and changed from `boolean | undefined` to a `ContractInitializationStatus` enum with values `INITIALIZED`, `UNINITIALIZED`, and `UNKNOWN`. - -- `INITIALIZED`: the contract has been initialized (initialization nullifier found) -- `UNINITIALIZED`: the contract instance is registered but has not been initialized -- `UNKNOWN`: the instance is not registered and no public initialization nullifier was found - -When the instance is not registered, the wallet now attempts to check the public initialization nullifier (computed from address alone) before returning `UNKNOWN`. Previously this case returned `undefined`. - -**Migration:** - -```diff -+ import { ContractInitializationStatus } from '@aztec/aztec.js/wallet'; - - const metadata = await wallet.getContractMetadata(address); -- if (metadata.isContractInitialized) { -+ if (metadata.initializationStatus === ContractInitializationStatus.INITIALIZED) { - // contract is initialized - } -``` - -### [Aztec.js] Use `NO_FROM` instead of `AztecAddress.ZERO` to bypass account contract entrypoint - -When sending transactions that should not be mediated by an account contract (e.g., account contract self-deployments), use the explicit `NO_FROM` sentinel instead of `AztecAddress.ZERO`. - -`NO_FROM` signals that the transaction should be executed directly via the `DefaultEntrypoint`. This replaces the brittle convention of passing `AztecAddress.ZERO` as the `from` field. - -**Migration:** - -```diff -- import { AztecAddress } from '@aztec/aztec.js'; -+ import { NO_FROM } from '@aztec/aztec.js/account'; - - await contract.methods.my_method().send({ -- from: AztecAddress.ZERO, -+ from: NO_FROM, - }); -``` - -Note that `DefaultEntrypoint` only accepts a single call. If you need to execute multiple calls without account contract mediation (e.g., deploying an account contract and paying a fee in the same transaction), wrap them through `DefaultMultiCallEntrypoint` on the app side before sending: - -```typescript -import { NO_FROM } from "@aztec/aztec.js/account"; -import { DefaultMultiCallEntrypoint } from "@aztec/entrypoints/multicall"; -import { mergeExecutionPayloads } from "@aztec/stdlib/tx"; - -// Merge multiple execution payloads into one -const merged = mergeExecutionPayloads([deployPayload, feePayload]); - -// Wrap through multicall so it becomes a single call for DefaultEntrypoint -const multicall = new DefaultMultiCallEntrypoint(); -const chainInfo = await wallet.getChainInfo(); -const wrappedPayload = await multicall.wrapExecutionPayload(merged, chainInfo); - -// Send without account contract mediation -await wallet.sendTx(wrappedPayload, { from: NO_FROM }); -``` - -Using other contracts for wrapping (for example, supporting more calls) is also supported, as long as the contract is registered in the wallet. This opens the door to different flows that do not use account entrypoints as the first call in the chain, including app sponsored FPCs. - -**Impact**: Any code that passes `AztecAddress.ZERO` as the `from` option in `.send()`, `.simulate()`, or deploy options must switch to `NO_FROM`. Wallets use `DefaultEntrypoint` directly for `NO_FROM` transactions, instead of the `DefaultMultiCallEntrypoint` that was used internally before when specifying `AztecAddress.ZERO`. - -### [Aztec.js] `ExecuteUtilityOptions.scope` renamed to `scopes` and type changed to `AztecAddress[]` - -The `scope` field in `ExecuteUtilityOptions` has been renamed to `scopes` and changed from a single `AztecAddress` to `AztecAddress[]`. This aligns the wallet's `executeUtility` API with the PXE API and `sendTx` in `Wallet`, which both accept an array of scopes. - -**Migration:** - -```diff - wallet.executeUtility(call, { -- scope: myAddress, -+ scopes: [myAddress], - }); -``` - -**Impact**: Any code that calls `wallet.executeUtility` directly must update the options object. Wallets must update to adapt to the new interface - -### [Aztec.nr] `attempt_note_discovery` now takes two separate functions instead of one - -The `attempt_note_discovery` function (and related discovery functions like `do_sync_state`, `process_message_ciphertext`) now takes separate `compute_note_hash` and `compute_note_nullifier` arguments instead of a single combined `compute_note_hash_and_nullifier`. The corresponding type aliases are now `ComputeNoteHash` and `ComputeNoteNullifier` (instead of `ComputeNoteHashAndNullifier`). - -This split improves performance during nonce discovery: the note hash only needs to be computed once, while the old combined function recomputed it for every candidate nonce. - -Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle this automatically. Only contracts that call `attempt_note_discovery` directly need to update. - -**Migration:** - -```diff - attempt_note_discovery( - contract_address, - tx_hash, - unique_note_hashes_in_tx, - first_nullifier_in_tx, - recipient, -- _compute_note_hash_and_nullifier, -+ _compute_note_hash, -+ _compute_note_nullifier, - owner, - storage_slot, - randomness, - note_type_id, - packed_note, - ); -``` - -**Impact**: Contracts that call `attempt_note_discovery` or related discovery functions directly with a custom `_compute_note_hash_and_nullifier` argument. The old combined function is still generated (deprecated) but is no longer used by the framework. Additionally, if you had a custom `_compute_note_hash_and_nullifier` function then compilation will now fail as you'll need to also produce the corresponding `_compute_note_hash` and `_compute_note_nullifier` functions. - -### Private initialization nullifier now includes `init_hash` - -The private initialization nullifier is no longer derived from just the contract address. It is now computed as a Poseidon2 hash of `[address, init_hash]` using a dedicated domain separator. This prevents observers from determining whether a fully private contract has been initialized by simply knowing its address. - -Note that `Wallet.getContractMetadata` now returns `initializationStatus: ContractInitializationStatus.UNKNOWN` when the wallet does not have the contract instance registered, since `init_hash` is needed to compute the nullifier and initialization status cannot be determined. Previously, this check worked for any address. Callers should check the enum value before branching on the initialization state. - -If you use `assert_contract_was_initialized_by` or `assert_contract_was_not_initialized_by` from `aztec::history::deployment`, these now require an additional `init_hash: Field` parameter: - -```diff -+ let instance = get_contract_instance(contract_address); - assert_contract_was_initialized_by( - block_header, - contract_address, -+ instance.initialization_hash, - ); -``` - -### Two separate init nullifiers for private and public - -Contract initialization now emits two separate nullifiers instead of one: a **private init nullifier** and a **public init nullifier**. Each nullifier gates its respective execution domain: - -- Private external functions check the private init nullifier. -- Public external functions check the public init nullifier. - -**How initializers work:** - -- **Private initializers** emit the private init nullifier. If the contract has any external public functions, the protocol auto-enqueues a public call to emit the public init nullifier. -- **Public initializers** emit both nullifiers directly. -- Contracts with no public functions only emit the private init nullifier. - -**`only_self` functions no longer have init checks.** They behave as if marked `noinitcheck`. - -**External functions called during private initialization must be `#[only_self]`.** Init nullifiers are emitted at the end of the initializer, so any external functions called on the initializing contract (e.g. via `enqueue_self` or `call_self`) during initialization will fail the init check unless they skip it. - -**Breaking change for deployment:** If your contract has external public functions and a private initializer, the class must be registered onchain before initialization. You can no longer pass `skipClassPublication: true`, because the auto-enqueued public call requires the class to be available. - -```diff - const deployed = await MyContract.deploy(wallet, ...args).send({ -- skipClassPublication: true, - }).deployed(); -``` - -### [Aztec.nr] Made `compute_note_hash_for_nullification` unconstrained - -This function shouldn't have been constrained in the first place, as constrained computation of `HintedNote` nullifiers is dangerous (constrained computation of nullifiers can be performed only on the `ConfirmedNote` type). If you were calling this from a constrained function, consider using `compute_confirmed_note_hash_for_nullification` instead. Unconstrained usage is safe. - -### [Aztec.nr] Changes to standard note hash computation - -Note hashes used to be computed with the storage slot being the last value of the preimage, it is now the first. This is to make it easier to ensure all note hashes have proper domain separation. - -This change requires no input from your side unless you were testing or relying on hardcoded note hashes. - -## 4.1.3 - -### [Aztec.js] `TxReceipt` now includes `epochNumber` - -`TxReceipt` now includes an `epochNumber` field that indicates which epoch the transaction was included in. - -### [Aztec.js] `computeL2ToL1MembershipWitness` signature changed - -The function signature has changed to resolve the epoch internally from a transaction hash, rather than requiring the caller to pass the epoch number. - -**Migration:** - -```diff -- const witness = await computeL2ToL1MembershipWitness(aztecNode, epochNumber, messageHash); -- // epoch was passed in by the caller -+ const witness = await computeL2ToL1MembershipWitness(aztecNode, messageHash, txHash); -+ // epoch is now available on the returned witness -+ const epoch = witness.epochNumber; -``` - -The return type `L2ToL1MembershipWitness` now includes `epochNumber`. An optional `messageIndexInTx` parameter can be passed as the fourth argument to disambiguate when a transaction emits multiple identical L2-to-L1 messages. - -**Impact**: All call sites that compute L2-to-L1 membership witnesses must update to the new argument order and extract `epochNumber` from the result instead of passing it in. - -### [Aztec.js] `getPublicEvents` now returns an object instead of an array - -`getPublicEvents` now returns a `GetPublicEventsResult` object with `events` and `maxLogsHit` fields instead of a plain array. This enables pagination through large result sets using the new `afterLog` filter option. - -```diff -- const events = await getPublicEvents(node, MyContract.events.MyEvent, filter); -+ const { events } = await getPublicEvents(node, MyContract.events.MyEvent, filter); -``` - -The `maxLogsHit` flag indicates whether the log limit was reached, meaning more results may be available. You can use `afterLog` in the filter to fetch the next page. - -### [Aztec.nr] Removed `get_random_bytes` - -The `get_random_bytes` unconstrained function has been removed from `aztec::utils::random`. If you were using it, you can replace it with direct calls to the `random` oracle from `aztec::oracle::random` and convert to bytes yourself. ->>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)):docs/developer_versioned_docs/version-v4.2.0/docs/resources/migration_notes.md ## 4.1.0-rc.2 diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index 2ead2ddd7f04..de8844723961 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -29,7 +29,6 @@ If you were using these oracle functions directly (e.g. in `schnorr_account_cont Note the field renames: `index` is now `leaf_index`, and `path` is now `sibling_path` (matching the protocol circuit's `MembershipWitness` type). This has been done because this is the format expected by the functionality in protocol circuits and given that this is sensitive security-wise it made sense to reuse that functionality in Aztec.nr. -<<<<<<< HEAD ### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` `GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. @@ -37,54 +36,10 @@ This has been done because this is the format expected by the functionality in p The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. -======= - -### [L1 Contracts] Empire slasher removed, slasher config simplified - -The empire slashing model has been removed. Only the tally-based slashing model remains, and it has been renamed from `TallySlashingProposer` to `SlashingProposer`. - -**L1 contract changes:** -- `SlasherFlavor` enum removed from `ISlasher.sol` -- `RollupConfigInput.slasherFlavor` (enum) replaced with `slasherEnabled` (bool) -- `TallySlashingProposer` contract renamed to `SlashingProposer` -- `TallySlasherDeploymentExtLib` library renamed to `SlasherDeploymentExtLib` -- `SlashFactory` periphery contract removed -- `SLASHING_PROPOSER_TYPE` constant removed from `SlashingProposer` -- All `TallySlashingProposer__` error prefixes renamed to `SlashingProposer__` - -**Environment variable changes:** -```diff -- AZTEC_SLASHER_FLAVOR=tally # was: "tally" | "empire" | "none" -+ AZTEC_SLASHER_ENABLED=true # now a boolean -``` - -**Removed environment variables:** `SLASH_MIN_PENALTY_PERCENTAGE`, `SLASH_MAX_PENALTY_PERCENTAGE` - -**Removed from deploy outputs:** `slashFactoryAddress` - -**Node admin API:** `getSlashPayloads()` method removed. - -**TypeScript config changes:** -```diff -- slasherFlavor: 'tally' | 'none' -+ slasherEnabled: boolean -``` - -`slashMinPenaltyPercentage` and `slashMaxPenaltyPercentage` removed from `SlasherConfig`. - -## Unreleased (v5) - -### [aztec.js] `DeployMethod.send()` always returns `{ contract, receipt, instance }` - -The `returnReceipt` option in deploy wait options has been removed. `DeployMethod.send()` now always returns an object with `contract`, `receipt`, and `instance` at the top level, provided the user waits for the transaction to be included. - -The `DeployTxReceipt` and `DeployWaitOptions` types have been removed. ->>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) **Migration:** ```diff -<<<<<<< HEAD - import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; - const settings = GasSettings.default({ maxFeesPerGas }); + const settings = GasSettings.fallback({ maxFeesPerGas }); @@ -135,20 +90,44 @@ The zero address (`AztecAddress::zero()`) is always allowed regardless of the sc **Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. -======= -- const { -- receipt: { contract, instance }, -- } = await MyContract.deploy(wallet, ...args).send({ -- from: address, -- wait: { returnReceipt: true }, -- }); +### [Aztec.nr] Ephemeral arrays replace capsule arrays in PXE oracle interfaces -+ const { contract, instance } = await MyContract.deploy(wallet, ...args).send({ -+ from: address, -+ }); +Oracle interfaces between Aztec.nr and PXE now use a new `EphemeralArray` type (`aztec::ephemeral::EphemeralArray`) instead of `CapsuleArray`. Ephemeral arrays live in memory and are scoped by contract call frame, so they no longer need to be addressed by `(contract_address, scope)`. Several public message-discovery and validation functions lost their `recipient`, `scope`, and `contract_address` parameters as a result. + +Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle these APIs automatically. Only contracts that call these functions directly need to update. + +**Migration:** + +```diff + attempt_note_discovery( + contract_address, + tx_hash, + unique_note_hashes_in_tx, + first_nullifier_in_tx, +- recipient, + compute_note_hash, + compute_note_nullifier, + owner, + storage_slot, + randomness, + note_type_id, + packed_note, + ); + +- enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash, scope); ++ enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash); + +- enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash, scope); ++ enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash); + +- validate_and_store_enqueued_notes_and_events(contract_address, scope); ++ validate_and_store_enqueued_notes_and_events(scope); ``` ->>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) +The `sync_inbox` function and the `OffchainInboxSync` type now return `EphemeralArray` instead of `CapsuleArray`. Custom message handlers that bind the returned array to an explicit type must update the type annotation. + +**Impact**: Contracts that call the above functions directly (rather than relying on macro-generated code) will fail to compile until the trailing `recipient`, `scope`, and `contract_address` parameters are removed. + ### `aztec new` and `aztec init` now create a 2-crate workspace `aztec new` and `aztec init` now create a workspace with two crates instead of a single contract crate: @@ -218,127 +197,6 @@ The `--name` flag has been removed from both `aztec new` and `aztec init`. For ` **Impact**: If you were using `--name` to set a contract name different from the directory name, rename your directory or use `aztec new` with the desired contract name directly. -<<<<<<< HEAD -======= -## 4.2.0 - -### [Aztec.js] `GasSettings.default()` renamed to `GasSettings.fallback()` - -`GasSettings.default()` has been renamed to `GasSettings.fallback()` to clarify that these gas limits are not protocol defaults — the protocol has no concept of "default" gas settings. `fallback()` is a convenience for cases where gas estimation is not being used, but callers should prefer estimating gas via simulation for accurate limits. - -The old `DEFAULT_GAS_LIMIT` and `DEFAULT_TEARDOWN_GAS_LIMIT` constants have been removed. Gas limits are now derived from protocol-level maximums (`MAX_PROCESSABLE_L2_GAS`, `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`) rather than arbitrary fixed values. - -A new `GasSettings.forEstimation()` method provides intentionally high gas limits for use during simulation. These limits exceed protocol maximums so the simulation doesn't hit gas caps — you must pass `skipTxValidation: true` when simulating with them, then use the results to set accurate gas limits on the actual transaction. `EmbeddedWallet` does this by default. - -**Migration:** - -```diff -- import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT } from '@aztec/constants'; -- const settings = GasSettings.default({ maxFeesPerGas }); -+ const settings = GasSettings.fallback({ maxFeesPerGas }); -``` - -**Impact**: Any code referencing `GasSettings.default()`, `DEFAULT_GAS_LIMIT`, or `DEFAULT_TEARDOWN_GAS_LIMIT` will fail to compile. - -### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'` - -The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`, -`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed -`'ALL_SCOPES'` must now specify which addresses will be in scope for the call. - -**Migration:** - -```diff -+ const accounts = await pxe.getRegisteredAccounts(); -+ const scopes = accounts.map(a => a.address); - - // simulateTx -- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' }); -+ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes }); - - // executeUtility -- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' }); -+ await pxe.executeUtility(call, { scopes }); - - // profileTx -- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' }); -+ await pxe.profileTx(txRequest, { profileMode: 'full', scopes }); - - // proveTx -- await pxe.proveTx(txRequest, 'ALL_SCOPES'); -+ await pxe.proveTx(txRequest, scopes); -``` - -**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses. - -### [PXE] Capsule operations are now scope-enforced at the PXE level - -The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error: - -``` -Scope 0x1234... is not in the allowed scopes list: [0xabcd...]. -``` - -The zero address (`AztecAddress::zero()`) is always allowed regardless of the scopes list, preserving backwards compatibility for contracts using the global scope. - -**Impact**: Contracts that access capsules scoped to addresses not included in the transaction's authorized scopes will now fail at runtime. Ensure the correct scopes are passed when executing transactions. - -### [aztec.js] `EmbeddedWalletOptions` now uses a unified `pxe` field - -The `pxeConfig` and `pxeOptions` fields on `EmbeddedWalletOptions` have been deprecated in favor of a single `pxe` field that accepts both PXE configuration and dependency overrides (custom prover, store, simulator): - -```diff -const wallet = await EmbeddedWallet.create(nodeUrl, { -- pxeConfig: { proverEnabled: true }, -- pxeOptions: { proverOrOptions: myCustomProver }, -+ pxe: { -+ proverEnabled: true, -+ proverOrOptions: myCustomProver, -+ }, -}); -``` - -The old fields still work but will be removed in a future release. - -### [Aztec.nr] Ephemeral arrays replace capsule arrays in PXE oracle interfaces - -Oracle interfaces between Aztec.nr and PXE now use a new `EphemeralArray` type (`aztec::ephemeral::EphemeralArray`) instead of `CapsuleArray`. Ephemeral arrays live in memory and are scoped by contract call frame, so they no longer need to be addressed by `(contract_address, scope)`. Several public message-discovery and validation functions lost their `recipient`, `scope`, and `contract_address` parameters as a result. - -Most contracts are not affected, as the macro-generated `sync_state` and `process_message` functions handle these APIs automatically. Only contracts that call these functions directly need to update. - -**Migration:** - -```diff - attempt_note_discovery( - contract_address, - tx_hash, - unique_note_hashes_in_tx, - first_nullifier_in_tx, -- recipient, - compute_note_hash, - compute_note_nullifier, - owner, - storage_slot, - randomness, - note_type_id, - packed_note, - ); - -- enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash, scope); -+ enqueue_note_for_validation(contract_address, owner, storage_slot, randomness, note_nonce, packed_note, note_hash, nullifier, tx_hash); - -- enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash, scope); -+ enqueue_event_for_validation(contract_address, event_type_id, randomness, serialized_event, event_commitment, tx_hash); - -- validate_and_store_enqueued_notes_and_events(contract_address, scope); -+ validate_and_store_enqueued_notes_and_events(scope); -``` - -The `sync_inbox` function and the `OffchainInboxSync` type now return `EphemeralArray` instead of `CapsuleArray`. Custom message handlers that bind the returned array to an explicit type must update the type annotation. - -**Impact**: Contracts that call the above functions directly (rather than relying on macro-generated code) will fail to compile until the trailing `recipient`, `scope`, and `contract_address` parameters are removed. - ->>>>>>> dec97a2d55 (docs: backfill v4.2.0 migration notes (#22612)) ## 4.2.0-aztecnr-rc.2 ### Custom token FPCs removed from default public setup allowlist