Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2d4a609
refactor(aztec-nr): use constructor methods for MessageDelivery varia…
nchamo May 28, 2026
b9b2c57
docs: update testing_contracts.md for two-crate aztec new layout (#23…
benesjan May 28, 2026
05ad02c
fix: drop usage of include and indexof on types that support equals (…
nventuro May 28, 2026
7ede19d
fix: unused ts expressions in tests (#23621)
nventuro May 28, 2026
6542ea5
feat(aztec-nr): Get tagging index for constrained delivery (#23359)
vezenovm May 28, 2026
7332e70
feat!: demote auth registry to non-protocol contract (#23106)
dbanks12 May 28, 2026
a42bff4
feat(aztec-nr)!: embed BoundedVec max length in validation requests (…
nchamo May 28, 2026
a1c9ae7
fix: regenerate standard contract addresses after auth registry demot…
nchamo May 28, 2026
10bbb74
feat(aztec-nr): encrypt handshake log for indistinguishability (#23638)
nchamo May 28, 2026
0c79106
feat!: demote public_checks to non-protocol contract (#23217)
dbanks12 May 28, 2026
9247eab
fix: noir precommit re-staging inside worktrees (#23628)
nchamo May 28, 2026
fc72404
fix(txe): deploy standard AuthRegistry and PublicChecks in TXE sessions
dbanks12 May 28, 2026
3187f87
Merge branch 'next' into merge-train/fairies
May 28, 2026
fee1dfe
fix(txe): keep block baseline when deploying standard contracts at init
dbanks12 May 28, 2026
0f7d22a
fix(e2e): await async selector() in e2e_nested_utility_calls
dbanks12 May 29, 2026
fc8e4bd
fix(standard-contracts): regenerate AuthRegistry + PublicChecks addre…
dbanks12 May 29, 2026
d1ee5d5
Merge branch 'next' into merge-train/fairies
May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions barretenberg/cpp/pil/vm2/constants_gen.pil
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ namespace constants;
pol MAX_L2_TO_L1_MSGS_PER_TX = 8;
pol MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 3000;
pol MAX_PROTOCOL_CONTRACTS = 11;
pol CANONICAL_AUTH_REGISTRY_ADDRESS = 1;
pol CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS = 2;
pol CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS = 3;
pol MULTI_CALL_ENTRYPOINT_ADDRESS = 4;
pol FEE_JUICE_ADDRESS = 5;
pol PUBLIC_CHECKS_ADDRESS = 6;
pol FEE_JUICE_BALANCES_SLOT = 1;
pol UPDATED_CLASS_IDS_SLOT = 1;
pol FLAT_PUBLIC_LOGS_HEADER_LENGTH = 1;
Expand Down
2 changes: 0 additions & 2 deletions barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@
#define GENESIS_ARCHIVE_ROOT "0x177a4955b31ecaafad999753938a44e526b54c5ba5d536688227f85f15cfbdf5"
#define MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS 3000
#define MAX_PROTOCOL_CONTRACTS 11
#define CANONICAL_AUTH_REGISTRY_ADDRESS 1
#define CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS 2
#define CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS 3
#define MULTI_CALL_ENTRYPOINT_ADDRESS 4
#define FEE_JUICE_ADDRESS 5
#define PUBLIC_CHECKS_ADDRESS 6
#define FEE_JUICE_BALANCES_SLOT 1
#define UPDATED_CLASS_IDS_SLOT 1
#define FLAT_PUBLIC_LOGS_HEADER_LENGTH 1
Expand Down
4 changes: 2 additions & 2 deletions boxes/boxes/react/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ contract BoxReact {
let new_number = FieldNote { value: number };

self.storage.numbers.at(owner).initialize(new_number).deliver(
MessageDelivery.ONCHAIN_CONSTRAINED,
MessageDelivery::onchain_constrained(),
);
}

#[external("private")]
fn setNumber(number: Field, owner: AztecAddress) {
self.storage.numbers.at(owner).replace(|_old| FieldNote { value: number }).deliver(
MessageDelivery.ONCHAIN_CONSTRAINED,
MessageDelivery::onchain_constrained(),
);
}

Expand Down
4 changes: 2 additions & 2 deletions boxes/boxes/vite/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ contract BoxReact {
let new_number = FieldNote { value: number };

self.storage.numbers.at(owner).initialize(new_number).deliver(
MessageDelivery.ONCHAIN_CONSTRAINED,
MessageDelivery::onchain_constrained(),
);
}

#[external("private")]
fn setNumber(number: Field, owner: AztecAddress) {
self.storage.numbers.at(owner).replace(|_old| FieldNote { value: number }).deliver(
MessageDelivery.ONCHAIN_CONSTRAINED,
MessageDelivery::onchain_constrained(),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn transfer(to: AztecAddress, amount: u128) {

self.emit(Transfer { from, to, amount }).deliver_to(
to,
MessageDelivery.ONCHAIN_UNCONSTRAINED,
MessageDelivery::onchain_unconstrained(),
);
}
```
Expand All @@ -55,15 +55,15 @@ You can deliver the same event to multiple recipients with different delivery mo

```rust
let message = self.emit(Transfer { from, to, amount });
message.deliver_to(from, MessageDelivery.OFFCHAIN);
message.deliver_to(to, MessageDelivery.ONCHAIN_CONSTRAINED);
message.deliver_to(from, MessageDelivery::offchain());
message.deliver_to(to, MessageDelivery::onchain_constrained());
```

The `MessageDelivery` options are:

- **`ONCHAIN_CONSTRAINED`** - Constrained encryption with onchain delivery. Slowest proving but provides cryptographic guarantees that recipients can decrypt messages.
- **`ONCHAIN_UNCONSTRAINED`** - Unconstrained encryption with onchain delivery. Faster proving, but trusts the sender to encrypt correctly.
- **`OFFCHAIN`** - Unconstrained encryption with offchain delivery. Lowest cost, but requires custom infrastructure to deliver messages to recipients.
- **`onchain_constrained()`** - Constrained encryption with onchain delivery. Slowest proving but provides cryptographic guarantees that recipients can decrypt messages.
- **`onchain_unconstrained()`** - Unconstrained encryption with onchain delivery. Faster proving, but trusts the sender to encrypt correctly.
- **`offchain()`** - Unconstrained encryption with offchain delivery. Lowest cost, but requires custom infrastructure to deliver messages to recipients.

:::note
Emitting private events is optional. Onchain delivery publishes encrypted data to Ethereum blobs, inheriting Ethereum's data availability guarantees. You can choose to share information offchain instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub contract PrivateToken {
fn mint(amount: u128, recipient: AztecAddress) {
// Adding to the balance returns a MaybeNoteMessage
self.storage.balances.at(recipient).add(amount)
.deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver(MessageDelivery::onchain_constrained());
}
}
```
Expand All @@ -37,7 +37,7 @@ pub contract PrivateToken {

Aztec provides three delivery modes that offer different tradeoffs between cost, proving time, and guarantees:

### `MessageDelivery.OFFCHAIN`
### `MessageDelivery::offchain()`

**Fully offchain delivery with no guarantees.**

Expand Down Expand Up @@ -76,7 +76,7 @@ This is expected to be the most common delivery method when you don't need const
```rust
// Change note - sender is motivated to deliver to themselves
self.storage.balances.at(sender).add(change_amount)
.deliver(MessageDelivery.OFFCHAIN);
.deliver(MessageDelivery::offchain());
```

:::info TODO
Expand Down Expand Up @@ -119,7 +119,7 @@ await contract.methods.process_message(ciphertext, messageContext.toNoirStruct()

See the [aztec.js documentation](../../aztec-js/index.md) for more details on accessing transaction effects.

### `MessageDelivery.ONCHAIN_UNCONSTRAINED`
### `MessageDelivery::onchain_unconstrained()`

**Onchain delivery with no content guarantees.**

Expand All @@ -133,10 +133,10 @@ This mode provides the same low proving time as `OFFCHAIN` while avoiding the ne
```rust
// Minting to an admin who controls the contract
self.storage.balances.at(admin).add(amount)
.deliver(MessageDelivery.ONCHAIN_UNCONSTRAINED);
.deliver(MessageDelivery::onchain_unconstrained());
```

### `MessageDelivery.ONCHAIN_CONSTRAINED`
### `MessageDelivery::onchain_constrained()`

**Onchain delivery with guaranteed correct content.**

Expand All @@ -150,7 +150,7 @@ self.storage.balances.at(admin).add(amount)
```rust
// Minting to an arbitrary recipient - must guarantee delivery
self.storage.balances.at(recipient).add(amount)
.deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver(MessageDelivery::onchain_constrained());
```

## Choosing a Delivery Mode
Expand Down Expand Up @@ -199,7 +199,7 @@ You can deliver a note to an address other than the note's owner using `.deliver
```rust
// Create a note owned by `owner` but deliver it to `auditor`
self.storage.balances.at(owner).add(amount)
.deliver_to(auditor, MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver_to(auditor, MessageDelivery::onchain_constrained());
```

**Important:** The recipient (e.g. an `auditor`) can see the note was created but **cannot use it** - only the owner can spend the note (this is authorized by the contract logic). The recipient also cannot see when/if the note is nullified.
Expand All @@ -219,12 +219,12 @@ fn transfer(amount: u128, sender: AztecAddress, recipient: AztecAddress) {
// Subtract from sender - unconstrained since sender is the caller
self.storage.balances.at(sender)
.sub(amount)
.deliver(MessageDelivery.ONCHAIN_UNCONSTRAINED);
.deliver(MessageDelivery::onchain_unconstrained());

// Add to recipient - constrained delivery for untrusted sender
self.storage.balances.at(recipient)
.add(amount)
.deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver(MessageDelivery::onchain_constrained());
}
```

Expand All @@ -238,6 +238,6 @@ fn constructor(admin: AztecAddress) {
// Use unconstrained delivery since we don't know if deployer is incentivized
self.storage.admin
.initialize(AddressNote { address: admin }, admin)
.deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver(MessageDelivery::onchain_constrained());
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ When working with private state variables, many operations return a `NoteMessage
#### Delivery Methods

Private notes need to be communicated to their recipients so they know the note exists and can use it. The [`NoteMessage`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/note/struct.NoteMessage) wrapper forces you to make an explicit choice about how this happens:
- [`MessageDelivery.ONCHAIN_CONSTRAINED`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDeliveryEnum#structfield.ONCHAIN_CONSTRAINED): Verified in the circuit (most secure, but highest cost) - Use when the sender cannot be trusted to deliver correctly (e.g., protocol fees, multisig config updates). **Warning:** Currently [not fully constrained](https://github.com/AztecProtocol/aztec-packages/issues/14565) - the log's tag is unconstrained.
- [`MessageDelivery.ONCHAIN_UNCONSTRAINED`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDeliveryEnum#structfield.ONCHAIN_UNCONSTRAINED): Message stored onchain but no guarantees on content - Use when the sender is incentivized to deliver correctly but may not have an offchain channel to the recipient.
- [`MessageDelivery.OFFCHAIN`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDeliveryEnum#structfield.OFFCHAIN): Lowest cost, no onchain data - Use when the sender and recipient can communicate and the sender is incentivized to deliver correctly.
- [`MessageDelivery::onchain_constrained()`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDelivery#method.onchain_constrained): Verified in the circuit (most secure, but highest cost) - Use when the sender cannot be trusted to deliver correctly (e.g., protocol fees, multisig config updates). **Warning:** Currently [not fully constrained](https://github.com/AztecProtocol/aztec-packages/issues/14565) - the log's tag is unconstrained.
- [`MessageDelivery::onchain_unconstrained()`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDelivery#method.onchain_unconstrained): Message stored onchain but no guarantees on content - Use when the sender is incentivized to deliver correctly but may not have an offchain channel to the recipient.
- [`MessageDelivery::offchain()`](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/messages/message_delivery/struct.MessageDelivery#method.offchain): Lowest cost, no onchain data - Use when the sender and recipient can communicate and the sender is incentivized to deliver correctly.

#include_code note_delivery /noir-projects/noir-contracts/contracts/app/private_token_contract/src/main.nr rust

Expand Down Expand Up @@ -324,7 +324,7 @@ fn perform_admin_action() {
// value of the counter and can update it again in the future.
self.storage.admin_call_count
.replace(|current| UintNote{ value: current.value + 1 }) // wouldn't it be great if we didn't have to deal with this wrapping and unwrapping?
.deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
.deliver(MessageDelivery::onchain_constrained());

// ...
}
Expand Down Expand Up @@ -381,7 +381,7 @@ This function allows us to get the note of a `PrivateMutable`, essentially readi
#[external("private")]
fn read_settings() {
let owner = self.msg_sender();
self.storage.user_settings.at(owner).get_note().deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
self.storage.user_settings.at(owner).get_note().deliver(MessageDelivery::onchain_constrained());
}
```

Expand Down Expand Up @@ -484,11 +484,11 @@ When initializing, you still pass an owner address, but this specifies who can d

```rust
// owner_address determines who can see the note, not where it's stored
self.storage.admin.initialize(note, owner_address).deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
self.storage.admin.initialize(note, owner_address).deliver(MessageDelivery::onchain_constrained());
```

:::warning
`SinglePrivateMutable` uses a nullify-and-recreate pattern when reading. Unless the caller is incentivized to deliver the note message correctly, you should use `MessageDelivery.ONCHAIN_CONSTRAINED` to prevent malicious actors from bricking the contract by failing to deliver the note.
`SinglePrivateMutable` uses a nullify-and-recreate pattern when reading. Unless the caller is incentivized to deliver the note message correctly, you should use `MessageDelivery::onchain_constrained()` to prevent malicious actors from bricking the contract by failing to deliver the note.
:::

## Containers
Expand Down Expand Up @@ -558,7 +558,7 @@ fn transfer(from: AztecAddress, to: AztecAddress, amount: u128) {

// Access the balance for the 'to' address
let new_note = UintNote { value: amount };
self.storage.balances.at(to).insert(new_note).deliver(MessageDelivery.ONCHAIN_UNCONSTRAINED);
self.storage.balances.at(to).insert(new_note).deliver(MessageDelivery::onchain_unconstrained());
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/docs-developers/docs/aztec-nr/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ A good example of this is writing to private state variables. These functions re

```rust
storage.votes.insert(new_vote); // compiler error - unused NoteMessage return value
storage.votes.insert(new_vote).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); // deliver the note message onchain
storage.votes.insert(new_vote).deliver(MessageDelivery::onchain_constrained()); // deliver the note message onchain
```

## Contract Development
Expand Down
2 changes: 1 addition & 1 deletion docs/docs-developers/docs/aztec-nr/standards/escrow.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn _share_escrow(
) {
let event_struct = EscrowDetailsLogContent { escrow, master_secret_keys };
emit_event_in_private(context, event_struct).deliver_to(
account, MessageDelivery.ONCHAIN_CONSTRAINED,
account, MessageDelivery::onchain_constrained(),
);
}
```
Expand Down
76 changes: 33 additions & 43 deletions docs/docs-developers/docs/aztec-nr/testing_contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,69 +46,59 @@ Always use `aztec test` instead of `nargo test`. The `TestEnvironment` requires

## Basic test structure

Tests live in the same crate as your contract. `aztec new` creates a single-crate project, and the convention is to place `#[test]` functions in a `mod tests` block alongside the contract (or in submodules of the crate):
`aztec new my_project` scaffolds a workspace with two crates: a `contract` crate that holds the contract code, and a separate `test` crate that holds your `#[test]` functions:

```text
my_project/
├── Nargo.toml # [workspace] members = ["my_project_contract", "my_project_test"]
├── my_project_contract/
│ ├── Nargo.toml # type = "contract"
│ └── src/main.nr
└── my_project_test/
├── Nargo.toml # type = "lib", depends on my_project_contract
└── src/lib.nr # #[test] functions go here
```

```rust
use aztec::macros::aztec;
The motivation for the split of contract and tests into its own crates is **faster iteration**: editing a test does not invalidate the contract's compiled artifact, so `aztec test` skips contract recompilation when only test code changed.

#[aztec]
pub contract MyContract {
// ...contract functions...
}
`aztec compile` warns if it finds `#[test]` functions inside a contract crate.

mod tests {
use super::MyContract;
use aztec::test::helpers::test_environment::TestEnvironment;
The generated test crate template imports the contract by package name and then initializes it:

#[test]
unconstrained fn test_basic_flow() {
// 1. Create test environment
let mut env = TestEnvironment::new();
```rust
// my_project_test/src/lib.nr
use aztec::test::helpers::test_environment::TestEnvironment;
use my_project_contract::Main;

// 2. Create accounts
let _owner = env.create_light_account();
}
#[test]
unconstrained fn test_constructor() {
let mut env = TestEnvironment::new();
let deployer = env.create_light_account();

let _contract_address = env.deploy("@my_project_contract/Main")
.with_private_initializer(deployer, Main::interface().constructor());
}
```

Because tests live in their own crate, we refer to the contract via its crate name using the `@crate_name/ContractName` syntax.

:::info Test execution notes

- Tests run in parallel by default
- Use `unconstrained` functions for faster execution
- See all `TestEnvironment` methods [here](pathname:///aztec-nr-api/#api_ref_version/noir_aztec/test/helpers/test_environment/struct.TestEnvironment)

- It is always necessary to deploy a contract in order to test it
:::

:::tip Organizing test files
For larger test suites, split tests into submodules of your crate rather than keeping them all inside `main.nr`:

- Create modules like `src/transfer_tests.nr`, `src/auth_tests.nr`
- Declare them from `src/main.nr` with `mod transfer_tests;`, `mod auth_tests;`
- Share setup functions in `src/test_utils.nr`

See the [aztec-standards token contract](https://github.com/defi-wonderland/aztec-standards/tree/dev/src/token_contract) for a worked example of this layout.
:::

## Deploying contracts

In order to test you'll most likely want to deploy a contract in your testing environment. First, instantiate a deployer:
If you'll add arguments to your contract's constructor you pass them directly to the constructor function in the test:

```rust
let deployer = env.deploy("ContractName");

// If on a different crate:
let deployer = env.deploy("../other_contract");
let initializer = MyContract::interface().constructor(param1, param2);
```

:::warning
It is always necessary to deploy a contract in order to test it. `aztec test` automatically compiles contracts when changes are detected, but you can also manually compile with `aztec compile` to regenerate the bytecode and ABI.
:::

You can then choose whatever you need to initialize by interfacing with your initializer and calling it:
Since Aztec contracts can be initialized both in private and public or they can be interacted with without any kind of initialization (see [Contract creation](../foundational-topics/contract_creation.md) for how Aztec's deployment model differs from Ethereum's) there are 3 options on the deployer:

```rust
let initializer = MyContract::interface().constructor(param1, param2);

let contract_address = deployer.with_private_initializer(owner, initializer);
let contract_address = deployer.with_public_initializer(owner, initializer);
let contract_address = deployer.without_initializer();
Expand All @@ -122,7 +112,7 @@ pub unconstrained fn setup(initial_value: Field) -> (TestEnvironment, AztecAddre
let mut env = TestEnvironment::new();
let owner = env.create_light_account();
let initializer = MyContract::interface().constructor(initial_value, owner);
let contract_address = env.deploy("MyContract").with_private_initializer(owner, initializer);
let contract_address = env.deploy("@my_project_contract/MyContract").with_private_initializer(owner, initializer);
(env, contract_address, owner)
}

Expand Down
4 changes: 2 additions & 2 deletions docs/docs-developers/docs/foundational-topics/call_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ An example of how a deadline can be checked using the `PublicChecks` contract fo

This is what the implementation of the check timestamp functionality looks like:

#include_code check_timestamp /noir-projects/noir-contracts/contracts/protocol/public_checks_contract/src/main.nr rust
#include_code check_timestamp /noir-projects/noir-contracts/contracts/standard/public_checks_contract/src/main.nr rust

:::note
The `PublicChecks` contract is not part of the [aztec-nr repository](https://github.com/AztecProtocol/aztec-nr).
To add it as a dependency, point to the aztec-packages repository:

```toml
[dependencies]
public_checks = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "#include_aztec_version", directory = "noir-projects/noir-contracts/contracts/protocol/public_checks_contract" }
public_checks = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "#include_aztec_version", directory = "noir-projects/noir-contracts/contracts/standard/public_checks_contract" }
```

:::
Expand Down
Loading
Loading