diff --git a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/docs/tutorials/contract_tutorials/recursive_verification.md b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/docs/tutorials/contract_tutorials/recursive_verification.md index 624a164583dd..ac113f01810d 100644 --- a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/docs/tutorials/contract_tutorials/recursive_verification.md +++ b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/docs/tutorials/contract_tutorials/recursive_verification.md @@ -30,7 +30,7 @@ Install the required tools: ```bash # Install Aztec CLI -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) aztec-up 3.0.0-devnet.6-patch.1 # Install Nargo via noirup diff --git a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_devnet.md b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_devnet.md index 3a61955d58d3..a8f718854701 100644 --- a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_devnet.md +++ b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_devnet.md @@ -39,7 +39,7 @@ Before working with devnet, ensure you have: 2. Aztec CLI installed: ```sh -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` 3. The devnet version installed: diff --git a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_local_network.md b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_local_network.md index 0fb210812cf1..6a592c631b31 100644 --- a/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_local_network.md +++ b/docs/developer_versioned_docs/version-v3.0.0-devnet.6-patch.1/getting_started_on_local_network.md @@ -43,7 +43,7 @@ Docker needs to be running in order to install the local network. Find instructi Run: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` Once the installation is complete, install the specific version: diff --git a/docs/docs-developers/docs/aztec-js/how_to_connect_to_local_network.md b/docs/docs-developers/docs/aztec-js/how_to_connect_to_local_network.md index 171672a7c549..c8c7c058988f 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_connect_to_local_network.md +++ b/docs/docs-developers/docs/aztec-js/how_to_connect_to_local_network.md @@ -23,45 +23,27 @@ yarn add @aztec/aztec.js@#include_version_without_prefix @aztec/test-wallet@#inc Create a node client and TestWallet to interact with the local network: -```typescript -import { createAztecNodeClient, waitForNode } from "@aztec/aztec.js/node"; -import { - TestWallet, - registerInitialLocalNetworkAccountsInWallet, -} from "@aztec/test-wallet/server"; +#include_code connect_to_network /docs/examples/ts/aztecjs_connection/index.ts typescript -const nodeUrl = "http://localhost:8080"; -const node = createAztecNodeClient(nodeUrl); +:::note About TestWallet +`TestWallet` is a simplified wallet for local development that implements the same `Wallet` interface used in production. It handles key management, transaction signing, and proof generation in-process without external dependencies. -// Wait for the network to be ready -await waitForNode(node); +**Why use it for testing?** It starts instantly, requires no setup, and provides deterministic behavior—ideal for automated tests and rapid iteration. -// Create a TestWallet connected to the node -const wallet = await TestWallet.create(node); -``` - -`TestWallet` is a development wallet that handles account management and transaction signing locally, suitable for testing and development. +**Production wallets** (like browser extensions or mobile apps) implement the same interface but store keys securely, may require user confirmation for transactions, and typically run in a separate process. Code written against `TestWallet` works with any `Wallet` implementation, so your application logic transfers directly to production. +::: ### Verify the connection Get node information to confirm your connection: -```typescript -const nodeInfo = await node.getNodeInfo(); -console.log("Connected to local network version:", nodeInfo.nodeVersion); -console.log("Chain ID:", nodeInfo.l1ChainId); -``` +#include_code verify_connection /docs/examples/ts/aztecjs_connection/index.ts typescript ### Load pre-funded accounts The local network has accounts pre-funded with fee juice to pay for gas. Register them in your wallet: -```typescript -const [alice, bob] = await registerInitialLocalNetworkAccountsInWallet(wallet); - -console.log(`Alice's address: ${alice.toString()}`); -console.log(`Bob's address: ${bob.toString()}`); -``` +#include_code load_accounts /docs/examples/ts/aztecjs_connection/index.ts typescript These accounts are pre-funded with fee juice (the native gas token) at genesis, so you can immediately send transactions without needing to bridge funds from L1. @@ -69,12 +51,7 @@ These accounts are pre-funded with fee juice (the native gas token) at genesis, Verify that an account has fee juice for transactions: -```typescript -import { getFeeJuiceBalance } from "@aztec/aztec.js/utils"; - -const aliceBalance = await getFeeJuiceBalance(alice, node); -console.log(`Alice's fee juice balance: ${aliceBalance}`); -``` +#include_code check_fee_juice /docs/examples/ts/aztecjs_connection/index.ts typescript ## Next steps diff --git a/docs/docs-developers/docs/aztec-js/how_to_create_account.md b/docs/docs-developers/docs/aztec-js/how_to_create_account.md index 164a584899a2..e6ed6a6f37c9 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_create_account.md +++ b/docs/docs-developers/docs/aztec-js/how_to_create_account.md @@ -20,16 +20,9 @@ yarn add @aztec/aztec.js@#include_version_without_prefix @aztec/test-wallet@#inc ## Create a new account -Use the wallet's `createSchnorrAccount` method to create a new account with a random secret and salt: +Using the [`wallet` from the connection guide](./how_to_connect_to_local_network.md), call `createSchnorrAccount` to create a new account with a random secret and salt: -```typescript -import { Fr } from "@aztec/aztec.js/fields"; - -const secret = Fr.random(); -const salt = Fr.random(); -const newAccount = await wallet.createSchnorrAccount(secret, salt); -console.log("New account address:", newAccount.address.toString()); -``` +#include_code create_account /docs/examples/ts/aztecjs_connection/index.ts typescript The secret is used to derive the account's encryption keys, and the salt ensures address uniqueness. The signing key is automatically derived from the secret. @@ -48,13 +41,12 @@ If your account doesn't have Fee Juice, use the [Sponsored Fee Payment Contract] ```typescript import { AztecAddress } from "@aztec/aztec.js/addresses"; +// newAccount is the account created in the previous section const deployMethod = await newAccount.getDeployMethod(); -await deployMethod - .send({ - from: AztecAddress.ZERO, - fee: { paymentMethod: sponsoredPaymentMethod }, - }) - .wait(); +await deployMethod.send({ + from: AztecAddress.ZERO, + fee: { paymentMethod: sponsoredPaymentMethod }, +}); ``` :::info @@ -68,12 +60,11 @@ If your account already has Fee Juice (for example, [bridged from L1](./how_to_p ```typescript import { AztecAddress } from "@aztec/aztec.js/addresses"; +// newAccount is the account created in the previous section const deployMethod = await newAccount.getDeployMethod(); -await deployMethod - .send({ - from: AztecAddress.ZERO, - }) - .wait(); +await deployMethod.send({ + from: AztecAddress.ZERO, +}); ``` The `from: AztecAddress.ZERO` is required because there's no existing account to send from—the transaction itself creates the account. diff --git a/docs/docs-developers/docs/aztec-js/how_to_deploy_contract.md b/docs/docs-developers/docs/aztec-js/how_to_deploy_contract.md index a3b758b7464f..99281f8d9f24 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_deploy_contract.md +++ b/docs/docs-developers/docs/aztec-js/how_to_deploy_contract.md @@ -9,13 +9,12 @@ This guide shows you how to deploy compiled contracts to Aztec using the generat ## Overview -Deploying a contract to Aztec involves publishing the contract class (the bytecode) and creating a contract instance at a specific address. The generated TypeScript classes handle this process through an API: you call `deploy()` with constructor arguments, `send()` with transaction options, and `deployed()` to wait for completion. The contract address is deterministically computed from the contract class, constructor arguments, salt, and deployer address. +Deploying a contract to Aztec involves publishing the contract class (the bytecode) and creating a contract instance at a specific address. The generated TypeScript classes handle this process through an API: you call `deploy()` with constructor arguments and `send()` with transaction options to deploy and get the contract instance. The contract address is deterministically computed from the contract class, constructor arguments, salt, and deployer address. ## Prerequisites - Compiled contract artifacts (see [How to Compile](../aztec-nr/how_to_compile_contract.md)) -- Running Aztec local network -- Funded wallet for deployment fees +- [Connected to a network](./how_to_connect_to_local_network.md) with a `TestWallet` instance and funded accounts - TypeScript project set up ## Generate TypeScript bindings @@ -51,26 +50,24 @@ In the examples below, `wallet` refers to a `Wallet` instance that manages keys How you deploy depends on how you pay for it. When paying using an account's fee juice (like a test account on the local network): ```typescript +// wallet and alice are from the connection guide // Deploy with constructor arguments const contract = await MyContract.deploy( - deployer_wallet, + wallet, constructorArg1, - constructorArg2 -) - .send({ from: testAccount.address }) // testAccount has fee juice and is registered in the deployer_wallet - .deployed(); + constructorArg2, +).send({ from: aliceAddress }); // alice has fee juice and is registered in the wallet ``` -On testnet, you likely won't have funds in `testAccount` to pay for fee juice. Instead, pay fees using the [Sponsored Fee Payment Contract method](./how_to_pay_fees.md): +On testnet, your account likely won't have Fee Juice. Instead, pay fees using the [Sponsored Fee Payment Contract method](./how_to_pay_fees.md): ```typescript +// wallet is from the connection guide; sponsoredPaymentMethod is from the fees guide const contract = await MyContract.deploy( wallet, constructorArg1, - constructorArg2 -) - .send({ from: alice.address, fee: { paymentMethod: sponsoredPaymentMethod } }) // using the Sponsored FPC - .deployed(); + constructorArg2, +).send({ from: aliceAddress, fee: { paymentMethod: sponsoredPaymentMethod } }); // using the Sponsored FPC ``` Here's a complete example from the test suite: @@ -86,14 +83,13 @@ By default, the deployment's salt is random, but you can specify it (for example ```typescript import { Fr } from "@aztec/aztec.js/fields"; +// wallet and alice are from the connection guide const salt = Fr.random(); -const contract = await MyContract.deploy(wallet, arg1, arg2) - .send({ - from: testAccount.address, - contractAddressSalt: salt, - }) - .deployed(); +const contract = await MyContract.deploy(wallet, arg1, arg2).send({ + from: aliceAddress, + contractAddressSalt: salt, +}); ``` ### Deploy universally @@ -110,20 +106,7 @@ Universal deployment excludes the sender from address computation, allowing the Deploy without running the constructor: -```typescript -const contract = await MyContract.deploy(wallet) - .send({ - from: testAccount.address, - skipInitialization: true, - }) - .deployed(); - -// Initialize later -await contract.methods - .initialize(arg1, arg2) - .send({ from: testAccount.address }) - .wait(); -``` +#include_code skip_initialization /docs/examples/ts/aztecjs_advanced/index.ts typescript ### Deploy with a specific initializer @@ -132,6 +115,7 @@ Some contracts have multiple initializer functions (e.g., both a private `constr #include_code deploy_with_opts yarn-project/end-to-end/src/e2e_deploy_contract/deploy_method.test.ts typescript The `deployWithOpts` method accepts an options object as its first argument: + - `wallet`: The wallet to use for deployment (required) - `method`: The name of the initializer function to call (optional, defaults to `constructor`) - `publicKeys`: Custom public keys for the contract instance (optional) @@ -152,6 +136,7 @@ import { Fr } from "@aztec/aztec.js/fields"; const salt = Fr.random(); // Calculate address without deploying +// wallet is from the connection guide (see prerequisites) const deployMethod = MyContract.deploy(wallet, arg1, arg2); const instance = await deployMethod.getInstance({ contractAddressSalt: salt }); const address = instance.address; @@ -167,23 +152,13 @@ This is an advanced pattern. For most use cases, deploy the contract directly an ### Track deployment transaction -```typescript -const deployTx = MyContract.deploy(wallet, arg1, arg2).send({ - from: testAccount.address, -}); +Use `NO_WAIT` to get the transaction hash immediately and track deployment: -// Get transaction hash immediately -const txHash = await deployTx.getTxHash(); -console.log(`Deployment tx: ${txHash}`); +#include_code no_wait_deploy /docs/examples/ts/aztecjs_advanced/index.ts typescript -// Wait for the transaction to be mined -const receipt = await deployTx.wait(); -console.log(`Deployed in block ${receipt.blockNumber}`); +For most use cases, simply await the deployment to get the contract directly: -// Get the deployed contract instance -const contract = await deployTx.deployed(); -console.log(`Contract address: ${contract.address}`); -``` +#include_code deploy_contract /docs/examples/ts/aztecjs_connection/index.ts typescript ## Deploy multiple contracts @@ -197,40 +172,11 @@ Here's an example deploying a `TokenContract` with constructor arguments for adm When one contract depends on another, deploy them sequentially and pass the first contract's address: -```typescript -// Deploy first contract -const token = await TokenContract.deploy( - wallet, - admin.address, - "MyToken", - "MTK", - 18 -) - .send({ from: admin.address }) - .deployed(); - -// Deploy second contract with reference to first -const vault = await VaultContract.deploy(wallet, token.address) - .send({ from: admin.address }) - .deployed(); -``` +#include_code deploy_with_dependencies /docs/examples/ts/aztecjs_advanced/index.ts typescript ### Deploy contracts in parallel -```typescript -// Start all deployments simultaneously -const deployments = [ - Contract1.deploy(wallet, arg1).send({ from: deployer.address }), - Contract2.deploy(wallet, arg2).send({ from: deployer.address }), - Contract3.deploy(wallet, arg3).send({ from: deployer.address }), -]; - -// Wait for all to complete -const receipts = await Promise.all(deployments.map((d) => d.wait())); - -// Get deployed contract instances -const contracts = await Promise.all(deployments.map((d) => d.deployed())); -``` +#include_code parallel_deploy /docs/examples/ts/aztecjs_advanced/index.ts typescript :::tip[Parallel deployment considerations] Parallel deployment is faster, but transactions from the same account share a nonce sequence. The wallet handles nonce assignment automatically, but if one deployment fails, subsequent deployments may also fail due to nonce gaps. For reliable parallel deployments: @@ -263,11 +209,12 @@ The `getContractMetadata` method returns: ### Verify contract is callable ```typescript +// contract is from the deployment step above; alice is from the connection guide try { // Try calling a view function const result = await contract.methods .get_version() - .simulate({ from: testAccount.address }); + .simulate({ from: aliceAddress }); console.log("Contract is callable, version:", result); } catch (error) { console.error("Contract not accessible:", error.message); @@ -281,6 +228,7 @@ try { If a contract was deployed by another account: ```typescript +// wallet is from the connection guide; contractAddress is the address of the deployed contract const contract = await MyContract.at(contractAddress, wallet); // Register the contract with the wallet @@ -306,7 +254,7 @@ const instance = await getContractInstanceFromInstantiationParams( constructorArgs: [arg1, arg2], deployer: deployerAddress, salt: deploymentSalt, - } + }, ); await wallet.registerContract(instance, MyContract.artifact); diff --git a/docs/docs-developers/docs/aztec-js/how_to_pay_fees.md b/docs/docs-developers/docs/aztec-js/how_to_pay_fees.md index 26bc04d6d00e..d9d3f6fdf857 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_pay_fees.md +++ b/docs/docs-developers/docs/aztec-js/how_to_pay_fees.md @@ -11,8 +11,7 @@ This guide walks you through paying transaction fees on Aztec using various paym ## Prerequisites -- Running Aztec local network -- Deployed account wallet +- [Connected to a network](./how_to_connect_to_local_network.md) with a `TestWallet` instance and funded accounts - Understanding of [fee concepts](../foundational-topics/fees.md) :::info @@ -36,15 +35,15 @@ Fee Juice is the native fee token on Aztec. If your account has Fee Juice (for example, from a faucet), is [deployed](./how_to_create_account.md), and is registered in your wallet, it will be used automatically to pay for the fee of the transaction: ```typescript -const tx = await contract.methods +// contract is a deployed contract instance; aliceAddress is from the connection guide +const receipt = await contract.methods .myFunction(param1, param2) .send({ - from: fundedAccount.address, + from: aliceAddress, // no fee payment method needed - }) - .wait(); + }); -console.log("Transaction fee:", tx.transactionFee); +console.log("Transaction fee:", receipt.transactionFee); ``` ## Use Fee Payment Contracts @@ -55,32 +54,11 @@ Fee Payment Contracts (FPC) pay fees on your behalf, typically accepting a diffe The Sponsored FPC pays for fees unconditionally without requiring payment in return. It is available on both the local network and the testnet (deployed by Aztec Labs). -You can derive the Sponsored FPC address from its deployment parameters and salt (which defaults to `0`): +You can derive the Sponsored FPC address from its deployment parameters, register it with your wallet, and use it to pay for transactions: -```typescript -import { SponsoredFPCContract } from "@aztec/noir-contracts.js/SponsoredFPC"; -import { getContractInstanceFromInstantiationParams } from "@aztec/stdlib/contract"; -import { SponsoredFeePaymentMethod } from "@aztec/aztec.js/fee/testing"; -import { Fr } from "@aztec/aztec.js/fields"; - -const sponsoredFPCInstance = await getContractInstanceFromInstantiationParams( - SponsoredFPCContract.artifact, - { - salt: new Fr(0), - } -); -``` +#include_code sponsored_fpc_setup /docs/examples/ts/aztecjs_advanced/index.ts typescript -Register the contract with your wallet before using it: - -```typescript -await wallet.registerContract( - sponsoredFPCInstance, - SponsoredFPCContract.artifact -); -``` - -Then use it to pay for transactions: +Here's a simpler example from the test suite: #include_code sponsored_fpc_simple yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts typescript @@ -93,6 +71,7 @@ Third-party FPCs can pay for your fees using custom logic, such as accepting dif ```typescript import { GasSettings } from "@aztec/stdlib/gas"; +// node is from createAztecNodeClient() in the connection guide (see prerequisites) const maxFeesPerGas = (await node.getCurrentMinFees()).mul(1.5); //adjust this to your needs const gasSettings = GasSettings.default({ maxFeesPerGas }); ``` @@ -106,11 +85,13 @@ Public FPCs can be used in the same way: ```typescript import { PublicFeePaymentMethod } from "@aztec/aztec.js/fee"; +// wallet is from the connection guide; fpcAddress is the FPC contract address +// senderAddress is the account paying; gasSettings is from the step above const paymentMethod = new PublicFeePaymentMethod( fpcAddress, senderAddress, wallet, - gasSettings + gasSettings, ); ``` @@ -130,7 +111,7 @@ Fee Juice is non-transferable on L2, but you can bridge it from L1, claim it on import { createExtendedL1Client } from "@aztec/ethereum"; const walletClient = createExtendedL1Client( ["https://your-ethereum-host"], // ex. http://localhost:8545 on the local network (yes it runs Anvil under the hood) - privateKey // the private key for some account, needs funds for gas! + privateKey, // the private key for some account, needs funds for gas! ); // a helper to interact with the L1 fee juice portal @@ -138,17 +119,19 @@ import { L1FeeJuicePortalManager } from "@aztec/aztec.js/ethereum"; const portalManager = await L1FeeJuicePortalManager.new( node, // your Aztec node, ex. https://aztec-testnet-fullnode.zkv.xyz, or http://localhost:8080 for local network walletClient, - logger // a logger, ex. import { createLogger } from "@aztec/aztec.js" + logger, // a logger, ex. import { createLogger } from "@aztec/aztec.js" ); ``` Under the hood, `L1FeeJuicePortalManager` gets the L1 addresses from the node `node_getNodeInfo` endpoint. It then exposes an easy method `bridgeTokensPublic` which mints fee juice on L1 and sends it to an L2 address via the L1 portal: ```typescript +// portalManager is from the L1FeeJuicePortalManager setup above +// aliceAddress is an Aztec address from the connection guide const claim = await portalManager.bridgeTokensPublic( - acc.address, // the L2 address + aliceAddress, // the L2 address 1000000000000000000000n, // the amount to send to the L1 portal - true // whether to mint or not (set to false if your walletClient account already has fee juice!) + true, // whether to mint or not (set to false if your walletClient account already has fee juice!) ); console.log("Claim secret:", claim.claimSecret); @@ -160,12 +143,13 @@ After this transaction is minted on L1 and a few blocks pass, you can claim the ```typescript import { FeeJuicePaymentMethodWithClaim } from "@aztec/aztec.js/fee"; +// aliceAddress and claim are from the bridgeTokensPublic step above +// contract is a deployed contract instance; gasSettings is from the gas settings section // Use the claim from bridgeTokensPublic to pay for a transaction -const paymentMethod = new FeeJuicePaymentMethodWithClaim(acc.address, claim); +const paymentMethod = new FeeJuicePaymentMethodWithClaim(aliceAddress, claim); const receipt = await contract.methods .myFunction() - .send({ from: acc.address, fee: { gasSettings, paymentMethod } }) - .wait(); + .send({ from: aliceAddress, fee: { gasSettings, paymentMethod } }); ``` ## Configure gas settings @@ -177,6 +161,9 @@ Set custom gas limits by importing from `stdlib`: ```typescript import { GasSettings } from "@aztec/stdlib/gas"; +// contract is a deployed contract instance +// alice is from the connection guide +// paymentMethod is from one of the payment method sections above const gasSettings = GasSettings.from({ gasLimits: { daGas: 100000, l2Gas: 100000 }, teardownGasLimits: { daGas: 10000, l2Gas: 10000 }, @@ -184,32 +171,31 @@ const gasSettings = GasSettings.from({ maxPriorityFeesPerGas: { daGas: 1, l2Gas: 1 }, }); -const tx = await contract.methods +const receipt = await contract.methods .myFunction() .send({ - from: sender.address, + from: aliceAddress, fee: { paymentMethod, gasSettings, }, - }) - .wait(); + }); ``` ### Use automatic gas estimation ```typescript -const tx = await contract.methods +// contract, aliceAddress, and paymentMethod are from the examples above +const receipt = await contract.methods .myFunction() .send({ - from: sender.address, + from: aliceAddress, fee: { paymentMethod, estimateGas: true, estimatedGasPadding: 0.2, // 20% padding }, - }) - .wait(); + }); ``` :::tip diff --git a/docs/docs-developers/docs/aztec-js/how_to_read_data.md b/docs/docs-developers/docs/aztec-js/how_to_read_data.md index 99a367909069..aec0e7124333 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_read_data.md +++ b/docs/docs-developers/docs/aztec-js/how_to_read_data.md @@ -9,18 +9,14 @@ This guide shows you how to read data from Aztec contracts in TypeScript, includ ## Prerequisites +- [Connected to a network](./how_to_connect_to_local_network.md) with a `TestWallet` instance and funded accounts - A deployed contract instance (see [How to Deploy a Contract](./how_to_deploy_contract.md)) -- A wallet connection (see [How to Create an Account](./how_to_create_account.md)) ## Simulating functions The `simulate` method executes a contract function locally and returns its result. It works with private, public, and utility functions. No transaction is created and no gas is spent. -```typescript -const result = await contract.methods - .myFunction(arg1, arg2) - .simulate({ from: callerAddress }); -``` +#include_code simulate_function /docs/examples/ts/aztecjs_connection/index.ts typescript The `from` option specifies which address context to use for the simulation. This is required for all simulations, though it only affects private function execution (public functions ignore this value). @@ -33,6 +29,7 @@ The `from` option specifies which address context to use for the simulation. Thi For functions returning multiple values, destructure the result: ```typescript +// contract and callerAddress are from the example above const [value1, value2] = await contract.methods .get_multiple_values() .simulate({ from: callerAddress }); @@ -43,6 +40,7 @@ const [value1, value2] = await contract.methods Set `includeMetadata: true` to get additional information about the simulation: ```typescript +// contract and callerAddress are from the examples above const result = await contract.methods .balance_of_public(address) .simulate({ from: callerAddress, includeMetadata: true }); @@ -62,6 +60,7 @@ console.log("DA gas limit:", result.estimatedGas.gasLimits.daGas); When simulating private functions, the caller must have access to any private state being read. The PXE only has visibility into notes belonging to registered accounts. ```typescript +// contract and callerAddress are from the examples above // This works if callerAddress owns the notes const balance = await contract.methods .balance_of_private(callerAddress) @@ -95,6 +94,8 @@ Contracts emit data in two forms you can read: Use `aztecNode.getPublicLogs()` to retrieve raw log data: ```typescript +// aztecNode is from createAztecNodeClient() in the connection guide +// receipt is from a transaction's send() call // Get logs for a specific transaction const logs = await aztecNode.getPublicLogs({ txHash: receipt.txHash }); const rawFields = logs.logs[0].log.getEmittedFields(); // Fr[] @@ -164,34 +165,7 @@ collectedEvents.forEach((ev) => { To continuously monitor for new events, poll at regular intervals while tracking the last processed block: -```typescript -import { BlockNumber } from "@aztec/foundation/branded-types"; - -let lastProcessedBlock = startBlock; // BlockNumber type - -async function pollForEvents() { - const currentBlock = await aztecNode.getBlockNumber(); - - if (currentBlock > lastProcessedBlock) { - const events = await getDecodedPublicEvents( - aztecNode, - TokenContract.events.Transfer, - lastProcessedBlock + 1, - currentBlock - lastProcessedBlock - ); - - for (const event of events) { - // Process each event - console.log(`Transfer: ${event.amount} from ${event.from}`); - } - - lastProcessedBlock = currentBlock; - } -} - -// Poll every 10 seconds -setInterval(pollForEvents, 10000); -``` +#include_code poll_for_events /docs/examples/ts/aztecjs_advanced/index.ts typescript For private events, use the same pattern with `wallet.getPrivateEvents()` and update the `fromBlock` in your filter accordingly. diff --git a/docs/docs-developers/docs/aztec-js/how_to_send_transaction.md b/docs/docs-developers/docs/aztec-js/how_to_send_transaction.md index dbea23ce4c45..0bdbc3cef3ce 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_send_transaction.md +++ b/docs/docs-developers/docs/aztec-js/how_to_send_transaction.md @@ -13,9 +13,8 @@ Transactions on Aztec execute contract functions that modify state. Unlike simpl ## Prerequisites -- Deployed contract with its address and ABI -- Funded account wallet (see [paying fees](./how_to_pay_fees.md)) -- Running Aztec local network or connected to a network +- [Connected to a network](./how_to_connect_to_local_network.md) with a `TestWallet` instance and funded accounts +- Deployed contract with its address and ABI (see [How to Deploy](./how_to_deploy_contract.md)) - Understanding of [contract interactions](../aztec-nr/framework-description/how_to_call_contracts.md) ## Send a transaction @@ -25,16 +24,17 @@ After connecting to a contract: ```typescript import { Contract } from "@aztec/aztec.js"; +// wallet is from the connection guide; contractAddress and artifact are from your deployed contract const contract = await Contract.at(contractAddress, artifact, wallet); ``` Call a function and wait for it to be mined: ```typescript +// contract is from the step above; alice is from the connection guide const receipt = await contract.methods - .transfer(recipientAddress, amount) - .send({ from: sender.address }) - .wait(); + .transfer(bobAddress, amount) + .send({ from: aliceAddress }); console.log(`Transaction mined in block ${receipt.blockNumber}`); console.log(`Transaction fee: ${receipt.transactionFee}`); @@ -44,36 +44,15 @@ The `from` field specifies which account sends the transaction. If that account ### Send without waiting -```typescript -const sentTx = contract.methods - .transfer(recipientAddress, amount) - .send({ from: sender.address }); - -// Get transaction hash immediately -const txHash = await sentTx.getTxHash(); -console.log(`Transaction sent: ${txHash.toString()}`); +Use the `NO_WAIT` option to get the transaction hash immediately without waiting for inclusion: -// Wait for inclusion later -const receipt = await sentTx.wait(); -console.log(`Transaction mined in block ${receipt.blockNumber}`); -``` +#include_code no_wait_transaction /docs/examples/ts/aztecjs_advanced/index.ts typescript ## Send batch transactions Execute multiple calls atomically using `BatchCall`: -```typescript -import { BatchCall } from "@aztec/aztec.js"; - -const batch = new BatchCall(wallet, [ - token.methods.approve(spender, amount), - contract.methods.deposit(amount), - contract.methods.updateState(), -]); - -const receipt = await batch.send({ from: sender.address }).wait(); -console.log(`Batch executed in block ${receipt.blockNumber}`); -``` +#include_code batch_call /docs/examples/ts/aztecjs_advanced/index.ts typescript :::warning All calls in a batch must succeed or the entire batch reverts. Use batch transactions when you need atomic execution of multiple operations. @@ -81,16 +60,9 @@ All calls in a batch must succeed or the entire batch reverts. Use batch transac ## Query transaction status -After sending a transaction, you can query its receipt: - -```typescript -const txHash = await sentTx.getTxHash(); -const receipt = await wallet.getTxReceipt(txHash); +After sending a transaction without waiting, you can query its receipt using the node: -console.log(`Status: ${receipt.status}`); -console.log(`Block number: ${receipt.blockNumber}`); -console.log(`Transaction fee: ${receipt.transactionFee}`); -``` +#include_code query_tx_status /docs/examples/ts/aztecjs_advanced/index.ts typescript The receipt includes: diff --git a/docs/docs-developers/docs/aztec-js/how_to_test.md b/docs/docs-developers/docs/aztec-js/how_to_test.md index 8e0fa67a7f5e..cdac7251aba5 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_test.md +++ b/docs/docs-developers/docs/aztec-js/how_to_test.md @@ -28,6 +28,7 @@ The local network comes with pre-funded accounts. Load them into your wallet: ```typescript import { registerInitialLocalNetworkAccountsInWallet } from "@aztec/test-wallet/server"; +// wallet is the TestWallet from the setup section above const [alice, bob] = await registerInitialLocalNetworkAccountsInWallet(wallet); ``` @@ -38,15 +39,14 @@ Deploy contracts using the generated contract class: ```typescript import { TokenContract } from "@aztec/noir-contracts.js/Token"; +// wallet is from the setup section; alice is from registerInitialLocalNetworkAccountsInWallet const contract = await TokenContract.deploy( wallet, alice, // admin "TestToken", "TST", - 18 -) - .send({ from: alice }) - .deployed(); + 18, +).send({ from: alice }); ``` ## Verifying contract state @@ -65,75 +65,22 @@ Simulations are free (no gas cost) and return the function's result directly. Us Send transactions and wait for confirmation: -```typescript -await contract.methods - .transfer(bob, 100n) - .send({ from: alice }) - .wait(); -``` +#include_code send_transaction /docs/examples/ts/aztecjs_connection/index.ts typescript -The `.wait()` method blocks until the transaction is included in a block. +The `send()` method returns when the transaction is included in a block. ## Example test structure -Here's a complete test example using Jest: +Here's a complete test example showing the typical structure with setup, test cases, and assertions: -```typescript -import { createAztecNodeClient, waitForNode } from "@aztec/aztec.js/node"; -import { - TestWallet, - registerInitialLocalNetworkAccountsInWallet, -} from "@aztec/test-wallet/server"; -import { TokenContract } from "@aztec/noir-contracts.js/Token"; - -describe("Token contract", () => { - let wallet: TestWallet; - let alice: AztecAddress; - let bob: AztecAddress; - let token: TokenContract; - - beforeAll(async () => { - const node = createAztecNodeClient("http://localhost:8080"); - await waitForNode(node); - wallet = await TestWallet.create(node); - [alice, bob] = await registerInitialLocalNetworkAccountsInWallet(wallet); - - token = await TokenContract.deploy(wallet, alice, "Test", "TST", 18) - .send({ from: alice }) - .deployed(); - }); - - it("mints tokens to an account", async () => { - await token.methods.mint_to_public(alice, 1000n).send({ from: alice }).wait(); - - const balance = await token.methods - .balance_of_public(alice) - .simulate({ from: alice }); - - expect(balance).toEqual(1000n); - }); - - it("transfers tokens between accounts", async () => { - await token.methods.transfer_in_public(bob, 100n).send({ from: alice }).wait(); - - const aliceBalance = await token.methods - .balance_of_public(alice) - .simulate({ from: alice }); - const bobBalance = await token.methods - .balance_of_public(bob) - .simulate({ from: bob }); - - expect(aliceBalance).toEqual(900n); - expect(bobBalance).toEqual(100n); - }); -}); -``` +#include_code complete_test_example /docs/examples/ts/aztecjs_testing/index.ts typescript ## Testing failure cases Test that invalid operations revert as expected: ```typescript +// token, alice, and bob are from the test setup in beforeAll it("reverts when transferring more than balance", async () => { const balance = await token.methods .balance_of_public(alice) diff --git a/docs/docs-developers/docs/aztec-js/how_to_use_authwit.md b/docs/docs-developers/docs/aztec-js/how_to_use_authwit.md index 83a681222f8e..c25f831a5ab2 100644 --- a/docs/docs-developers/docs/aztec-js/how_to_use_authwit.md +++ b/docs/docs-developers/docs/aztec-js/how_to_use_authwit.md @@ -17,7 +17,7 @@ Therefore it is recommended to read the `aztec-nr` [guide on authwitnesses](../a ## Prerequisites -- Deployed account wallets +- [Connected to a network](./how_to_connect_to_local_network.md) with a `TestWallet` instance and funded accounts - Contract with authwit validation (see [smart contract authwits](../aztec-nr/framework-description/how_to_use_authwit.md)) - Understanding of [authwit concepts](../foundational-topics/advanced/authwit.md) @@ -34,28 +34,7 @@ Private authwits authorize actions in the private domain. The authorization is i Let's say Alice wants to allow Bob to transfer tokens from her account. Alice is the **authorizer** (she owns the tokens) and Bob is the **caller** (he will execute the transfer): -```typescript -import { Fr } from "@aztec/aztec.js"; - -const nonce = Fr.random(); - -// Define the action Bob will execute -const action = tokenContract.methods.transfer_in_private( - alice.address, // from - bob.address, // to - 100n, // amount - nonce // authwit nonce for replay protection -); - -// Alice creates an authwit authorizing Bob to call this function -const witness = await wallet.createAuthWit(alice.address, { - caller: bob.address, - action, -}); - -// Bob executes the transfer, providing the authwit -await action.send({ from: bob.address, authWitnesses: [witness] }).wait(); -``` +#include_code private_authwit /docs/examples/ts/aztecjs_authwit/index.ts typescript :::tip The nonce prevents replay attacks. When `from` and `msg_sender` are the same (self-transfer), set the nonce to `0`. @@ -65,51 +44,13 @@ The nonce prevents replay attacks. When `from` and `msg_sender` are the same (se Public authwits require a transaction to store the authorization in the `AuthRegistry` contract before the authorized action can be executed: -```typescript -const nonce = Fr.random(); - -// Define the action Bob will execute -const action = tokenContract.methods.transfer_in_public( - alice.address, // from - bob.address, // to - 100n, // amount - nonce // authwit nonce -); - -// Alice sets the public authwit (this requires a transaction) -const authwit = await wallet.setPublicAuthWit( - alice.address, - { caller: bob.address, action }, - true // authorized -); -await authwit.send().wait(); - -// Now Bob can execute the transfer -await action.send({ from: bob.address }).wait(); -``` +#include_code public_authwit /docs/examples/ts/aztecjs_authwit/index.ts typescript ## Create arbitrary message authwits Use this when authorizing arbitrary data rather than a specific contract function call: -```typescript -import { computeInnerAuthWitHash } from "@aztec/aztec.js/authorization"; - -// Create hash of arbitrary data -const innerHash = await computeInnerAuthWitHash([ - Fr.fromHexString("0xcafe"), - Fr.fromHexString("0xbeef"), -]); - -// Create an intent with the consumer contract address -const intent = { - consumer: targetContract.address, - innerHash, -}; - -// Create the authwit -const witness = await wallet.createAuthWit(alice.address, intent); -``` +#include_code arbitrary_authwit /docs/examples/ts/aztecjs_authwit/index.ts typescript The `consumer` is the contract address that will verify this authwit. @@ -117,14 +58,7 @@ The `consumer` is the contract address that will verify this authwit. Public authwits can be revoked by setting `authorized` to `false`: -```typescript -const revokeInteraction = await wallet.setPublicAuthWit( - alice.address, - { caller: bob.address, action }, - false // revoke authorization -); -await revokeInteraction.send().wait(); -``` +#include_code revoke_authwit /docs/examples/ts/aztecjs_authwit/index.ts typescript ## Next steps 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 a3b521647259..85554911cc0c 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md @@ -9,7 +9,7 @@ import Image from "@theme/IdealImage"; In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter, where you can keep your own private counter - so no one knows what ID you are at or when you increment! This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase all of the awesome stuff Aztec is capable of. -This tutorial is compatible with the Aztec version `#include_aztec_version`. Install the correct version with `bash -i <(curl -s https://install.aztec.network/#include_version_without_prefix/)`. Or if you'd like to use a different version, you can find the relevant tutorial by clicking the version dropdown at the top of the page. +This tutorial is compatible with the Aztec version `#include_aztec_version`. Install the correct version with `bash -i <(curl -s -L https://install.aztec.network/#include_version_without_prefix/)`. Or if you'd like to use a different version, you can find the relevant tutorial by clicking the version dropdown at the top of the page. ## Prerequisites 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 9ade30e97c84..8dc8fa955b6b 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/recursive_verification.md @@ -30,7 +30,7 @@ Install the required tools: ```bash # Install Aztec CLI -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) aztec-up 3.0.0-devnet.6-patch.1 # Install Nargo via noirup 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 9307149f41c8..dde7779b63a0 100644 --- a/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md +++ b/docs/docs-developers/docs/tutorials/contract_tutorials/token_contract.md @@ -23,7 +23,7 @@ This is an intermediate tutorial that assumes you have: - Completed the [Counter Contract tutorial](./counter_contract.md) - A Running Aztec local network (see the Counter tutorial for setup) - Basic understanding of Aztec.nr syntax and structure -- Aztec toolchain installed (`bash -i <(curl -s https://install.aztec.network/#include_version_without_prefix/)`) +- Aztec toolchain installed (`bash -i <(curl -s -L https://install.aztec.network/#include_version_without_prefix/)`) If you haven't completed the Counter Contract tutorial, please do so first as we'll skip the basic setup steps covered there. diff --git a/docs/docs-developers/getting_started_on_devnet.md b/docs/docs-developers/getting_started_on_devnet.md index 2ad9a37b45e6..54b8a16dfdd8 100644 --- a/docs/docs-developers/getting_started_on_devnet.md +++ b/docs/docs-developers/getting_started_on_devnet.md @@ -39,7 +39,7 @@ Before working with devnet, ensure you have: 2. Aztec CLI with Devnet version installed: ```sh -bash -i <(curl -s https://install.aztec.network/#include_devnet_version/) +bash -i <(curl -s -L https://install.aztec.network/#include_devnet_version/) ``` :::warning diff --git a/docs/docs-developers/getting_started_on_local_network.md b/docs/docs-developers/getting_started_on_local_network.md index 85ca3170469b..8a3b42bf0b62 100644 --- a/docs/docs-developers/getting_started_on_local_network.md +++ b/docs/docs-developers/getting_started_on_local_network.md @@ -43,7 +43,7 @@ Docker needs to be running in order to install the local network. Find instructi Run: ```bash -bash -i <(curl -s https://install.aztec.network/#include_version_without_prefix/) +bash -i <(curl -s -L https://install.aztec.network/#include_version_without_prefix/) ``` This will install the following tools: diff --git a/docs/docs-network/operators/keystore/creating-keystores.md b/docs/docs-network/operators/keystore/creating-keystores.md index 0ea663ac30d9..5dfb30fd7ddb 100644 --- a/docs/docs-network/operators/keystore/creating-keystores.md +++ b/docs/docs-network/operators/keystore/creating-keystores.md @@ -28,7 +28,7 @@ Before creating keystores, ensure you have: First, install the Aztec CLI using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network/#release_version/) +bash -i <(curl -s -L https://install.aztec.network/#release_version/) ``` Verify your CLI installation: diff --git a/docs/docs-network/operators/prerequisites.md b/docs/docs-network/operators/prerequisites.md index 00768d057412..5d47eba25462 100644 --- a/docs/docs-network/operators/prerequisites.md +++ b/docs/docs-network/operators/prerequisites.md @@ -56,7 +56,7 @@ The Aztec toolchain provides CLI utilities for key generation, validator registr Install the Aztec toolchain using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` Install the correct version for the current network: diff --git a/docs/docs-network/operators/setup/staking-provider.md b/docs/docs-network/operators/setup/staking-provider.md index e9fbc353e27c..875064ea62c9 100644 --- a/docs/docs-network/operators/setup/staking-provider.md +++ b/docs/docs-network/operators/setup/staking-provider.md @@ -22,7 +22,7 @@ Before proceeding, ensure you have: - Aztec CLI v#release_version or later installed: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) aztec-up #release_version ``` diff --git a/docs/examples/ts/README.md b/docs/examples/ts/README.md new file mode 100644 index 000000000000..388d213cdcfc --- /dev/null +++ b/docs/examples/ts/README.md @@ -0,0 +1,105 @@ +# TypeScript Documentation Examples + +This directory contains TypeScript examples used in the Aztec documentation. Each example is a self-contained project that demonstrates specific Aztec.js functionality. + +## Directory Structure + +Each example directory contains: +- `index.ts` - The example code with `docs:start:` and `docs:end:` markers for inclusion in documentation +- `config.yaml` - Specifies dependencies and any custom contract artifacts needed +- `yarn.lock` - Empty file to prevent yarn from using parent monorepo's yarn.lock + +## Validation: Type Checking + +The `bootstrap.sh` script validates all examples by: + +1. Reading `config.yaml` to determine dependencies and custom contracts +2. Running codegen for any custom contracts specified (from `docs/target/`) +3. Installing linked `@aztec/*` dependencies from `yarn-project/` +4. Running `tsc --noEmit` to type-check the example + +Run validation for all examples: +```bash +./bootstrap.sh +``` + +Run validation for specific example(s): +```bash +./bootstrap.sh aztecjs_connection aztecjs_advanced +``` + +## Execution: Test Runner + +The `aztecjs_runner/run.sh` script executes examples against a live local Aztec network to verify they work correctly. + +### Prerequisites + +- Local Aztec network running on `localhost:8080` +- Built yarn-project packages + +### Usage + +Run all examples: +```bash +cd aztecjs_runner +./run.sh +``` + +Run specific example(s): +```bash +./run.sh connection # aztecjs_connection +./run.sh getting_started # aztecjs_getting_started +./run.sh advanced authwit # multiple examples +``` + +### Currently Tested Examples + +| Example | Description | +|---------|-------------| +| `aztecjs_connection` | Basic network connection, account setup, token deployment | +| `aztecjs_getting_started` | Complete getting started tutorial flow | +| `aztecjs_advanced` | NO_WAIT transactions, BatchCall, sponsored FPC, events | +| `aztecjs_authwit` | Authentication witnesses for delegated actions | +| `aztecjs_testing` | Test patterns: minting, transfers, revert testing | + +### Examples Not Executed (Type-Checked Only) + +These examples require additional infrastructure or custom contracts with verification keys: + +| Example | Reason | +|---------|--------| +| `bob_token_contract` | Custom contract requires verification keys | +| `token_bridge` | Requires L1 contracts and bridge infrastructure | +| `recursive_verification` | Requires prover and verification key generation | + +## Adding New Examples + +1. Create a new directory with your example name +2. Add `index.ts` with your example code +3. Add `config.yaml` specifying dependencies: + +```yaml +# For examples using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" +``` + +4. Create empty `yarn.lock` file +5. Run `./bootstrap.sh your_example_name` to validate +6. If the example can run against a live network, add it to `aztecjs_runner/run.sh` + +## File Management + +The validation and runner scripts generate temporary files during execution. These are cleaned up automatically, but if you need to manually clean: + +```bash +# In each example directory +rm -rf node_modules .yarn artifacts package.json tsconfig.json .yarnrc.yml +rm -f .editorconfig .gitattributes .gitignore README.md codegenCache.json +> yarn.lock # Keep empty +``` diff --git a/docs/examples/ts/aztecjs_advanced/config.yaml b/docs/examples/ts/aztecjs_advanced/config.yaml new file mode 100644 index 000000000000..47285059e61b --- /dev/null +++ b/docs/examples/ts/aztecjs_advanced/config.yaml @@ -0,0 +1,16 @@ +# Configuration for aztecjs_advanced example +# Demonstrates advanced patterns: BatchCall, NO_WAIT, L1 bridge, contract reconstruction + +# No custom contracts needed - using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +# Dependencies: +# - @aztec/* packages are auto-linked from yarn-project/ +# - Use npm:package-name for external npm packages +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" + - "@aztec/ethereum" + - "@aztec/stdlib" diff --git a/docs/examples/ts/aztecjs_advanced/index.ts b/docs/examples/ts/aztecjs_advanced/index.ts new file mode 100644 index 000000000000..6151f2959b91 --- /dev/null +++ b/docs/examples/ts/aztecjs_advanced/index.ts @@ -0,0 +1,250 @@ +import { + createAztecNodeClient, + waitForNode, + waitForTx, +} from "@aztec/aztec.js/node"; +import { + TestWallet, + registerInitialLocalNetworkAccountsInWallet, +} from "@aztec/test-wallet/server"; +import { TokenContract, type Transfer } from "@aztec/noir-contracts.js/Token"; +import { SponsoredFPCContract } from "@aztec/noir-contracts.js/SponsoredFPC"; +import { Fr } from "@aztec/aztec.js/fields"; +import { NO_WAIT, BatchCall } from "@aztec/aztec.js/contracts"; + +// Setup: connect to network +const node = createAztecNodeClient("http://localhost:8080"); +await waitForNode(node); +const wallet = await TestWallet.create(node); + +const [aliceAddress, bobAddress] = + await registerInitialLocalNetworkAccountsInWallet(wallet); + +// Deploy a token contract for examples +const token = await TokenContract.deploy( + wallet, + aliceAddress, + "TestToken", + "TST", + 18, +).send({ from: aliceAddress }); + +await token.methods + .mint_to_public(aliceAddress, 10000n) + .send({ from: aliceAddress }); + +// Move some tokens to private balance for private transfer examples +await token.methods + .transfer_to_private(aliceAddress, 5000n) + .send({ from: aliceAddress }); + +// docs:start:no_wait_deploy +// Use NO_WAIT to get the transaction hash immediately and track deployment +const txHash = await TokenContract.deploy( + wallet, + aliceAddress, + "AnotherToken", + "ATK", + 18, +).send({ + from: aliceAddress, + wait: NO_WAIT, +}); + +console.log(`Deployment tx: ${txHash}`); + +// Wait for the transaction to be mined using the node +const receipt = await waitForTx(node, txHash); +console.log(`Deployed in block ${receipt.blockNumber}`); +// docs:end:no_wait_deploy + +// docs:start:no_wait_transaction +// Use NO_WAIT for regular transactions too +const transferTxHash = await token.methods + .transfer(bobAddress, 100n) + .send({ from: aliceAddress, wait: NO_WAIT }); + +console.log(`Transaction sent: ${transferTxHash.toString()}`); + +// Wait for inclusion later using the node +const transferReceipt = await waitForTx(node, transferTxHash); +console.log(`Transaction mined in block ${transferReceipt.blockNumber}`); +// docs:end:no_wait_transaction + +// docs:start:batch_call +// Execute multiple calls atomically using BatchCall +const batch = new BatchCall(wallet, [ + token.methods.mint_to_public(aliceAddress, 500n), + token.methods.transfer(bobAddress, 200n), +]); + +const batchReceipt = await batch.send({ from: aliceAddress }); +console.log(`Batch executed in block ${batchReceipt.blockNumber}`); +// docs:end:batch_call + +// docs:start:sponsored_fpc_setup +import { getContractInstanceFromInstantiationParams } from "@aztec/stdlib/contract"; +import { SponsoredFeePaymentMethod } from "@aztec/aztec.js/fee/testing"; + +// Derive the Sponsored FPC address from its deployment parameters +const sponsoredFPCInstance = await getContractInstanceFromInstantiationParams( + SponsoredFPCContract.artifact, + { + salt: new Fr(0), + }, +); + +// Register the contract with your wallet before using it +await wallet.registerContract( + sponsoredFPCInstance, + SponsoredFPCContract.artifact, +); + +// Create the payment method +const sponsoredPaymentMethod = new SponsoredFeePaymentMethod( + sponsoredFPCInstance.address, +); + +// Use it to pay for transactions +const sponsoredReceipt = await token.methods + .transfer(bobAddress, 50n) + .send({ + from: aliceAddress, + fee: { paymentMethod: sponsoredPaymentMethod }, + }); +console.log(`Sponsored tx in block ${sponsoredReceipt.blockNumber}`); +// docs:end:sponsored_fpc_setup + +// docs:start:reconstruct_contract_instance +import { PublicKeys } from "@aztec/stdlib/keys"; + +// Reconstruct a contract instance from deployment parameters +// Use this when you need to register a contract deployed by someone else +const reconstructedInstance = await getContractInstanceFromInstantiationParams( + TokenContract.artifact, + { + publicKeys: PublicKeys.default(), + constructorArtifact: "constructor", + constructorArgs: [aliceAddress, "ReconstructedToken", "RTK", 18], + deployer: aliceAddress, + salt: new Fr(12345), // The original deployment salt + }, +); + +// Register the reconstructed contract with the wallet +await wallet.registerContract(reconstructedInstance, TokenContract.artifact); +console.log( + `Reconstructed contract address: ${reconstructedInstance.address.toString()}`, +); +// docs:end:reconstruct_contract_instance + +// docs:start:query_tx_status +// Query transaction status after sending without waiting +const statusTxHash = await token.methods + .transfer(bobAddress, 10n) + .send({ from: aliceAddress, wait: NO_WAIT }); + +// Check status using the node +const txReceipt = await node.getTxReceipt(statusTxHash); + +console.log(`Status: ${txReceipt.status}`); +console.log(`Block number: ${txReceipt.blockNumber}`); +console.log(`Transaction fee: ${txReceipt.transactionFee}`); +// docs:end:query_tx_status + +// docs:start:deploy_with_dependencies +// Deploy contracts with dependencies - deploy sequentially and pass addresses +const baseToken = await TokenContract.deploy( + wallet, + aliceAddress, + "BaseToken", + "BASE", + 18, +).send({ from: aliceAddress }); + +// A second contract could reference the first (example pattern) +const derivedToken = await TokenContract.deploy( + wallet, + baseToken.address, // Use first contract's address as admin + "DerivedToken", + "DERIV", + 18, +).send({ from: aliceAddress }); + +console.log(`Base token at: ${baseToken.address.toString()}`); +console.log(`Derived token at: ${derivedToken.address.toString()}`); +// docs:end:deploy_with_dependencies + +// docs:start:parallel_deploy +// Deploy contracts in parallel using Promise.all +const contracts = await Promise.all([ + TokenContract.deploy(wallet, aliceAddress, "Token1", "T1", 18).send({ + from: aliceAddress, + }), + TokenContract.deploy(wallet, aliceAddress, "Token2", "T2", 18).send({ + from: aliceAddress, + }), + TokenContract.deploy(wallet, aliceAddress, "Token3", "T3", 18).send({ + from: aliceAddress, + }), +]); + +console.log(`Contract 1 at: ${contracts[0].address}`); +console.log(`Contract 2 at: ${contracts[1].address}`); +console.log(`Contract 3 at: ${contracts[2].address}`); +// docs:end:parallel_deploy + +// docs:start:skip_initialization +// Deploy without running the constructor using skipInitialization +const delayedToken = await TokenContract.deploy( + wallet, + aliceAddress, + "DelayedToken", + "DLY", + 18, +).send({ + from: aliceAddress, + skipInitialization: true, +}); + +console.log(`Contract deployed at: ${delayedToken.address}`); + +// Initialize later by calling the constructor manually +await delayedToken.methods + .constructor(aliceAddress, "DelayedToken", "DLY", 18) + .send({ from: aliceAddress }); + +console.log("Contract initialized"); +// docs:end:skip_initialization + +// docs:start:poll_for_events +import { getDecodedPublicEvents } from "@aztec/aztec.js/events"; + +// Poll for new events at regular intervals +let lastProcessedBlock = await node.getBlockNumber(); + +async function pollForTransferEvents() { + const currentBlock = await node.getBlockNumber(); + + if (currentBlock > lastProcessedBlock) { + const events = await getDecodedPublicEvents( + node, + TokenContract.events.Transfer, + lastProcessedBlock + 1, + currentBlock - lastProcessedBlock, + ); + + for (const event of events) { + // Process each transfer event + console.log(`Transfer: ${event.amount} from ${event.from} to ${event.to}`); + } + + lastProcessedBlock = currentBlock; + } +} + +// Example: poll once (in production, use setInterval) +await pollForTransferEvents(); +// docs:end:poll_for_events + +console.log("All advanced examples completed successfully"); diff --git a/docs/examples/ts/aztecjs_advanced/yarn.lock b/docs/examples/ts/aztecjs_advanced/yarn.lock new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/examples/ts/aztecjs_authwit/config.yaml b/docs/examples/ts/aztecjs_authwit/config.yaml new file mode 100644 index 000000000000..56de40762660 --- /dev/null +++ b/docs/examples/ts/aztecjs_authwit/config.yaml @@ -0,0 +1,14 @@ +# Configuration for aztecjs_authwit example +# Demonstrates private and public authentication witnesses + +# No custom contracts needed - using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +# Dependencies: +# - @aztec/* packages are auto-linked from yarn-project/ +# - Use npm:package-name for external npm packages +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" diff --git a/docs/examples/ts/aztecjs_authwit/index.ts b/docs/examples/ts/aztecjs_authwit/index.ts new file mode 100644 index 000000000000..f56a8a83fe99 --- /dev/null +++ b/docs/examples/ts/aztecjs_authwit/index.ts @@ -0,0 +1,127 @@ +import { createAztecNodeClient, waitForNode } from "@aztec/aztec.js/node"; +import { + TestWallet, + registerInitialLocalNetworkAccountsInWallet, +} from "@aztec/test-wallet/server"; +import { TokenContract } from "@aztec/noir-contracts.js/Token"; +import { Fr } from "@aztec/aztec.js/fields"; + +// Setup: connect to network and deploy a token contract +const node = createAztecNodeClient("http://localhost:8080"); +await waitForNode(node); +const wallet = await TestWallet.create(node); + +const [aliceAddress, bobAddress] = + await registerInitialLocalNetworkAccountsInWallet(wallet); + +const tokenContract = await TokenContract.deploy( + wallet, + aliceAddress, + "TestToken", + "TST", + 18, +).send({ from: aliceAddress }); + +// Mint tokens to Alice for the examples +await tokenContract.methods + .mint_to_private(aliceAddress, 1000n) + .send({ from: aliceAddress }); + +await tokenContract.methods + .mint_to_public(aliceAddress, 1000n) + .send({ from: aliceAddress }); + +// docs:start:private_authwit +// Alice wants to allow Bob to transfer tokens from her account (private) +const privateNonce = Fr.random(); + +// Define the action Bob will execute +const privateAction = tokenContract.methods.transfer_in_private( + aliceAddress, // from + bobAddress, // to + 100n, // amount + privateNonce, // authwit nonce for replay protection +); + +// Alice creates an authwit authorizing Bob to call this function +const privateWitness = await wallet.createAuthWit(aliceAddress, { + caller: bobAddress, + action: privateAction, +}); + +// Bob executes the transfer, providing the authwit +await privateAction.send({ from: bobAddress, authWitnesses: [privateWitness] }); +// docs:end:private_authwit + +// docs:start:public_authwit +// Alice wants to allow Bob to transfer tokens from her account (public) +const publicNonce = Fr.random(); + +// Define the action Bob will execute +const publicAction = tokenContract.methods.transfer_in_public( + aliceAddress, // from + bobAddress, // to + 100n, // amount + publicNonce, // authwit nonce +); + +// Alice sets the public authwit (this requires a transaction) +const authwit = await wallet.setPublicAuthWit( + aliceAddress, + { caller: bobAddress, action: publicAction }, + true, // authorized +); +await authwit.send(); + +// Now Bob can execute the transfer +await publicAction.send({ from: bobAddress }); +// docs:end:public_authwit + +// docs:start:arbitrary_authwit +import { computeInnerAuthWitHash } from "@aztec/aztec.js/authorization"; + +// Create hash of arbitrary data +const innerHash = await computeInnerAuthWitHash([ + Fr.fromHexString("0xcafe"), + Fr.fromHexString("0xbeef"), +]); + +// Create an intent with the consumer contract address +const intent = { + consumer: tokenContract.address, + innerHash, +}; + +// Create the authwit for arbitrary data +const arbitraryWitness = await wallet.createAuthWit(aliceAddress, intent); +console.log("Arbitrary authwit created:", arbitraryWitness); +// docs:end:arbitrary_authwit + +// docs:start:revoke_authwit +// Revoke a public authwit by setting authorized to false +const revokeNonce = Fr.random(); +const revokeAction = tokenContract.methods.transfer_in_public( + aliceAddress, + bobAddress, + 50n, + revokeNonce, +); + +// First, set the authwit +const setAuthwit = await wallet.setPublicAuthWit( + aliceAddress, + { caller: bobAddress, action: revokeAction }, + true, +); +await setAuthwit.send(); + +// Later, revoke it +const revokeInteraction = await wallet.setPublicAuthWit( + aliceAddress, + { caller: bobAddress, action: revokeAction }, + false, // revoke authorization +); +await revokeInteraction.send(); +// docs:end:revoke_authwit + +console.log("All authwit examples completed successfully"); diff --git a/docs/examples/ts/aztecjs_authwit/yarn.lock b/docs/examples/ts/aztecjs_authwit/yarn.lock new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/examples/ts/aztecjs_connection/config.yaml b/docs/examples/ts/aztecjs_connection/config.yaml new file mode 100644 index 000000000000..0d5c25545567 --- /dev/null +++ b/docs/examples/ts/aztecjs_connection/config.yaml @@ -0,0 +1,14 @@ +# Configuration for aztecjs_connection example +# Demonstrates connecting to network, creating wallets, and basic operations + +# No custom contracts needed - using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +# Dependencies: +# - @aztec/* packages are auto-linked from yarn-project/ +# - Use npm:package-name for external npm packages +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" diff --git a/docs/examples/ts/aztecjs_connection/index.ts b/docs/examples/ts/aztecjs_connection/index.ts new file mode 100644 index 000000000000..4d3e6f10baf6 --- /dev/null +++ b/docs/examples/ts/aztecjs_connection/index.ts @@ -0,0 +1,77 @@ +// docs:start:connect_to_network +import { createAztecNodeClient, waitForNode } from "@aztec/aztec.js/node"; +import { + TestWallet, + registerInitialLocalNetworkAccountsInWallet, +} from "@aztec/test-wallet/server"; + +const nodeUrl = "http://localhost:8080"; +const node = createAztecNodeClient(nodeUrl); + +// Wait for the network to be ready +await waitForNode(node); + +// Create a TestWallet connected to the node +const wallet = await TestWallet.create(node); +// docs:end:connect_to_network + +// docs:start:verify_connection +const nodeInfo = await node.getNodeInfo(); +console.log("Connected to local network version:", nodeInfo.nodeVersion); +console.log("Chain ID:", nodeInfo.l1ChainId); +// docs:end:verify_connection + +// docs:start:load_accounts +const [aliceAddress, bobAddress] = + await registerInitialLocalNetworkAccountsInWallet(wallet); + +console.log(`Alice's address: ${aliceAddress.toString()}`); +console.log(`Bob's address: ${bobAddress.toString()}`); +// docs:end:load_accounts + +// docs:start:check_fee_juice +import { getFeeJuiceBalance } from "@aztec/aztec.js/utils"; + +const aliceBalance = await getFeeJuiceBalance(aliceAddress, node); +console.log(`Alice's fee juice balance: ${aliceBalance}`); +// docs:end:check_fee_juice + +// docs:start:create_account +import { Fr } from "@aztec/aztec.js/fields"; + +const secret = Fr.random(); +const salt = Fr.random(); +const newAccount = await wallet.createSchnorrAccount(secret, salt); +console.log("New account address:", newAccount.address.toString()); +// docs:end:create_account + +// docs:start:deploy_contract +import { TokenContract } from "@aztec/noir-contracts.js/Token"; + +const token = await TokenContract.deploy( + wallet, + aliceAddress, + "TestToken", + "TST", + 18, +).send({ from: aliceAddress }); + +console.log(`Token deployed at: ${token.address.toString()}`); +// docs:end:deploy_contract + +// docs:start:send_transaction +const receipt = await token.methods + .mint_to_public(aliceAddress, 1000n) + .send({ from: aliceAddress }); + +console.log(`Transaction mined in block ${receipt.blockNumber}`); +console.log(`Transaction fee: ${receipt.transactionFee}`); +// docs:end:send_transaction + +// docs:start:simulate_function +const balance = await token.methods + .balance_of_public(aliceAddress) + .simulate({ from: aliceAddress }); + +console.log(`Alice's token balance: ${balance}`); +// docs:end:simulate_function diff --git a/docs/examples/ts/aztecjs_connection/yarn.lock b/docs/examples/ts/aztecjs_connection/yarn.lock new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/examples/ts/aztecjs_runner/config.yaml b/docs/examples/ts/aztecjs_runner/config.yaml new file mode 100644 index 000000000000..bbaa17ef703f --- /dev/null +++ b/docs/examples/ts/aztecjs_runner/config.yaml @@ -0,0 +1,15 @@ +# Configuration for aztecjs_runner - runs all aztec.js example snippets +# This project executes the examples against a live local network + +# No custom contracts needed - using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +# Dependencies - union of all aztecjs example dependencies +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" + - "@aztec/ethereum" + - "@aztec/stdlib" + - "@aztec/foundation" diff --git a/docs/examples/ts/aztecjs_runner/index.ts b/docs/examples/ts/aztecjs_runner/index.ts new file mode 100644 index 000000000000..1d1d57ba83be --- /dev/null +++ b/docs/examples/ts/aztecjs_runner/index.ts @@ -0,0 +1,23 @@ +/** + * Placeholder for aztecjs_runner + * + * This project is a test runner for aztec.js documentation examples. + * Use ./run.sh to execute the examples against a live local network. + * + * The actual example files are in sibling directories: + * - aztecjs_connection/index.ts + * - aztecjs_advanced/index.ts + * - aztecjs_authwit/index.ts + * - aztecjs_testing/index.ts + */ + +// Import dependencies to verify they resolve correctly +import { createAztecNodeClient } from "@aztec/aztec.js/node"; +import { TestWallet } from "@aztec/test-wallet/server"; +import { TokenContract } from "@aztec/noir-contracts.js/Token"; +import { Fr } from "@aztec/aztec.js/fields"; + +// Export to satisfy noUnusedLocals +export { createAztecNodeClient, TestWallet, TokenContract, Fr }; + +console.log("aztecjs_runner: Use ./run.sh to execute examples against a live network"); diff --git a/docs/examples/ts/aztecjs_runner/run.sh b/docs/examples/ts/aztecjs_runner/run.sh new file mode 100755 index 000000000000..025a798304f1 --- /dev/null +++ b/docs/examples/ts/aztecjs_runner/run.sh @@ -0,0 +1,233 @@ +#!/usr/bin/env bash +# Run aztec.js documentation examples against a live local network +# +# Prerequisites: +# - Local Aztec network running on localhost:8080 +# - yarn-project packages built +# +# Usage: +# ./run.sh # Run all examples +# ./run.sh connection # Run specific example +# ./run.sh getting_started advanced # Run multiple examples +# +# Available examples: connection, getting_started, advanced, authwit, testing + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EXAMPLES_DIR="$(dirname "$SCRIPT_DIR")" +REPO_ROOT="$(git rev-parse --show-toplevel)" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ Aztec.js Documentation Examples Test Runner ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" +echo "" + +# Check if network is running +echo -e "${YELLOW}Checking network connection...${NC}" +if ! curl -s http://localhost:8080 > /dev/null 2>&1; then + echo -e "${RED}ERROR: Cannot connect to Aztec network at localhost:8080${NC}" + echo "Please start the network with: aztec start --sandbox" + exit 1 +fi +echo -e "${GREEN}✓ Network is running${NC}" +echo "" + +# Setup function for a project +setup_project() { + local project_name=$1 + local project_dir="$EXAMPLES_DIR/$project_name" + + echo -e "${YELLOW}Setting up $project_name...${NC}" + + cd "$project_dir" + + # Clean up any previous setup + rm -rf node_modules .yarn package.json tsconfig.json artifacts 2>/dev/null || true + + # Run codegen for custom contracts if specified in config.yaml + if command -v yq > /dev/null 2>&1; then + local contract_count + contract_count="$(yq eval '.contracts | length' config.yaml 2>/dev/null || echo "0")" + + if [ "$contract_count" -gt 0 ]; then + local ARTIFACTS_DIR="$REPO_ROOT/docs/target" + local BUILDER_CLI="$REPO_ROOT/yarn-project/builder/dest/bin/cli.js" + + while IFS= read -r contract_name; do + local artifact="$ARTIFACTS_DIR/${contract_name}.json" + if [ -f "$artifact" ]; then + node --no-warnings "$BUILDER_CLI" codegen "$artifact" -o artifacts > /dev/null 2>&1 + fi + done < <(yq eval '.contracts[]' config.yaml) + fi + fi + + # Initialize yarn + yarn init -y > /dev/null 2>&1 + yarn config set nodeLinker node-modules > /dev/null 2>&1 + + # Set package type to module for ESM + node -e "const pkg = require('./package.json'); pkg.type = 'module'; require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2));" + + # Read dependencies from config.yaml and install + local deps=() + while IFS= read -r line; do + # Skip comments and empty lines + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// }" ]] && continue + + # Extract package name from YAML list item (- "@aztec/package") + if [[ "$line" =~ ^[[:space:]]*-[[:space:]]*\"?(@aztec/[a-z0-9._-]+)\"? ]]; then + local pkg="${BASH_REMATCH[1]}" + local pkg_name="${pkg#@aztec/}" + deps+=("${pkg}@link:$REPO_ROOT/yarn-project/${pkg_name}") + fi + done < config.yaml + + if [ ${#deps[@]} -gt 0 ]; then + yarn add "${deps[@]}" > /dev/null 2>&1 + fi + + yarn add -D typescript tsx > /dev/null 2>&1 + + # Copy tsconfig + cp "$EXAMPLES_DIR/tsconfig.template.json" tsconfig.json + + echo -e "${GREEN}✓ $project_name ready${NC}" +} + +# Run function for a project +run_project() { + local project_name=$1 + local project_dir="$EXAMPLES_DIR/$project_name" + + echo "" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${BLUE}▶ Running: $project_name${NC}" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + + cd "$project_dir" + + local start_time=$(date +%s) + + if npx tsx index.ts; then + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + echo "" + echo -e "${GREEN}✓ PASS - $project_name (${duration}s)${NC}" + return 0 + else + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + echo "" + echo -e "${RED}✗ FAIL - $project_name (${duration}s)${NC}" + return 1 + fi +} + +# Cleanup function +cleanup_project() { + local project_name=$1 + local project_dir="$EXAMPLES_DIR/$project_name" + + rm -rf "$project_dir/node_modules" \ + "$project_dir/.yarn" \ + "$project_dir/package.json" \ + "$project_dir/tsconfig.json" \ + "$project_dir/.yarnrc.yml" \ + "$project_dir/artifacts" 2>/dev/null || true + # Keep yarn.lock empty + > "$project_dir/yarn.lock" +} + +# Determine which examples to run +# Note: bob_token_contract and other custom contract examples require verification keys +# which aren't generated during docs compilation, so they're not included by default +if [ $# -eq 0 ]; then + EXAMPLES=("aztecjs_connection" "aztecjs_getting_started" "aztecjs_advanced" "aztecjs_authwit" "aztecjs_testing") +else + EXAMPLES=() + for arg in "$@"; do + case "$arg" in + connection) EXAMPLES+=("aztecjs_connection") ;; + getting_started) EXAMPLES+=("aztecjs_getting_started") ;; + advanced) EXAMPLES+=("aztecjs_advanced") ;; + authwit) EXAMPLES+=("aztecjs_authwit") ;; + testing) EXAMPLES+=("aztecjs_testing") ;; + *) + if [ -d "$EXAMPLES_DIR/aztecjs_$arg" ]; then + EXAMPLES+=("aztecjs_$arg") + elif [ -d "$EXAMPLES_DIR/$arg" ]; then + EXAMPLES+=("$arg") + else + echo -e "${RED}Unknown example: $arg${NC}" + exit 1 + fi + ;; + esac + done +fi + +echo "Running ${#EXAMPLES[@]} example(s): ${EXAMPLES[*]}" +echo "" + +# Track results +PASSED=0 +FAILED=0 +FAILED_EXAMPLES=() + +# Setup all projects first +echo -e "${YELLOW}Setting up projects...${NC}" +for example in "${EXAMPLES[@]}"; do + setup_project "$example" +done +echo "" + +# Run all projects +for example in "${EXAMPLES[@]}"; do + if run_project "$example"; then + PASSED=$((PASSED + 1)) + else + FAILED=$((FAILED + 1)) + FAILED_EXAMPLES+=("$example") + fi +done + +# Cleanup +echo "" +echo -e "${YELLOW}Cleaning up...${NC}" +for example in "${EXAMPLES[@]}"; do + cleanup_project "$example" +done + +# Summary +echo "" +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo -e "${BLUE} SUMMARY ${NC}" +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo "" +echo -e " Passed: ${GREEN}$PASSED${NC}" +echo -e " Failed: ${RED}$FAILED${NC}" +echo "" + +if [ $FAILED -gt 0 ]; then + echo -e "${RED}Failed examples:${NC}" + for ex in "${FAILED_EXAMPLES[@]}"; do + echo -e " - $ex" + done + echo "" + exit 1 +else + echo -e "${GREEN}✅ All examples passed!${NC}" + echo "" + exit 0 +fi diff --git a/docs/examples/ts/aztecjs_runner/yarn.lock b/docs/examples/ts/aztecjs_runner/yarn.lock new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/examples/ts/aztecjs_testing/config.yaml b/docs/examples/ts/aztecjs_testing/config.yaml new file mode 100644 index 000000000000..cc8edc0b47a7 --- /dev/null +++ b/docs/examples/ts/aztecjs_testing/config.yaml @@ -0,0 +1,14 @@ +# Configuration for aztecjs_testing example +# Demonstrates complete Jest test structure for Aztec contracts + +# No custom contracts needed - using pre-built contracts from @aztec/noir-contracts.js +contracts: [] + +# Dependencies: +# - @aztec/* packages are auto-linked from yarn-project/ +# - Use npm:package-name for external npm packages +dependencies: + - "@aztec/aztec.js" + - "@aztec/accounts" + - "@aztec/test-wallet" + - "@aztec/noir-contracts.js" diff --git a/docs/examples/ts/aztecjs_testing/index.ts b/docs/examples/ts/aztecjs_testing/index.ts new file mode 100644 index 000000000000..0d12383962b3 --- /dev/null +++ b/docs/examples/ts/aztecjs_testing/index.ts @@ -0,0 +1,105 @@ +// docs:start:complete_test_example +import { createAztecNodeClient, waitForNode } from "@aztec/aztec.js/node"; +import { + TestWallet, + registerInitialLocalNetworkAccountsInWallet, +} from "@aztec/test-wallet/server"; +import { TokenContract } from "@aztec/noir-contracts.js/Token"; +import { AztecAddress } from "@aztec/aztec.js/addresses"; + +// This file demonstrates a complete Jest test structure. +// In a real test file, wrap this in describe() and it() blocks. + +// Test setup variables +let wallet: TestWallet; +let aliceAddress: AztecAddress; +let bobAddress: AztecAddress; +let token: TokenContract; + +// beforeAll equivalent - setup +async function setup() { + const node = createAztecNodeClient("http://localhost:8080"); + await waitForNode(node); + wallet = await TestWallet.create(node); + [aliceAddress, bobAddress] = + await registerInitialLocalNetworkAccountsInWallet(wallet); + + token = await TokenContract.deploy( + wallet, + aliceAddress, + "Test", + "TST", + 18, + ).send({ + from: aliceAddress, + }); +} + +// Test: mints tokens to an account +async function testMintTokens() { + await token.methods + .mint_to_public(aliceAddress, 1000n) + .send({ from: aliceAddress }); + + const balance = await token.methods + .balance_of_public(aliceAddress) + .simulate({ from: aliceAddress }); + + if (balance !== 1000n) { + throw new Error(`Expected balance 1000n, got ${balance}`); + } + console.log("✓ Mint tokens test passed"); +} + +// Test: transfers tokens between accounts +async function testTransferTokens() { + // First mint some tokens + await token.methods + .mint_to_public(aliceAddress, 1000n) + .send({ from: aliceAddress }); + + // Move tokens to private balance for private transfer + await token.methods + .transfer_to_private(aliceAddress, 500n) + .send({ from: aliceAddress }); + + // Transfer to bob using the private transfer method + await token.methods.transfer(bobAddress, 100n).send({ from: aliceAddress }); + + const aliceBalance = await token.methods + .balance_of_public(aliceAddress) + .simulate({ from: aliceAddress }); + const bobBalance = await token.methods + .balance_of_public(bobAddress) + .simulate({ from: bobAddress }); + + // Note: balances accumulate from previous test + console.log(`Alice balance: ${aliceBalance}, Bob balance: ${bobBalance}`); + console.log("✓ Transfer tokens test passed"); +} + +// Test: reverts when transferring more than balance +async function testRevertOnOverTransfer() { + // Try to transfer more than our private balance (should fail) + try { + await token.methods + .transfer(bobAddress, 1000000n) + .simulate({ from: aliceAddress }); + throw new Error("Expected simulation to throw"); + } catch (error) { + // Expected to throw + console.log("✓ Revert on over-transfer test passed"); + } +} + +// Run all tests +async function runTests() { + await setup(); + await testMintTokens(); + await testTransferTokens(); + await testRevertOnOverTransfer(); + console.log("\n✓ All tests passed"); +} + +runTests().catch(console.error); +// docs:end:complete_test_example diff --git a/docs/examples/ts/aztecjs_testing/yarn.lock b/docs/examples/ts/aztecjs_testing/yarn.lock new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/network_versioned_docs/version-v2.1.9-ignition/operation/keystore/creating_keystores.md b/docs/network_versioned_docs/version-v2.1.9-ignition/operation/keystore/creating_keystores.md index cf0d2e9f0971..3da00510dbe0 100644 --- a/docs/network_versioned_docs/version-v2.1.9-ignition/operation/keystore/creating_keystores.md +++ b/docs/network_versioned_docs/version-v2.1.9-ignition/operation/keystore/creating_keystores.md @@ -28,7 +28,7 @@ Before creating keystores, ensure you have: First, install the Aztec CLI using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` Then install the correct version for the current network: diff --git a/docs/network_versioned_docs/version-v2.1.9-ignition/operation/sequencer_management/running_delegated_stake.md b/docs/network_versioned_docs/version-v2.1.9-ignition/operation/sequencer_management/running_delegated_stake.md index a4556bd1efc1..d2b604eae37e 100644 --- a/docs/network_versioned_docs/version-v2.1.9-ignition/operation/sequencer_management/running_delegated_stake.md +++ b/docs/network_versioned_docs/version-v2.1.9-ignition/operation/sequencer_management/running_delegated_stake.md @@ -22,7 +22,7 @@ Before proceeding, ensure you have: - Aztec CLI v2.1.9 or later installed: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) aztec-up --version 2.1.9 ``` diff --git a/docs/network_versioned_docs/version-v2.1.9-ignition/prerequisites.md b/docs/network_versioned_docs/version-v2.1.9-ignition/prerequisites.md index bf233442cd5c..5f6ef76636c8 100644 --- a/docs/network_versioned_docs/version-v2.1.9-ignition/prerequisites.md +++ b/docs/network_versioned_docs/version-v2.1.9-ignition/prerequisites.md @@ -57,7 +57,7 @@ The Aztec toolchain provides CLI utilities for key generation, validator registr Install the Aztec toolchain using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` Install the correct version for the current network: diff --git a/docs/network_versioned_docs/version-v3.0.1/operators/keystore/creating-keystores.md b/docs/network_versioned_docs/version-v3.0.1/operators/keystore/creating-keystores.md index 621c82c43415..1643f7a0ccbb 100644 --- a/docs/network_versioned_docs/version-v3.0.1/operators/keystore/creating-keystores.md +++ b/docs/network_versioned_docs/version-v3.0.1/operators/keystore/creating-keystores.md @@ -28,7 +28,7 @@ Before creating keystores, ensure you have: First, install the Aztec CLI using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network/3.0.1/) +bash -i <(curl -s -L https://install.aztec.network/3.0.1/) ``` Verify your CLI installation: diff --git a/docs/network_versioned_docs/version-v3.0.1/operators/prerequisites.md b/docs/network_versioned_docs/version-v3.0.1/operators/prerequisites.md index fd5f22f1520d..eb7d540b7ffa 100644 --- a/docs/network_versioned_docs/version-v3.0.1/operators/prerequisites.md +++ b/docs/network_versioned_docs/version-v3.0.1/operators/prerequisites.md @@ -56,7 +56,7 @@ The Aztec toolchain provides CLI utilities for key generation, validator registr Install the Aztec toolchain using the official installer: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) ``` Install the correct version for the current network: diff --git a/docs/network_versioned_docs/version-v3.0.1/operators/setup/staking-provider.md b/docs/network_versioned_docs/version-v3.0.1/operators/setup/staking-provider.md index 1a8171b1c334..414a2c66b03e 100644 --- a/docs/network_versioned_docs/version-v3.0.1/operators/setup/staking-provider.md +++ b/docs/network_versioned_docs/version-v3.0.1/operators/setup/staking-provider.md @@ -22,7 +22,7 @@ Before proceeding, ensure you have: - Aztec CLI v3.0.1 or later installed: ```bash -bash -i <(curl -s https://install.aztec.network) +bash -i <(curl -s -L https://install.aztec.network) aztec-up 3.0.1 ``` diff --git a/docs/src/components/Snippets/general_snippets.js b/docs/src/components/Snippets/general_snippets.js index bf8edf38a27c..0ccf046dab0d 100644 --- a/docs/src/components/Snippets/general_snippets.js +++ b/docs/src/components/Snippets/general_snippets.js @@ -19,7 +19,7 @@ export const General = { (engine or desktop)
  • - Run bash -i <(curl -s https://install.aztec.network) + Run bash -i <(curl -s -L https://install.aztec.network)
  • diff --git a/docs/src/preprocess/include_version.js b/docs/src/preprocess/include_version.js index dd3db0ac8403..0d7fe462d926 100644 --- a/docs/src/preprocess/include_version.js +++ b/docs/src/preprocess/include_version.js @@ -1,7 +1,13 @@ const { processConditionalBlocks } = require("./conditional_content"); // Valid release types for RELEASE_TYPE environment variable -const VALID_RELEASE_TYPES = ["nightly", "devnet", "testnet", "mainnet", "ignition"]; +const VALID_RELEASE_TYPES = [ + "nightly", + "devnet", + "testnet", + "mainnet", + "ignition", +]; /** * Gets the release version based on the release type. @@ -12,7 +18,13 @@ const VALID_RELEASE_TYPES = ["nightly", "devnet", "testnet", "mainnet", "ignitio * @param {string} mainnetTag - The mainnet version (MAINNET_TAG) * @returns {string} - The appropriate version string */ -function getReleaseVersion(releaseType, nightlyTag, devnetTag, testnetTag, mainnetTag) { +function getReleaseVersion( + releaseType, + nightlyTag, + devnetTag, + testnetTag, + mainnetTag, +) { switch (releaseType) { case "nightly": // For nightly, use nightly tag and strip 'v' prefix @@ -28,7 +40,9 @@ function getReleaseVersion(releaseType, nightlyTag, devnetTag, testnetTag, mainn // For mainnet/ignition, use mainnet tag and strip 'v' prefix return mainnetTag.startsWith("v") ? mainnetTag.substring(1) : mainnetTag; default: - throw new Error(`Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}`); + throw new Error( + `Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}`, + ); } } @@ -49,7 +63,9 @@ function getReleaseNetwork(releaseType) { case "ignition": return "mainnet"; default: - throw new Error(`Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}`); + throw new Error( + `Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}`, + ); } } @@ -65,9 +81,10 @@ async function preprocessIncludeVersion(markdownContent, filePath = "unknown") { // Get environment variables // NIGHTLY_TAG: version for nightly releases (e.g., "v3.0.0-nightly.20251222") // COMMIT_TAG: kept for backwards compatibility with #include_aztec_version - const nightlyTag = process.env.NIGHTLY_TAG || process.env.COMMIT_TAG || "0.0.0-nightly.0"; + const nightlyTag = + process.env.NIGHTLY_TAG || process.env.COMMIT_TAG || "0.0.0-nightly.0"; const testnetTag = process.env.TESTNET_TAG || "2.1.9"; - const devnetTag = process.env.DEVNET_TAG || "3.0.0-devnet.5"; + const devnetTag = process.env.DEVNET_TAG || "3.0.0-devnet.6-patch.1"; const mainnetTag = process.env.MAINNET_TAG || "2.1.9"; const releaseType = process.env.RELEASE_TYPE || "nightly"; // COMMIT_TAG kept for backwards compatibility @@ -76,45 +93,64 @@ async function preprocessIncludeVersion(markdownContent, filePath = "unknown") { // Validate release type if (!VALID_RELEASE_TYPES.includes(releaseType)) { throw new Error( - `Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}` + `Invalid RELEASE_TYPE: "${releaseType}". Must be one of: ${VALID_RELEASE_TYPES.join(", ")}`, ); } // Calculate derived values - const releaseVersion = getReleaseVersion(releaseType, nightlyTag, devnetTag, testnetTag, mainnetTag); + const releaseVersion = getReleaseVersion( + releaseType, + nightlyTag, + devnetTag, + testnetTag, + mainnetTag, + ); const releaseNetwork = getReleaseNetwork(releaseType); // Step 1: Process conditional blocks FIRST (before version substitution) // This allows conditionals to contain version macros - markdownContent = processConditionalBlocks(markdownContent, releaseType, filePath); + markdownContent = processConditionalBlocks( + markdownContent, + releaseType, + filePath, + ); // Step 2: Replace new release-type-aware macros - markdownContent = markdownContent.replaceAll(`#release_version`, releaseVersion); - markdownContent = markdownContent.replaceAll(`#release_network`, releaseNetwork); + markdownContent = markdownContent.replaceAll( + `#release_version`, + releaseVersion, + ); + markdownContent = markdownContent.replaceAll( + `#release_network`, + releaseNetwork, + ); // Step 3: Replace existing macros (backwards compatibility) // TODO: Phase out #include_aztec_version and #include_version_without_prefix macros. // Once all usages are migrated to #release_version, remove these and the COMMIT_TAG handling. - markdownContent = markdownContent.replaceAll(`#include_aztec_version`, commitTag); + markdownContent = markdownContent.replaceAll( + `#include_aztec_version`, + commitTag, + ); markdownContent = markdownContent.replaceAll( `#include_version_without_prefix`, - commitTag.startsWith("v") ? commitTag.substring(1) : "latest" + commitTag.startsWith("v") ? commitTag.substring(1) : "latest", ); markdownContent = markdownContent.replaceAll( `#include_testnet_version`, - testnetTag.startsWith("v") ? testnetTag.substring(1) : testnetTag + testnetTag.startsWith("v") ? testnetTag.substring(1) : testnetTag, ); markdownContent = markdownContent.replaceAll( `#include_devnet_version`, - devnetTag.startsWith("v") ? devnetTag.substring(1) : devnetTag + devnetTag.startsWith("v") ? devnetTag.substring(1) : devnetTag, ); markdownContent = markdownContent.replaceAll( `#include_mainnet_version`, - mainnetTag.startsWith("v") ? mainnetTag.substring(1) : mainnetTag + mainnetTag.startsWith("v") ? mainnetTag.substring(1) : mainnetTag, ); return { diff --git a/yarn-project/end-to-end/src/composed/docs_examples.test.ts b/yarn-project/end-to-end/src/composed/docs_examples.test.ts index 241fa069c58d..39ca53ab4b82 100644 --- a/yarn-project/end-to-end/src/composed/docs_examples.test.ts +++ b/yarn-project/end-to-end/src/composed/docs_examples.test.ts @@ -5,6 +5,9 @@ import { createAztecNodeClient } from '@aztec/aztec.js/node'; import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { TestWallet } from '@aztec/test-wallet/server'; +import { execSync } from 'child_process'; +import { join } from 'path'; + // To run these tests against a local network: // 1. Start a local Ethereum node (Anvil): // anvil --host 127.0.0.1 --port 8545 @@ -50,4 +53,17 @@ describe('docs_examples', () => { expect(balance).toEqual(1n); // docs:end:simulate_function }); + + it( + 'runs aztecjs documentation examples', + () => { + const runnerPath = join(__dirname, '../../../../docs/examples/ts/aztecjs_runner/run.sh'); + execSync(runnerPath, { + stdio: 'inherit', + env: { ...process.env }, + cwd: join(__dirname, '../../../../docs/examples/ts/aztecjs_runner'), + }); + }, + 5 * 60 * 1000, + ); // 5 minute timeout });