diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/dev_docs/cli/sandbox-reference.md index 71b5c427c55..fa6d0087f98 100644 --- a/docs/docs/dev_docs/cli/sandbox-reference.md +++ b/docs/docs/dev_docs/cli/sandbox-reference.md @@ -61,7 +61,9 @@ MODE='sandbox' # Option to start the sandbox or a standalone part of the system. AZTEC_NODE_PORT=8079 # The port that the Aztec node wil be listening to (default: 8079) PXE_PORT=8080 # The port that the PXE will be listening to (default: 8080) - +# Ethereum Forking (Optional: not enabled by default) # +FORK_BLOCK_NUMBER=0 # The block number to fork from +FORK_URL="" # The URL of the Ethereum node to fork from ## Polling intervals ## ARCHIVER_POLLING_INTERVAL_MS=50 @@ -78,7 +80,6 @@ Variables like `DEPLOY_AZTEC_CONTRACTS` & `AZTEC_NODE_PORT` are valid here as de `TEST_ACCOUNTS` cannot be used here because the Aztec node does not control an Aztec account to deploy contracts from. ```sh - # P2P config # # Configuration variables for connecting a Node to the Aztec Node P2P network. You'll need a running P2P-Bootstrap node to connect to. P2P_ENABLED='false' # A flag to enable P2P networking for this node. (default: false) diff --git a/docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md b/docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md index 4592cc2e0f6..bbb5915ff12 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md +++ b/docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md @@ -8,32 +8,7 @@ In this step, we will write our token portal contract on L1. In `l1-contracts/contracts` in your file called `TokenPortal.sol` paste this: -```solidity -pragma solidity ^0.8.20; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; - -// Messaging -import {IRegistry} from "@aztec/l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol"; -import {IInbox} from "@aztec/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol"; -import {DataStructures} from "@aztec/l1-contracts/src/core/libraries/DataStructures.sol"; -import {Hash} from "@aztec/l1-contracts/src/core/libraries/Hash.sol"; - -contract TokenPortal { - using SafeERC20 for IERC20; - - IRegistry public registry; - IERC20 public underlying; - bytes32 public l2TokenAddress; - - function initialize(address _registry, address _underlying, bytes32 _l2TokenAddress) external { - registry = IRegistry(_registry); - underlying = IERC20(_underlying); - l2TokenAddress = _l2TokenAddress; - } -} -``` +#include_code init /l1-contracts/test/portals/TokenPortal.sol solidity This imports relevant files including the interfaces used by the Aztec rollup. And initializes the contract with the following parameters: @@ -45,20 +20,7 @@ Create a basic ERC20 contract that can mint tokens to anyone. We will use this t Create a file `PortalERC20.sol` in the same folder and add: -```solidity -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract PortalERC20 is ERC20 { - constructor() ERC20("Portal", "PORTAL") {} - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } -} -``` +#include_code contract /l1-contracts/test/portals/PortalERC20.sol solidity ## Depositing tokens to Aztec publicly @@ -108,8 +70,10 @@ Note that because L1 is public, everyone can inspect and figure out the fee, con **So how do we privately consume the message on Aztec?** -On Aztec, anytime something is consumed, we emit a nullifier hash and add it to the nullifier tree. This prevents double-spends. The nullifier hash is a hash of the message that is consumed. So without the secret, one could reverse engineer the expected nullifier hash that might be emitted on L2 upon message consumption. Hence, to consume the message on L2, the user provides a secret to the private noir function, which computes the hash and asserts that it matches to what was provided in the L1->L2 message. This secret is then included in the nullifier hash computation and emits this nullifier. This way, anyone inspecting the blockchain, won’t know which nullifier hash corresponds to the L1->L2 message consumption. +On Aztec, anytime something is consumed (i.e. deleted), we emit a nullifier hash and add it to the nullifier tree. This prevents double-spends. The nullifier hash is a hash of the message that is consumed. So without the secret, one could reverse engineer the expected nullifier hash that might be emitted on L2 upon message consumption. To consume the message on L2, the user provides a secret to the private function, which computes the hash and asserts that it matches to what was provided in the L1->L2 message. This secret is included in the nullifier hash computation and the nullifier is added to the nullifier tree. Anyone inspecting the blockchain won’t know which nullifier hash corresponds to the L1->L2 message consumption. -Note: the secret hashes are Pedersen hashes since the hash has to be computed on L2, and sha256 hash is very expensive for zk circuits. The content hash however is a sha256 hash truncated to a field as clearly shown before. +:::note +Secret hashes are Pedersen hashes since the hash has to be computed on L2 and sha256 hash is very expensive for zk circuits. The content hash however is a sha256 hash truncated to a field as shown before. +::: In the next step we will start writing our L2 smart contract to mint these tokens on L2. diff --git a/docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md b/docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md index 371659e0d67..9101322b633 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md +++ b/docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md @@ -6,23 +6,18 @@ In this step we will start writing our Aztec.nr bridge smart contract and write ## Initial contract setup -In our `token-bridge` Noir project in `aztec-contracts`, under `src` there is an example `main.nr` file. Delete all the code in here and paste this to define imports and initialize the constructor: +In our `token-bridge` Aztec project in `aztec-contracts`, under `src` there is an example `main.nr` file. Paste this to define imports and initialize the constructor: -```rust -mod util; -#include_code token_bridge_imports /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr raw - use crate::token_interface::Token; - use crate::util::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; -#include_code token_bridge_storage_and_constructor /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr raw -``` +#include_code token_bridge_imports /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust -This imports Aztec-related dependencies and our two helper files `token_interface.nr` and `util.nr`. +#include_code token_bridge_storage_and_constructor /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust + +This imports Aztec-related dependencies and our helper file `token_interface.nr`. (The code above will give errors right now - this is because we haven't implemented util and token_interface yet.) In `token_interface.nr`, add this: -#include_code token_bridge_token_interface /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/token_interface.nr rust -We will write `util.nr` as needed. +#include_code token_bridge_token_interface /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/token_interface.nr rust ## Consume the L1 message @@ -31,9 +26,6 @@ In the previous step, we have moved our funds to the portal and created a L1->L2 In `main.nr`, now paste this `claim_public` function: #include_code claim_public /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust -In your `util.nr` paste this `mint_public_content_hash` function: -#include_code mint_public_content_hash_nr /yarn-project/noir-contracts/src/contracts/token_portal_content_hash_lib/src/lib.nr rust - The `claim_public` function enables anyone to consume the message on the user's behalf and mint tokens for them on L2. This is fine as the minting of tokens is done publicly anyway. **What’s happening here?** @@ -55,9 +47,7 @@ Now we will create a function to mint the amount privately. Paste this into your #include_code call_mint_on_token /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust -Then inside your `util.nr`, paste this: - -#include_code get_mint_private_content_hash /yarn-project/noir-contracts/src/contracts/token_portal_content_hash_lib/src/lib.nr rust +The `get_mint_private_content_hash` function is imported from the `token_portal_content_hash_lib`. If the content hashes were constructed similarly for `mint_private` and `mint_publicly`, then content intended for private execution could have been consumed by calling the `claim_public` method. By making these two content hashes distinct, we prevent this scenario. diff --git a/docs/docs/dev_docs/tutorials/token_portal/setup.md b/docs/docs/dev_docs/tutorials/token_portal/setup.md index b4c011a659d..4b8076d412f 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/setup.md +++ b/docs/docs/dev_docs/tutorials/token_portal/setup.md @@ -48,7 +48,7 @@ aztec-contracts └── token_bridge ├── Nargo.toml ├── src - ├── main + ├── main.nr ``` Inside `Nargo.toml` add the following content: @@ -62,8 +62,7 @@ type = "contract" [dependencies] aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/aztec" } -value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/value-note"} -safe_math = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/safe-math"} +token_portal_content_hash_lib = { git="https://github.com/AztecProtocol/aztec-packages/", tag="aztec-packages-v0.16.9", directory="yarn-project/noir-contracts/src/contracts/token_portal_content_hash_lib" } protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/noir-protocol-circuits/src/crates/types"} ``` @@ -76,7 +75,6 @@ aztec-contracts ├── src ├── main.nr ├── token_interface.nr - ├── util.nr ``` # Create a JS hardhat project @@ -110,8 +108,6 @@ This is what your `l1-contracts` should look like: ```tree ├── README.md -├── artifacts -├── cache ├── contracts ├── hardhat.config.js ├── node_modules @@ -138,6 +134,8 @@ yarn add @aztec/aztec.js @aztec/noir-contracts @aztec/types @aztec/foundation @a yarn add -D jest @jest/globals ts-jest ``` +If you are going to track this repo using git, consider adding a `.gitignore` file to your `src` directory and adding `node_modules` to it. + In `package.json`, add: ```json diff --git a/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md b/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md index 9f66177bce9..99c4a67ea9e 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md +++ b/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md @@ -10,9 +10,7 @@ Go back to your `main.nr` and paste this: #include_code exit_to_l1_public /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust -For this to work we will need this helper function, in `util.nr`: - -#include_code get_withdraw_content_hash /yarn-project/noir-contracts/src/contracts/token_portal_content_hash_lib/src/lib.nr rust +For this to work we import the `get_withdraw_content_hash` helper function from the `token_portal_content_hash_lib`. **What’s happening here?** @@ -53,6 +51,16 @@ We also use a `_withCaller` parameter to determine the appropriate party that ca We call this pattern _designed caller_ which enables a new paradigm **where we can construct other such portals that talk to the token portal and therefore create more seamless crosschain legos** between L1 and L2. +Before we can compile and use the contract, we need to add two additional functions. + +We need a function that let's us read the token value. + +#include_code read_token /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust + +And the `compute_note_hash_and_nullifier` required on every contract. + +#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr rust + ## Compile code Congratulations, you have written all the contracts we need for this tutorial! Now let's compile them. diff --git a/l1-contracts/test/portals/PortalERC20.sol b/l1-contracts/test/portals/PortalERC20.sol index d53f551613c..4c1dc5372be 100644 --- a/l1-contracts/test/portals/PortalERC20.sol +++ b/l1-contracts/test/portals/PortalERC20.sol @@ -1,4 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 +// docs:start:contract pragma solidity ^0.8.0; import "@oz/token/ERC20/ERC20.sol"; @@ -10,3 +11,4 @@ contract PortalERC20 is ERC20 { _mint(to, amount); } } +// docs:end:contract diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index c3afb268351..ccd6661ea83 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -1,3 +1,4 @@ +// docs:start:init pragma solidity >=0.8.18; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; @@ -23,6 +24,7 @@ contract TokenPortal { underlying = IERC20(_underlying); l2TokenAddress = _l2TokenAddress; } + // docs:end:init // docs:start:deposit_public /** diff --git a/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr index f6b13fb5f02..3c6ee6879c6 100644 --- a/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr @@ -19,11 +19,11 @@ contract TokenBridge { types::type_serialization::address_serialization::AddressSerializationMethods, selector::compute_selector, }; - // docs:end:token_bridge_imports use dep::token_portal_content_hash_lib::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; use crate::token_interface::Token; + // docs:end:token_bridge_imports // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. @@ -148,9 +148,11 @@ contract TokenBridge { // /// Unconstrained /// + // docs:start:read_token unconstrained fn token() -> pub AztecAddress { storage.token.read() } + // docs:end:read_token #[aztec(public)] internal fn _initialize(token: AztecAddress) {