Skip to content

Commit

Permalink
fix(docs): Dapp tutorial edits (#8695)
Browse files Browse the repository at this point in the history
closes: AztecProtocol/dev-rel#383

---------

Co-authored-by: James Zaki <[email protected]>
  • Loading branch information
critesjosh and jzaki authored Oct 21, 2024
1 parent 367c38c commit f95bcff
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ You can see all of our example contracts in the monorepo [here (GitHub link)](ht
If you wish to run components of the Aztec network stack separately, you can use the `aztec start` command with various options for enabling components.

```bash
aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] ----p2p-bootstrap [p2pOptions]
aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] --p2p-bootstrap [p2pOptions]
```

Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. Eg if you want to run a PXE separately to a node, you can [read this guide](../../../guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md).
Expand Down
8 changes: 2 additions & 6 deletions docs/docs/tutorials/codealong/simple_dapp/0_project_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@ cd sample-dapp
yarn init -yp
```

3. Add the `aztec.js` and `accounts` libraries as a dependency:
3. Add the `aztec.js` and `accounts` libraries as dependencies. Also add `noir-contracts.js` for quick use of example contracts:

```sh
yarn add @aztec/aztec.js @aztec/accounts
yarn add @aztec/aztec.js @aztec/accounts @aztec/noir-contracts.js
```

## Next steps

With your project already set up, let's [connect to the Private eXecution Environment (PXE) running inside Sandbox and grab an account to interact with it](./1_pxe_service.md).
12 changes: 9 additions & 3 deletions docs/docs/tutorials/codealong/simple_dapp/1_pxe_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ PXE is a component of the Aztec Protocol that provides a private execution envir

As an app developer, the PXE interface provides you with access to the user's accounts and their private state, as well as a connection to the network for accessing public global state.

During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](../../../reference/developer_references/sandbox_reference/index.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil.
The [Aztec Sandbox](../../../reference/developer_references/sandbox_reference/index.md) runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil.
The Sandbox also includes a set of pre-initialized accounts that you can use from your app.

In this section, we'll connect to the Sandbox from our project.
Expand All @@ -20,7 +20,13 @@ Let's create our first file `src/index.mjs` with the following contents:

#include_code all yarn-project/end-to-end/src/sample-dapp/connect.mjs javascript

Run this example as `node src/index.mjs` and you should see the following output:
Make sure the [Sandbox is running](../../../guides/developer_guides/getting_started.md) and run the example

```bash
node src/index.mjs
```

and you should see the following output:

```
Connected to chain 31337
Expand All @@ -37,7 +43,7 @@ Let's try loading the accounts:

#include_code showAccounts yarn-project/end-to-end/src/sample-dapp/index.mjs javascript

Run again the above, and we should see:
Call the `showAccounts` function from `main`, run again the above, and you should see something like:

```
User accounts:
Expand Down
18 changes: 11 additions & 7 deletions docs/docs/tutorials/codealong/simple_dapp/2_contract_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Last, copy-paste the code from the `Token` contract into `contracts/token/main.n

### Helper files

:::info
Remove the `mod test;` line from `contracts/token/src/main.nr` as we will not be using TXE tests in this tutorial.
:::

The `Token` contract also requires some helper files. You can view the files [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src). Copy the `types.nr` and the `types` folder into `contracts/token/src`.

## Compile your contract
Expand All @@ -46,15 +50,15 @@ aztec-nargo compile

Let's now write a script for deploying your contracts to the Sandbox. We'll create a Private eXecution Environment (PXE) client, and then use the `ContractDeployer` class to deploy our contracts, and store the deployment address to a local JSON file.

Create a new file `src/deploy.mjs`:
Create a new file `src/deploy.mjs`. We import the contract artifacts we have generated plus the dependencies we'll need, and then we can deploy the contracts by adding the following code to the `src/deploy.mjs` file.

```js
// src/deploy.mjs
#include_code deploy-imports yarn-project/end-to-end/src/sample-dapp/deploy.mjs raw
import TokenContractJson from "../contracts/token/target/token-Token.json" assert { type: "json" };
import { writeFileSync } from 'fs';
import { Contract, loadContractArtifact, createPXEClient } from '@aztec/aztec.js';
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import TokenContractJson from "../contracts/token/target/token_contract-Token.json" assert { type: "json" };

const TokenContractArtifact = loadContractArtifact(TokenContractJson);

#include_code dapp-deploy yarn-project/end-to-end/src/sample-dapp/deploy.mjs raw

Expand All @@ -64,12 +68,12 @@ main().catch((err) => {
});
```

We import the contract artifacts we have generated plus the dependencies we'll need, and then we can deploy the contracts by adding the following code to the `src/deploy.mjs` file. Here, we are using the `ContractDeployer` class with the compiled artifact to send a new deployment transaction. The `wait` method will block execution until the transaction is successfully mined, and return a receipt with the deployed contract address.
Here, we are using the `Contract` class with the compiled artifact to send a new deployment transaction. The `deployed` method will block execution until the transaction is successfully mined, and return a receipt with the deployed contract address.

Note that the token's `_initialize()` method expects an `owner` address to mint an initial set of tokens to. We are using the first account from the Sandbox for this.
Note that the token's `constructor()` method expects an `owner` address to set as the contract `admin`. We are using the first account from the Sandbox for this.

:::info
If you are using the generated typescript classes, you can drop the generic `ContractDeployer` in favor of using the `deploy` method of the generated class, which will automatically load the artifact for you and type-check the constructor arguments. SEe the [How to deploy a contract](../../../guides/developer_guides/smart_contracts/how_to_deploy_contract.md) page for more info.
If you are using the generated typescript classes, you can drop the generic `ContractDeployer` in favor of using the `deploy` method of the generated class, which will automatically load the artifact for you and type-check the constructor arguments. See the [How to deploy a contract](../../../guides/developer_guides/smart_contracts/how_to_deploy_contract.md) page for more info.
:::

Run the snippet above as `node src/deploy.mjs`, and you should see the following output, along with a new `addresses.json` file in your project root:
Expand Down
52 changes: 28 additions & 24 deletions docs/docs/tutorials/codealong/simple_dapp/3_contract_interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,53 +18,57 @@ To do this, let's first initialize a new `Contract` instance using `aztec.js` th

```js
// src/contracts.mjs
import { Contract } from "@aztec/aztec.js";
import { readFileSync } from "fs";
import TokenContractJson from "../contracts/token/target/token_contract-Token.json" assert { type: "json" };
#include_code imports yarn-project/end-to-end/src/sample-dapp/contracts.mjs raw
```

And then add the following code for initializing the `Contract` instances:
You may have noticed that we are importing the `TokenContract` class from `@aztec/noir-contracts.js`. This is an alternative way to get the contract interface for interacting with the contract. With this, we can add the following code for initializing the `TokenContract` instance:

#include_code get-tokens yarn-project/end-to-end/src/sample-dapp/contracts.mjs javascript

:::info
You can use the typescript autogenerated interface instead of the generic `Contract` class to get type-safe methods.
:::
We can now get the token instance in our main code in `src/index.mjs`, by importing the function from `src/contracts.mjs`. Update the imports in `src/index.mjs` to look like this:

```js
// src/index.mjs
#include_code imports yarn-project/end-to-end/src/sample-dapp/index.mjs raw
```

We can now get the token instance in our main code in `src/index.mjs`, and query the private balance for each of the user accounts. To query a function, without sending a transaction, use the `view` function of the method:
and query the private balance for each of the user accounts. To query a function, without sending a transaction, use the `simulate` function of the method:

#include_code showPrivateBalances yarn-project/end-to-end/src/sample-dapp/index.mjs javascript

Run this as `node src/index.mjs` and you should now see the following output:
Call the function in `main` and run this with `node src/index.mjs` and you should now see the following output:

```
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 100
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 0
Balance of 0x226f8087792beff8d5009eb94e65d2a4a505b70baf4a9f28d33c8d620b0ba972: 0
Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0
```

## Transferring private tokens
## Mint tokens

Now that we can see the balance for each user, let's transfer tokens from one account to another. To do this, we will first need access to a `Wallet` object. This wraps access to an PXE and also provides an interface to craft and sign transactions on behalf of one of the user accounts.
Before we can transfer tokens, we need to mint some tokens to our user accounts. Add the following function to `src/index.mjs`:

We can initialize a wallet using one of the `getAccount` methods from the `accounts` package, along with the corresponding signing and encryption keys:
#include_code mintPrivateFunds yarn-project/end-to-end/src/sample-dapp/index.mjs javascript

```js
import { getSchnorrAccount } from "@aztec/accounts/schnorr";
const wallet = await getSchnorrAccount(
client,
ENCRYPTION_PRIVATE_KEY,
SIGNING_PRIVATE_KEY
).getWallet();
Call the function in `main`, run the script and after printing the balances of each account it will then privately mint tokens. After that completes, you should then see 20 tokens in the balance of the first account.

```text
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 20
Balance of 0x226f8087792beff8d5009eb94e65d2a4a505b70baf4a9f28d33c8d620b0ba972: 0
Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0
```

For ease of use, `accounts` also ships with a helper `getInitialTestAccountsWallets` method that returns a wallet for each of the pre-initialized accounts in the Sandbox, so you can send transactions as any of them.
## Transferring private tokens

Now that we can see the balance for each user, let's transfer tokens from one account to another. To do this, we will first need access to a `Wallet` object. This wraps access to an PXE and also provides an interface to craft and sign transactions on behalf of one of the user accounts.

For ease of use, `@aztec/accounts` also ships with a helper `getInitialTestAccountsWallets` method that returns a wallet for each of the pre-initialized accounts in the Sandbox, so you can send transactions as any of them.

```js
import { getInitialTestAccountsWallets } from "@aztec/accounts/testing";
```

We'll use one of these wallets to initialize the `Contract` instance that represents our private token contract, so every transaction sent through it will be sent through that wallet.
We'll use one of these wallets to initialize the `TokenContract` instance that represents our private token contract, so every transaction sent through it will be sent through that wallet.

#include_code transferPrivateFunds yarn-project/end-to-end/src/sample-dapp/index.mjs javascript

Expand All @@ -77,14 +81,14 @@ Run this new snippet and you should see the following:
```text
Sent transfer transaction 16025a7c4f6c44611d7ac884a5c27037d85d9756a4924df6d97fb25f6e83a0c8
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 100
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 20
Balance of 0x226f8087792beff8d5009eb94e65d2a4a505b70baf4a9f28d33c8d620b0ba972: 0
Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0
Awaiting transaction to be mined
Transaction has been mined on block 4
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 99
Balance of 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d: 19
Balance of 0x226f8087792beff8d5009eb94e65d2a4a505b70baf4a9f28d33c8d620b0ba972: 1
Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0
```
Expand Down
6 changes: 4 additions & 2 deletions docs/docs/tutorials/codealong/simple_dapp/4_testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ import {
waitForPXE,
} from "@aztec/aztec.js";
import { createAccount } from "@aztec/accounts/testing";
import { TokenContractArtifact } from "@aztec/noir-contracts.js/Token";
import { TokenContract } from "@aztec/noir-contracts.js/Token";

const {
PXE_URL = "http://localhost:8080",
ETHEREUM_HOST = "http://localhost:8545",
} = process.env;

describe("token contract", () => {});
describe("token contract", () => {
// <tests go here>
});
```

Let's set up our test suite. We'll make sure the Sandbox is running, create two fresh accounts to test with, and deploy an instance of our contract. `aztec.js` provides the helper functions we need to do this:
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/sample-dapp/connect.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createPXEClient } from '@aztec/aztec.js';
const { PXE_URL = 'http://localhost:8080' } = process.env;

async function main() {
const pxe = createPXEClient(PXE_URL);
const pxe = await createPXEClient(PXE_URL);
const { l1ChainId } = await pxe.getNodeInfo();
console.log(`Connected to chain ${l1ChainId}`);
}
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/end-to-end/src/sample-dapp/contracts.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// docs:start:imports
import { AztecAddress } from '@aztec/aztec.js';
import { TokenContract } from '@aztec/noir-contracts.js/Token';

import { readFileSync } from 'fs';

// docs:end:imports

// docs:start:get-tokens
export async function getToken(client) {
const addresses = JSON.parse(readFileSync('addresses.json'));
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/end-to-end/src/sample-dapp/deploy.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// docs:start:deploy-imports
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import { Contract, createPXEClient, loadContractArtifact, waitForPXE } from '@aztec/aztec.js';
// docs:end:deploy-imports
import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js';

import { writeFileSync } from 'fs';
Expand All @@ -15,7 +17,9 @@ async function main() {
const [ownerWallet] = await getInitialTestAccountsWallets(pxe);
const ownerAddress = ownerWallet.getAddress();

const token = await TokenContract.deploy(ownerWallet, ownerAddress, 'TokenName', 'TKN', 18).send().deployed();
const token = await Contract.deploy(ownerWallet, TokenContractArtifact, [ownerAddress, 'TokenName', 'TKN', 18])
.send()
.deployed();

console.log(`Token deployed at ${token.address.toString()}`);

Expand Down
28 changes: 17 additions & 11 deletions yarn-project/end-to-end/src/sample-dapp/index.mjs
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
// docs:start:imports
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import { ExtendedNote, Fr, Note, computeSecretHash, createPXEClient, waitForPXE } from '@aztec/aztec.js';
import { fileURLToPath } from '@aztec/foundation/url';
import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token';

import { getToken } from './contracts.mjs';

// docs:end:imports

const { PXE_URL = 'http://localhost:8080' } = process.env;

// docs:start:showAccounts
async function showAccounts(pxe) {
// docs:start:showAccounts
const accounts = await pxe.getRegisteredAccounts();
console.log(`User accounts:\n${accounts.map(a => a.address).join('\n')}`);
// docs:end:showAccounts
}
// docs:end:showAccounts

// docs:start:showPrivateBalances
async function showPrivateBalances(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

// docs:start:showPrivateBalances
const accounts = await pxe.getRegisteredAccounts();

for (const account of accounts) {
// highlight-next-line:showPrivateBalances
const balance = await token.methods.balance_of_private(account.address).simulate();
console.log(`Balance of ${account.address}: ${balance}`);
}
// docs:end:showPrivateBalances
}
// docs:end:showPrivateBalances

// docs:start:mintPrivateFunds
async function mintPrivateFunds(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);
Expand All @@ -49,15 +53,17 @@ async function mintPrivateFunds(pxe) {
TokenContract.notes.TransparentNote.id,
receipt.txHash,
);

await pxe.addNote(extendedNote, owner.getAddress());

await token.methods.redeem_shield(owner.getAddress(), mintAmount, secret).send().wait();
await token.withWallet(owner).methods.redeem_shield(owner.getAddress(), mintAmount, secret).send().wait();

await showPrivateBalances(pxe);
}
// docs:end:mintPrivateFunds

// docs:start:transferPrivateFunds
async function transferPrivateFunds(pxe) {
// docs:start:transferPrivateFunds
const [owner, recipient] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

Expand All @@ -67,26 +73,26 @@ async function transferPrivateFunds(pxe) {

console.log(`Transaction ${receipt.txHash} has been mined on block ${receipt.blockNumber}`);
await showPrivateBalances(pxe);
// docs:end:transferPrivateFunds
}
// docs:end:transferPrivateFunds

// docs:start:showPublicBalances
async function showPublicBalances(pxe) {
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

// docs:start:showPublicBalances
const accounts = await pxe.getRegisteredAccounts();

for (const account of accounts) {
// highlight-next-line:showPublicBalances
const balance = await token.methods.balance_of_public(account.address).simulate();
console.log(`Balance of ${account.address}: ${balance}`);
}
// docs:end:showPublicBalances
}
// docs:end:showPublicBalances

// docs:start:mintPublicFunds
async function mintPublicFunds(pxe) {
// docs:start:mintPublicFunds
const [owner] = await getInitialTestAccountsWallets(pxe);
const token = await getToken(owner);

Expand All @@ -97,7 +103,6 @@ async function mintPublicFunds(pxe) {
console.log(`Transaction ${receipt.txHash} has been mined on block ${receipt.blockNumber}`);

await showPublicBalances(pxe);
// docs:end:mintPublicFunds

// docs:start:showLogs
const blockNumber = await pxe.getBlockNumber();
Expand All @@ -106,6 +111,7 @@ async function mintPublicFunds(pxe) {
for (const log of textLogs) console.log(`Log emitted: ${log}`);
// docs:end:showLogs
}
// docs:end:mintPublicFunds

async function main() {
const pxe = createPXEClient(PXE_URL);
Expand Down
1 change: 1 addition & 0 deletions yarn-project/end-to-end/src/sample-dapp/index.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('token', () => {
TokenContract.notes.TransparentNote.id,
receipt.txHash,
);

await pxe.addNote(extendedNote, owner.getAddress());

await token.methods.redeem_shield(owner.getAddress(), initialBalance, secret).send().wait();
Expand Down

0 comments on commit f95bcff

Please sign in to comment.