diff --git a/aztec-up/test/counter_contract.sh b/aztec-up/test/counter_contract.sh index 28f337ec3256..c4ce76350d56 100755 --- a/aztec-up/test/counter_contract.sh +++ b/aztec-up/test/counter_contract.sh @@ -5,27 +5,37 @@ export LOG_LEVEL=silent # Execute commands as per: https://docs.aztec.network/tutorials/codealong/contract_tutorials/counter_contract aztec new counter_contract -if [ ! -f counter_contract/Nargo.toml ] || [ ! -f counter_contract/src/main.nr ]; then - echo "Failed to create contract." + +# Verify workspace structure +if [ ! -f counter_contract/Nargo.toml ]; then + echo "Failed to create workspace Nargo.toml." + exit 1 +fi +if [ ! -f counter_contract/contract/Nargo.toml ] || [ ! -f counter_contract/contract/src/main.nr ]; then + echo "Failed to create contract crate." + exit 1 +fi +if [ ! -f counter_contract/test/Nargo.toml ] || [ ! -f counter_contract/test/src/lib.nr ]; then + echo "Failed to create test crate." exit 1 fi -# Check counter_contract dir is owned by aztec-dev. +# Check counter_contract dir is owned by ubuntu. if [ "$(stat -c %U counter_contract)" != "ubuntu" ]; then echo "counter_contract dir is not owned by ubuntu." exit 1 fi -# "Write" our contract. -cp -Rf ./aztec-packages/noir-projects/noir-contracts/contracts/test/counter_contract . +# "Write" our contract over the scaffold. +cp -Rf ./aztec-packages/noir-projects/noir-contracts/contracts/test/counter_contract/* counter_contract/ cd counter_contract -sed -i 's|\.\./\.\./\.\./\.\./|/home/ubuntu/aztec-packages/noir-projects/|g' Nargo.toml +sed -i 's|\.\./\.\./\.\./\.\./\.\./|/home/ubuntu/aztec-packages/noir-projects/|g' contract/Nargo.toml test/Nargo.toml # Compile the contract. aztec compile # Codegen -aztec codegen -o src/artifacts target -if [ ! -d src/artifacts ]; then +aztec codegen -o contract/src/artifacts target +if [ ! -d contract/src/artifacts ]; then echo "Failed to codegen TypeScript." exit 1 fi diff --git a/boxes/init/.gitignore b/boxes/init/.gitignore new file mode 100644 index 000000000000..292dee672e8b --- /dev/null +++ b/boxes/init/.gitignore @@ -0,0 +1,2 @@ +target/ +codegenCache.json diff --git a/boxes/init/Nargo.toml b/boxes/init/Nargo.toml index 14bcaec85ac4..3ae352f74220 100644 --- a/boxes/init/Nargo.toml +++ b/boxes/init/Nargo.toml @@ -1,6 +1,2 @@ -[package] -name = "init" -type = "contract" - -[dependencies] -aztec = { path = "../../noir-projects/aztec-nr/aztec" } +[workspace] +members = ["contract", "test"] diff --git a/boxes/init/README.md b/boxes/init/README.md new file mode 100644 index 000000000000..5f0fe47a795f --- /dev/null +++ b/boxes/init/README.md @@ -0,0 +1,27 @@ +# init + +An Aztec Noir contract project. + +## Compile + +```bash +aztec compile +``` + +This compiles the contract in `contract/` and outputs artifacts to `target/`. + +## Test + +```bash +aztec test +``` + +This runs the tests in `test/`. + +## Generate TypeScript bindings + +```bash +aztec codegen target -o src/artifacts +``` + +This generates TypeScript contract artifacts from the compiled output in `target/` into `src/artifacts/`. diff --git a/boxes/init/contract/Nargo.toml b/boxes/init/contract/Nargo.toml new file mode 100644 index 000000000000..48e749065754 --- /dev/null +++ b/boxes/init/contract/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "init" +type = "contract" + +[dependencies] +aztec = { path = "../../../noir-projects/aztec-nr/aztec" } diff --git a/boxes/init/contract/src/main.nr b/boxes/init/contract/src/main.nr new file mode 100644 index 000000000000..fedcf9a88eea --- /dev/null +++ b/boxes/init/contract/src/main.nr @@ -0,0 +1,10 @@ +use aztec::macros::aztec; + +#[aztec] +pub contract Main { + use aztec::macros::functions::{external, initializer}; + + #[initializer] + #[external("private")] + fn constructor() {} +} diff --git a/boxes/init/src/main.nr b/boxes/init/src/main.nr deleted file mode 100644 index 302aec7a8469..000000000000 --- a/boxes/init/src/main.nr +++ /dev/null @@ -1,9 +0,0 @@ - -use aztec::macros::aztec; - -#[aztec] -contract Main { - #[external("private")] - #[initializer] - fn constructor() { } -} diff --git a/boxes/init/test/Nargo.toml b/boxes/init/test/Nargo.toml new file mode 100644 index 000000000000..38d2b87c645f --- /dev/null +++ b/boxes/init/test/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "init_test" +type = "lib" + +[dependencies] +aztec = { path = "../../../noir-projects/aztec-nr/aztec" } +init = { path = "../contract" } diff --git a/boxes/init/test/src/lib.nr b/boxes/init/test/src/lib.nr new file mode 100644 index 000000000000..7b5a395d4fd4 --- /dev/null +++ b/boxes/init/test/src/lib.nr @@ -0,0 +1,17 @@ +use aztec::test::helpers::test_environment::TestEnvironment; +use init::Main; + +#[test] +unconstrained fn test_constructor() { + let mut env = TestEnvironment::new(); + let deployer = env.create_light_account(); + + // Deploy the contract with the default constructor: + let contract_address = env.deploy("@init/Main").with_private_initializer( + deployer, + Main::interface().constructor(), + ); + + // Deploy without an initializer: + let contract_address = env.deploy("@init/Main").without_initializer(); +} diff --git a/docs/docs-developers/docs/aztec-nr/framework-description/contract_structure.md b/docs/docs-developers/docs/aztec-nr/framework-description/contract_structure.md index f72f320384ed..61f30c88b3b6 100644 --- a/docs/docs-developers/docs/aztec-nr/framework-description/contract_structure.md +++ b/docs/docs-developers/docs/aztec-nr/framework-description/contract_structure.md @@ -10,15 +10,23 @@ High-level structure of how Aztec smart contracts including the different compon ## Directory structure -Here's a common layout for a basic Aztec.nr Contract project: +When you create a new project with `aztec new`, it generates a workspace with two crates: a `contract` crate for your smart contract and a `test` crate for Noir tests. ```text title="layout of an aztec contract project" ─── my_aztec_contract_project - ├── src - │ └── main.nr <-- your contract - └── Nargo.toml <-- package and dependency management + ├── Nargo.toml <-- workspace root + ├── contract + │ ├── src + │ │ └── main.nr <-- your contract + │ └── Nargo.toml <-- contract package and dependencies + └── test + ├── src + │ └── lib.nr <-- your tests + └── Nargo.toml <-- test package and dependencies ``` +The workspace root `Nargo.toml` declares both crates as workspace members. The contract code lives in `contract/src/main.nr`, and tests live in a separate `test` crate that depends on the contract crate. + See the vanilla Noir docs for [more info on packages](https://noir-lang.org/docs/noir/modules_packages_crates/crates_and_packages). ## Contract block diff --git a/docs/docs-developers/docs/aztec-nr/index.md b/docs/docs-developers/docs/aztec-nr/index.md index 593e2630f136..34fe5705cc8f 100644 --- a/docs/docs-developers/docs/aztec-nr/index.md +++ b/docs/docs-developers/docs/aztec-nr/index.md @@ -42,16 +42,15 @@ storage.votes.insert(new_vote).deliver(vote_counter); // the vote counter accoun ### Flow -1. Write your contract and specify your contract dependencies. Every contract written for Aztec will have - aztec-nr as a dependency. Add it to your `Nargo.toml` with +1. Write your contract and specify your contract dependencies. Create a new project with `aztec new my_project`, which sets up a workspace with a `contract` crate and a `test` crate, with the `aztec` dependency already configured. If you need additional dependencies, add them to `contract/Nargo.toml`: ```toml -# Nargo.toml +# contract/Nargo.toml [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-nr/", tag="#include_aztec_version", directory="aztec" } ``` -Update your `main.nr` contract file to use the Aztec.nr macros for writing contracts. +Update your `contract/src/main.nr` contract file to use the Aztec.nr macros for writing contracts. #include_code setup /docs/examples/contracts/counter_contract/src/main.nr rust diff --git a/docs/docs-developers/docs/aztec-nr/testing_contracts.md b/docs/docs-developers/docs/aztec-nr/testing_contracts.md index f53315dcf7c4..a0836ef628fa 100644 --- a/docs/docs-developers/docs/aztec-nr/testing_contracts.md +++ b/docs/docs-developers/docs/aztec-nr/testing_contracts.md @@ -46,8 +46,10 @@ Always use `aztec test` instead of `nargo test`. The `TestEnvironment` requires ## Basic test structure +When you create a project with `aztec new` or `aztec init`, a separate `test` crate is created alongside the `contract` crate. Tests live in `test/src/lib.nr` and import the contract crate by name (not `crate::`): + ```rust -use crate::MyContract; +use my_contract::MyContract; use aztec::{ protocol::address::AztecAddress, test::helpers::test_environment::TestEnvironment, @@ -72,12 +74,11 @@ unconstrained fn test_basic_flow() { ::: :::tip Organizing test files -You can organize tests in separate files: +Tests live in the separate `test` crate that `aztec new` creates. You can organize them into modules: -- Create `src/test.nr` with `mod utils;` to import helper functions -- Split tests into modules like `src/test/transfer_tests.nr`, `src/test/auth_tests.nr` -- Import the test module in `src/main.nr` with `mod test;` -- Share setup functions in `src/test/utils.nr` +- Split tests into modules like `test/src/transfer_tests.nr`, `test/src/auth_tests.nr` +- Import them in `test/src/lib.nr` with `mod transfer_tests;`, `mod auth_tests;` +- Share setup functions in `test/src/utils.nr` ::: ## Deploying contracts diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index 12a9b995b30e..196e8dffbc29 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -9,6 +9,32 @@ Aztec is in active development. Each version may introduce breaking changes that ## TBD +### `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: + +- A `contract` crate (type = "contract") for your smart contract code +- A `test` crate (type = "lib") for Noir tests, which depends on the contract crate + +The new project structure looks like: + +``` +my_project/ +├── Nargo.toml # [workspace] members = ["contract", "test"] +├── contract/ +│ ├── src/main.nr +│ └── Nargo.toml # type = "contract" +└── test/ + ├── src/lib.nr + └── Nargo.toml # type = "lib" +``` + +**What changed:** +- The `--contract` and `--lib` flags have been removed from `aztec new` and `aztec init`. These commands now always create a contract workspace. +- Contract code is now at `contract/src/main.nr` instead of `src/main.nr`. +- The `Nargo.toml` in the project root is now a workspace file. Contract dependencies go in `contract/Nargo.toml`. +- Tests should be written in the separate `test` crate (`test/src/lib.nr`) and import the contract by package name (e.g., `use my_contract::MyContract;`) instead of using `crate::`. + ### Scope enforcement for private state access (TXE and PXE) Scope enforcement is now active across both TXE (test environment) and PXE (client). Previously, private execution could implicitly access any account's keys and notes. Now, only the caller (`from`) address is in scope by default, and accessing another address's private state requires explicitly granting scope. diff --git a/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md b/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md index 0f8a7f672b99..817aa4f78273 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md @@ -22,7 +22,7 @@ This tutorial is compatible with the Aztec version `#include_aztec_version`. Ins Run this to create a new contract project: ```bash -aztec new --contract counter +aztec new counter ``` Your structure should look like this: @@ -30,14 +30,20 @@ Your structure should look like this: ```tree . |-counter -| |-src -| | |-main.nr -| |-Nargo.toml +| |-Nargo.toml <-- workspace root +| |-contract +| | |-src +| | | |-main.nr +| | |-Nargo.toml <-- contract package config +| |-test +| | |-src +| | | |-lib.nr +| | |-Nargo.toml <-- test package config ``` -The file `main.nr` will soon turn into our smart contract! +The `aztec new` command creates a workspace with two crates: a `contract` crate for your smart contract code and a `test` crate for Noir tests. The file `contract/src/main.nr` will soon turn into our smart contract! -Add the following dependencies to `Nargo.toml` under the autogenerated content: +Add the following dependency to `contract/Nargo.toml` under the existing `aztec` dependency: ```toml [dependencies] @@ -47,7 +53,7 @@ balance_set = { git="https://github.com/AztecProtocol/aztec-nr/", tag="#include_ ## Define the functions -Go to `main.nr`, and replace the boilerplate code with this contract initialization: +Go to `contract/src/main.nr`, and replace the boilerplate code with this contract initialization: ```rust #include_code setup /docs/examples/contracts/counter_contract/src/main.nr raw diff --git a/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md b/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md index 68b831dbecae..79eacfbfa4a9 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md @@ -210,24 +210,30 @@ The contract demonstrates several important patterns: ### Create the Contract Project -Use `aztec init` to generate the contract project structure: +Use `aztec new` to generate the contract project structure: ```bash -aztec init --contract contract +aztec new contract --name ValueNotEqual ``` -This creates: +This creates a workspace with two crates: ```tree contract/ -├── src/ -│ └── main.nr # Contract code -└── Nargo.toml # Contract configuration +├── Nargo.toml # Workspace root +├── contract/ +│ ├── src/ +│ │ └── main.nr # Contract code +│ └── Nargo.toml # Contract configuration +└── test/ + ├── src/ + │ └── lib.nr # Test code + └── Nargo.toml # Test configuration ``` ### Contract Configuration -Update `contract/Nargo.toml` with the required dependencies: +Update `contract/contract/Nargo.toml` with the required dependencies: ```toml [package] @@ -240,7 +246,7 @@ aztec = { git = "https://github.com/AztecProtocol/aztec-nr/", tag = "#include_az bb_proof_verification = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "#include_aztec_version", directory = "barretenberg/noir/bb_proof_verification" } ``` -**Key differences from the circuit's Nargo.toml**: +**Key differences from the circuit's Nargo.toml** (in `contract/contract/Nargo.toml`): - `type = "contract"` (not `"bin"`) - Depends on `aztec` for Aztec-specific features @@ -248,7 +254,7 @@ bb_proof_verification = { git = "https://github.com/AztecProtocol/aztec-packages ### Contract Structure -Replace the contents of `contract/src/main.nr` with: +Replace the contents of `contract/contract/src/main.nr` with: #include_code full_contract /docs/examples/contracts/recursive_verification_contract/src/main.nr rust @@ -380,7 +386,7 @@ Create the following files in your project root directory. "name": "recursive-verification-tutorial", "type": "module", "scripts": { - "ccc": "cd contract && aztec compile && aztec codegen target -o artifacts", + "ccc": "cd contract && aztec compile && aztec codegen target -o contract/artifacts", "data": "tsx scripts/generate_data.ts", "recursion": "tsx scripts/run_recursion.ts" }, @@ -451,7 +457,7 @@ yarn ccc This generates: - `contract/target/ValueNotEqual.json` - Contract artifact (bytecode, ABI, etc.) -- `contract/artifacts/ValueNotEqual.ts` - TypeScript class for deploying and interacting with the contract +- `contract/contract/artifacts/ValueNotEqual.ts` - TypeScript class for deploying and interacting with the contract ### Proof Generation Script @@ -584,7 +590,7 @@ import { SponsoredFeePaymentMethod } from "@aztec/aztec.js/fee"; import type { FieldLike } from "@aztec/aztec.js/abi"; import { getSponsoredFPCInstance } from "./sponsored_fpc.ts"; import { SponsoredFPCContract } from "@aztec/noir-contracts.js/SponsoredFPC"; -import { ValueNotEqualContract } from "../contract/artifacts/ValueNotEqual"; +import { ValueNotEqualContract } from "../contract/contract/artifacts/ValueNotEqual"; import data from "../data.json"; import { EmbeddedWallet } from "@aztec/wallets/embedded"; import { AztecAddress } from "@aztec/aztec.js/addresses"; diff --git a/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md b/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md index 6381094315ec..98e5fdc0fb60 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md @@ -50,7 +50,7 @@ aztec init ## Contract structure -We have a messy, but working structure. In `src/main.nr` we even have a proto-contract. Let's replace it with a simple starting point: +The `aztec init` command created a workspace with two crates: a `contract` crate for your smart contract code and a `test` crate for Noir tests. In `contract/src/main.nr` we even have a proto-contract. Let's replace it with a simple starting point: ```rust #include_code start /docs/examples/contracts/bob_token_contract/src/main.nr raw @@ -60,7 +60,7 @@ We have a messy, but working structure. In `src/main.nr` we even have a proto-co The `#[aztec]` macro transforms our contract code to work with Aztec's privacy protocol. -Let's import the Aztec.nr library by adding it to our dependencies in `Nargo.toml`: +Let's make sure the Aztec.nr library is listed in our dependencies in `contract/Nargo.toml`: ```toml [package] @@ -254,7 +254,7 @@ In this case, all that the network sees (including Giggle) is just "something ha ### Updating Storage for Privacy -For something like balances, you can use a simple library called `easy_private_state` which abstracts away a custom private Note. A Note is at the core of how private state works in Aztec and you can read about it [here](../../foundational-topics/state_management.md). For now, let's just import the library in `Nargo.toml`: +For something like balances, you can use a simple library called `easy_private_state` which abstracts away a custom private Note. A Note is at the core of how private state works in Aztec and you can read about it [here](../../foundational-topics/state_management.md). For now, let's just import the library in `contract/Nargo.toml`: ```toml [dependencies] diff --git a/docs/docs-developers/docs/tutorials/js_tutorials/token_bridge.md b/docs/docs-developers/docs/tutorials/js_tutorials/token_bridge.md index 38a88723df02..f80d3c6897a5 100644 --- a/docs/docs-developers/docs/tutorials/js_tutorials/token_bridge.md +++ b/docs/docs-developers/docs/tutorials/js_tutorials/token_bridge.md @@ -86,25 +86,20 @@ aztec new contracts/aztec/nft cd contracts/aztec/nft ``` +This creates a workspace with two crates: a `contract` crate for the smart contract code and a `test` crate for Noir tests. The `aztec` dependency is already configured in `contract/Nargo.toml`. + :::tip Noir Language Server If you're using VS Code, install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) for syntax highlighting, error checking, and code completion while writing Noir contracts. ::: -Open `Nargo.toml` and make sure `aztec` is a dependency: - -```toml -[dependencies] -aztec = { git = "https://github.com/AztecProtocol/aztec-nr", tag = "#include_aztec_version", directory = "aztec" } -``` - ### Create the NFT Note -First, let's create a custom note type for private NFT ownership. In the `src/` directory, create a new file called `nft.nr`: +First, let's create a custom note type for private NFT ownership. In the `contract/src/` directory, create a new file called `nft.nr`: ```bash -touch src/nft.nr +touch contract/src/nft.nr ``` In this file, you're going to create a **private note** that represents NFT ownership. This is a struct with macros that indicate it is a note that can be compared and packed: @@ -121,7 +116,7 @@ Notes are powerful concepts. Learn more about how to use them in the [state mana ### Define Storage -Back in `main.nr`, you can now build the contract storage. You need: +Back in `contract/src/main.nr`, you can now build the contract storage. You need: - **admin**: Who controls the contract (set once, never changes) - **minter**: The bridge address (set once by admin) @@ -130,7 +125,7 @@ Back in `main.nr`, you can now build the contract storage. You need: One interesting aspect of this storage configuration is the use of `DelayedPublicMutable`, which allows private functions to read and use public state. You're using it to publicly track which NFTs are already minted while keeping their owners private. Read more about `DelayedPublicMutable` in [the storage guide](../../aztec-nr/framework-description/state_variables.md). -Write the storage struct and a simple [initializer](../../foundational-topics/contract_creation.md#initialization) to set the admin in the `main.nr` file: +Write the storage struct and a simple [initializer](../../foundational-topics/contract_creation.md#initialization) to set the admin in the `contract/src/main.nr` file: @@ -218,12 +213,12 @@ aztec new nft_bridge cd nft_bridge ``` -And again, add the `aztec-nr` dependency to `Nargo.toml`. We also need to add the `NFTPunk` contract we just wrote above: +Now add the `NFTPunk` contract dependency to `contract/Nargo.toml`. The `aztec` dependency is already there: ```toml [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-nr", tag = "#include_aztec_version", directory = "aztec" } -NFTPunk = { path = "../nft" } +NFTPunk = { path = "../../nft/contract" } ``` ### Understanding Bridges @@ -237,7 +232,7 @@ This means having knowledge about the L2 NFT contract, and the bridge on the L1 ### Bridge Storage -Clean up `main.nr` which is just a placeholder, and let's write the storage struct and the constructor. We'll use `PublicImmutable` since these values never change: +Clean up `contract/src/main.nr` which is just a placeholder, and let's write the storage struct and the constructor. We'll use `PublicImmutable` since these values never change: diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 6077b7dec019..9d35116f5a36 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -41,7 +41,7 @@ members = [ "contracts/test/avm_test_contract", "contracts/test/benchmarking_contract", "contracts/test/child_contract", - "contracts/test/counter_contract", + "contracts/test/counter_contract/contract", "contracts/test/event_only_contract", "contracts/test/import_test_contract", "contracts/test/invalid_account_contract", diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index e38c87d5ac44..74fd5ce1cc91 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -168,7 +168,7 @@ function compile { local contract_name contract_hash local contract_path=$(get_contract_path "$1" "$2") - local contract=${contract_path##*/} + local contract=$(grep -oP '(?<=^name = ")[^"]+' "$2/$contract_path/Nargo.toml") # Calculate filename because nargo... contract_name=$(cat $2/$contract_path/src/main.nr | awk '/^contract / { print $2 } /^pub contract / { print $3 }') local filename="$contract-$contract_name.json" diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/test/counter_contract/Nargo.toml index 09b54cf10ec5..3ae352f74220 100644 --- a/noir-projects/noir-contracts/contracts/test/counter_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/test/counter_contract/Nargo.toml @@ -1,9 +1,2 @@ -[package] -name = "counter_contract" -authors = [""] -compiler_version = ">=0.25.0" -type = "contract" - -[dependencies] -aztec = { path = "../../../../aztec-nr/aztec" } -balance_set = { path = "../../../../aztec-nr/balance-set" } +[workspace] +members = ["contract", "test"] diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/contract/Nargo.toml b/noir-projects/noir-contracts/contracts/test/counter_contract/contract/Nargo.toml new file mode 100644 index 000000000000..9b2c58e42173 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/counter_contract/contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "counter_contract" +authors = [""] +compiler_version = ">=0.25.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../../../aztec-nr/aztec" } +balance_set = { path = "../../../../../aztec-nr/balance-set" } diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test/counter_contract/contract/src/main.nr similarity index 51% rename from noir-projects/noir-contracts/contracts/test/counter_contract/src/main.nr rename to noir-projects/noir-contracts/contracts/test/counter_contract/contract/src/main.nr index 6a735d3af490..87260f157ad1 100644 --- a/noir-projects/noir-contracts/contracts/test/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test/counter_contract/contract/src/main.nr @@ -82,74 +82,4 @@ pub contract Counter { self.call(Counter::at(other_counter).increment(owner)); } - - mod test { - use crate::Counter; - use aztec::{ - protocol::address::AztecAddress, test::helpers::test_environment::TestEnvironment, - }; - - pub unconstrained fn setup( - initial_value: u128, - ) -> (TestEnvironment, AztecAddress, AztecAddress) { - // Setup env, generate keys - let mut env = TestEnvironment::new(); - let owner = env.create_light_account(); - - // Deploy contract and initialize - let initializer = Counter::interface().initialize(initial_value as u64, owner); - let contract_address = - env.deploy("Counter").with_private_initializer(owner, initializer); - (env, contract_address, owner) - } - - #[test] - unconstrained fn test_increment() { - let initial_value = 5; - let (mut env, contract_address, owner) = setup(initial_value); - - // Read the stored value in the note - let initial_counter = - env.execute_utility(Counter::at(contract_address).get_counter(owner)); - assert( - initial_counter == initial_value, - f"Expected {initial_value} but got {initial_counter}", - ); - - // Increment the counter - env.call_private(owner, Counter::at(contract_address).increment(owner)); - - let incremented_counter = - env.execute_utility(Counter::at(contract_address).get_counter(owner)); - let expected_current_value = initial_value + 1; - assert( - expected_current_value == incremented_counter, - f"Expected {expected_current_value} but got {incremented_counter}", - ); - } - - #[test] - unconstrained fn extended_incrementing_and_decrementing() { - let initial_value = 5; - let (env, contract_address, owner) = setup(initial_value); - - // Checking that the note was discovered from private logs - let initial_note_value = - env.execute_utility(Counter::at(contract_address).get_counter(owner)); - assert(initial_note_value == initial_value); - - env.call_private(owner, Counter::at(contract_address).increment_twice(owner)); - - assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 7); - - let _ = env.call_private( - owner, - Counter::at(contract_address).increment_and_decrement(owner), - ); - assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 7); - - env.call_private(owner, Counter::at(contract_address).decrement(owner)); - assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 6); - } - } } diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/src/test.nr b/noir-projects/noir-contracts/contracts/test/counter_contract/src/test.nr deleted file mode 100644 index 71f6bdde08e3..000000000000 --- a/noir-projects/noir-contracts/contracts/test/counter_contract/src/test.nr +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Counter; -use aztec::{ - oracle::notes::set_sender_for_tags, protocol::address::AztecAddress, - test::helpers::test_environment::TestEnvironment, -}; - -pub unconstrained fn setup(initial_value: Field) -> (TestEnvironment, AztecAddress, AztecAddress) { - // Setup env, generate keys - let mut env = TestEnvironment::new(); - let owner = env.create_light_account(); - - // Deploy contract and initialize - let initializer = Counter::interface().initialize(initial_value as u64, owner); - let contract_address = env.deploy("Counter").with_private_initializer(owner, initializer); - (env, contract_address, owner) -} diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/test/Nargo.toml b/noir-projects/noir-contracts/contracts/test/counter_contract/test/Nargo.toml new file mode 100644 index 000000000000..1d5b103087e7 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/counter_contract/test/Nargo.toml @@ -0,0 +1,10 @@ +[package] +name = "counter_contract_test" +authors = [""] +compiler_version = ">=0.25.0" +type = "lib" + +[dependencies] +aztec = { path = "../../../../../aztec-nr/aztec" } +balance_set = { path = "../../../../../aztec-nr/balance-set" } +counter_contract = { path = "../contract" } diff --git a/noir-projects/noir-contracts/contracts/test/counter_contract/test/src/lib.nr b/noir-projects/noir-contracts/contracts/test/counter_contract/test/src/lib.nr new file mode 100644 index 000000000000..2b1e84c12c3f --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/counter_contract/test/src/lib.nr @@ -0,0 +1,54 @@ +use aztec::{protocol::address::AztecAddress, test::helpers::test_environment::TestEnvironment}; +use counter_contract::Counter; + +pub unconstrained fn setup(initial_value: u128) -> (TestEnvironment, AztecAddress, AztecAddress) { + // Setup env, generate keys + let mut env = TestEnvironment::new(); + let owner = env.create_light_account(); + + // Deploy contract and initialize + let initializer = Counter::interface().initialize(initial_value as u64, owner); + let contract_address = + env.deploy("@counter_contract/Counter").with_private_initializer(owner, initializer); + (env, contract_address, owner) +} + +#[test] +unconstrained fn test_increment() { + let initial_value = 5; + let (mut env, contract_address, owner) = setup(initial_value); + + // Read the stored value in the note + let initial_counter = env.execute_utility(Counter::at(contract_address).get_counter(owner)); + assert(initial_counter == initial_value, f"Expected {initial_value} but got {initial_counter}"); + + // Increment the counter + env.call_private(owner, Counter::at(contract_address).increment(owner)); + + let incremented_counter = env.execute_utility(Counter::at(contract_address).get_counter(owner)); + let expected_current_value = initial_value + 1; + assert( + expected_current_value == incremented_counter, + f"Expected {expected_current_value} but got {incremented_counter}", + ); +} + +#[test] +unconstrained fn extended_incrementing_and_decrementing() { + let initial_value = 5; + let (env, contract_address, owner) = setup(initial_value); + + // Checking that the note was discovered from private logs + let initial_note_value = env.execute_utility(Counter::at(contract_address).get_counter(owner)); + assert(initial_note_value == initial_value); + + env.call_private(owner, Counter::at(contract_address).increment_twice(owner)); + + assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 7); + + let _ = env.call_private(owner, Counter::at(contract_address).increment_and_decrement(owner)); + assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 7); + + env.call_private(owner, Counter::at(contract_address).decrement(owner)); + assert_eq(env.execute_utility(Counter::at(contract_address).get_counter(owner)), 6); +} diff --git a/yarn-project/aztec/scripts/init.sh b/yarn-project/aztec/scripts/init.sh index fa66617ff6ed..3fae0e67f894 100755 --- a/yarn-project/aztec/scripts/init.sh +++ b/yarn-project/aztec/scripts/init.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash set -euo pipefail -NARGO=${NARGO:-nargo} script_path=$(realpath $(dirname "$0")) +name_arg="" + +# Check for help first for arg in "$@"; do if [ "$arg" == "--help" ] || [ "$arg" == "-h" ]; then cat << 'EOF' @@ -13,23 +15,31 @@ Usage: aztec init [OPTIONS] Options: --name Name of the package [default: current directory name] - --lib Use a library template -h, --help Print help -This command creates a new Aztec Noir project in the current directory using nargo -and automatically adds the Aztec.nr dependency to your Nargo.toml file. - +This command creates a new Aztec Noir project in the current directory with +a workspace containing a contract crate and a test crate, and automatically +adds the Aztec.nr dependency to both. EOF exit 0 fi - if [ "$arg" == "--lib" ]; then - is_contract=0 - fi done -echo "Initializing Noir project..." -$NARGO init "$@" +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --name) + name_arg="$2" + shift 2 + ;; + *) + shift + ;; + esac +done + +# Derive package name: use --name if provided, otherwise use current directory name +package_name="${name_arg:-$(basename $(pwd))}" -if [ "${is_contract:-1}" -eq 1 ]; then - $script_path/setup_project.sh -fi +echo "Initializing Aztec contract project..." +$script_path/setup_workspace.sh "$package_name" diff --git a/yarn-project/aztec/scripts/new.sh b/yarn-project/aztec/scripts/new.sh index 6901a235bfe8..37584fffae0a 100755 --- a/yarn-project/aztec/scripts/new.sh +++ b/yarn-project/aztec/scripts/new.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -euo pipefail -NARGO=${NARGO:-nargo} script_path=$(realpath $(dirname "$0")) -type_arg="--contract" +name_arg="" +project_path="" while [[ $# -gt 0 ]]; do case $1 in @@ -19,20 +19,16 @@ Arguments: Options: --name Name of the package [default: package directory name] - --lib Create a library template instead of a contract -h, --help Print help -This command creates a new Aztec Noir project using nargo and automatically -adds the Aztec.nr dependency to your Nargo.toml file. +This command creates a new Aztec Noir project with a workspace containing +a contract crate and a test crate, and automatically adds the Aztec.nr +dependency to both. EOF exit 0 ;; - --lib) - type_arg="--lib" - shift - ;; --name) - name_arg="--name $2" + name_arg="$2" shift 2 ;; *) @@ -50,10 +46,15 @@ if [ -z "$project_path" ]; then exit 1 fi -echo "Creating new Noir project at $project_path..." -$NARGO new $type_arg ${name_arg:-} $project_path - -if [ "$type_arg" == "--contract" ]; then - cd $project_path - $script_path/setup_project.sh +if [ -d "$project_path" ] && [ "$(ls -A $project_path 2>/dev/null)" ]; then + echo "Error: $project_path already exists and is not empty" + exit 1 fi + +# Derive package name: use --name if provided, otherwise use directory basename +package_name="${name_arg:-$(basename $project_path)}" + +echo "Creating new Aztec contract project at $project_path..." +mkdir -p "$project_path" +cd "$project_path" +$script_path/setup_workspace.sh "$package_name" diff --git a/yarn-project/aztec/scripts/setup_project.sh b/yarn-project/aztec/scripts/setup_project.sh deleted file mode 100755 index 1797a5625491..000000000000 --- a/yarn-project/aztec/scripts/setup_project.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Get the actual aztec version for the git tag. -AZTEC_VERSION=$(jq -r '.version' $(dirname $0)/../package.json) -NARGO_TOML_PATH="Nargo.toml" -MAIN_NR_PATH="src/main.nr" - -if [ ! -f "$NARGO_TOML_PATH" ]; then - >&2 echo "Warning: Could not find Nargo.toml at $NARGO_TOML_PATH to add aztec dependency" - exit 1 -fi - -if [ ! -f "$MAIN_NR_PATH" ]; then - >&2 echo "Warning: Could not find main.nr at $MAIN_NR_PATH" - exit 1 -fi - -# Add aztec dependency to Nargo.toml -echo "" >> "$NARGO_TOML_PATH" -echo "aztec = { git=\"https://github.com/AztecProtocol/aztec-nr\", tag=\"v${AZTEC_VERSION}\", directory=\"aztec\" }" >> "$NARGO_TOML_PATH" -echo "Added aztec dependency (v${AZTEC_VERSION}) to Nargo.toml" - -# Replace the contents of main.nr with the Aztec contract template -cat > "$MAIN_NR_PATH" << 'EOF' -use aztec::macros::aztec; - -#[aztec] -contract Main {} -EOF -echo "Created main.nr with Aztec contract template" diff --git a/yarn-project/aztec/scripts/setup_workspace.sh b/yarn-project/aztec/scripts/setup_workspace.sh new file mode 100755 index 000000000000..11ca9deb68f0 --- /dev/null +++ b/yarn-project/aztec/scripts/setup_workspace.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Creates an Aztec contract workspace with a contract crate and a test crate. +# Usage: setup_workspace.sh +# Must be called from the workspace root directory. + +package_name=$1 + +if [ -z "$package_name" ]; then + echo "Error: package name is required" + exit 1 +fi + +if [ -f "Nargo.toml" ]; then + echo "Error: Nargo.toml already exists in the current directory" + exit 1 +fi + +# Get the actual aztec version for the git tag. +AZTEC_VERSION=$(jq -r '.version' $(dirname $0)/../package.json) + +# Create workspace root Nargo.toml +cat > Nargo.toml << 'EOF' +[workspace] +members = ["contract", "test"] +EOF + +# Create contract crate +mkdir -p contract/src +cat > contract/Nargo.toml << CEOF +[package] +name = "${package_name}" +type = "contract" + +[dependencies] +aztec = { git="https://github.com/AztecProtocol/aztec-nr", tag="v${AZTEC_VERSION}", directory="aztec" } +CEOF + +cat > contract/src/main.nr << 'EOF' +use aztec::macros::aztec; + +#[aztec] +pub contract Main { + use aztec::macros::functions::{external, initializer}; + + #[initializer] + #[external("private")] + fn constructor() {} +} +EOF + +# Create test crate +mkdir -p test/src +cat > test/Nargo.toml << TEOF +[package] +name = "${package_name}_test" +type = "lib" + +[dependencies] +aztec = { git="https://github.com/AztecProtocol/aztec-nr", tag="v${AZTEC_VERSION}", directory="aztec" } +${package_name} = { path = "../contract" } +TEOF + +cat > test/src/lib.nr << 'NOIR' +use aztec::test::helpers::test_environment::TestEnvironment; +use __PACKAGE_NAME__::Main; + +#[test] +unconstrained fn test_constructor() { + let mut env = TestEnvironment::new(); + let deployer = env.create_light_account(); + + // Deploy the contract with the default constructor: + let contract_address = env.deploy("@__PACKAGE_NAME__/Main").with_private_initializer( + deployer, + Main::interface().constructor(), + ); + + // Deploy without an initializer: + let contract_address = env.deploy("@__PACKAGE_NAME__/Main").without_initializer(); +} +NOIR + +sed -i "s/__PACKAGE_NAME__/${package_name}/g" test/src/lib.nr + +# Create README +cat > README.md << REOF +# ${package_name} + +An Aztec Noir contract project. + +## Compile + +\`\`\`bash +aztec compile +\`\`\` + +This compiles the contract in \`contract/\` and outputs artifacts to \`target/\`. + +## Test + +\`\`\`bash +aztec test +\`\`\` + +This runs the tests in \`test/\`. + +## Generate TypeScript bindings + +\`\`\`bash +aztec codegen target -o src/artifacts +\`\`\` + +This generates TypeScript contract artifacts from the compiled output in \`target/\` into \`src/artifacts/\`. +REOF + +# Create .gitignore +cat > .gitignore << 'GEOF' +target/ +codegenCache.json +GEOF + +echo "Created Aztec contract workspace with crates '${package_name}' and '${package_name}_test'"