Skip to content

Commit

Permalink
chore(docs): fix tutorial in dapp development (#2421)
Browse files Browse the repository at this point in the history
tutorial on dapp dev doesn't work. Now it does (hopefully)
  • Loading branch information
rahul-kothari authored Sep 20, 2023
1 parent e4b559e commit 027530f
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 52 deletions.
57 changes: 26 additions & 31 deletions docs/docs/dev_docs/dapps/tutorials/contract_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,35 @@ Follow the instructions [here](../../getting_started/noir_contracts.md) to insta

## Initialise nargo project

Create a new `contracts` folder, and from there, initialise a new project called `private_token`:
Create a new `contracts` folder, and from there, initialise a new project called `token`:

```sh
mkdir contracts && cd contracts
nargo new --contract private_token
nargo new --contract token
```

Then, open the `contracts/private_token/Nargo.toml` configuration file, and add the `aztec.nr` and `value_note` libraries as dependencies:
Then, open the `contracts/token/Nargo.toml` configuration file, and add the `aztec.nr` and `value_note` libraries as dependencies:

```toml
[dependencies]
aztec = { git="https://github.com/AztecProtocol/aztec-nr", tag="master", directory="aztec" }
value_note = { git="https://github.com/AztecProtocol/aztec-nr", tag="master", directory="value-note" }
safe_math = { git="https://github.com/AztecProtocol/aztec-nr", tag="master", directory="safe-math" }
```

Last, copy-paste the code from the `PrivateToken` contract into `contracts/private_token/main.nr`:
Last, copy-paste the code from the `Token` contract into `contracts/token/main.nr`:

#include_code all yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr rust
#include_code token_all yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust

The `Token` contract also requires two helper files. Copy-them too:

Create `contracts/token/types.nr` and copy-paste the following:

#include_code token_types_all yarn-project/noir-contracts/src/contracts/token_contract/src/types.nr rust

Finally, create `contracts/token/util.nr` and copy-paste the following:

#include_code token_util_all yarn-project/noir-contracts/src/contracts/token_contract/src/util.nr rust

## Compile your contract

Expand All @@ -38,41 +49,26 @@ yarn add -D @aztec/cli
Now run the following from your project root:

```sh
yarn aztec-cli compile contracts/private_token
yarn aztec-cli compile contracts/token
```

:::info
If you are using Typescript, consider including the `--typescript` option to [generate type-safe wrappers](../../contracts/compiling.md#typescript-interfaces) for your contracts.
:::

This should have created an artifact `contracts/private_token/target/private_token-Main.json` with the interface and bytecode for your contract.

## Adding a second contract

For the purposes of this tutorial, we'll set up a second contract: a public token contract. Follow the same steps as above for initialising a new Nargo project, include the dependencies, and copy-paste the following code into `contracts/public_token/main.nr`:

#include_code all yarn-project/noir-contracts/src/contracts/public_token_contract/src/main.nr rust

Compile the contract with the CLI:

```sh
yarn aztec-cli compile contracts/public_token
```

With both contracts ready, we'll now proceed to deployment.
This should have created an artifact `contracts/token/target/Token.json` with the interface and bytecode for your contract.

## Deploy your contracts

Let's now write a script for deploying your contracts to the Sandbox. We'll create an RPC 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`, importing the contract artifacts we have generated plus the dependencies we'll need, and with a call to a `main` function that we'll populate in a second:
Create a new file `src/deploy.mjs`, with a call to a `main` function that we'll populate in a second:

```js
// src/deploy.mjs
import { writeFileSync } from "fs";
import { createAztecRpcClient, ContractDeployer } from "@aztec/aztec.js";
import PrivateTokenArtifact from "../contracts/private_token/target/PrivateToken.json" assert { type: "json" };
import PublicTokenArtifact from "../contracts/public_token/target/PublicToken.json" assert { type: "json" };
import { writeFileSync } from 'fs';
import { Contract, ContractDeployer, createAztecRpcClient, getSandboxAccountsWallets } from '@aztec/aztec.js';
import TokenContractAbi from "../contracts/token/target/Token.json" assert { type: "json" };

async function main() {}

Expand All @@ -82,26 +78,25 @@ main().catch((err) => {
});
```

Now 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.
Now we will 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.

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

Note that the private token constructor 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 `_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.

:::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:

```typescript
await PrivateToken.deploy(client, 100n, owner.address).send().wait();
await Token.deploy(client).send().wait();
```

:::

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:

```text
Private token deployed to 0x2950b0f290422ff86b8ee8b91af4417e1464ddfd9dda26de8af52dac9ea4f869
Public token deployed to 0x2b54f68fd1e18f7dcfa71e3be3c91bb06ecbe727a28d609e964c225a4b5549c8
Token deployed to 0x2950b0f290422ff86b8ee8b91af4417e1464ddfd9dda26de8af52dac9ea4f869
```

## Next steps
Expand Down
27 changes: 13 additions & 14 deletions docs/docs/dev_docs/dapps/tutorials/contract_interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ In this section, we'll write the logic in our app that will interact with the co

## Showing user balance

Let's start by showing our user balance for the private token across their accounts. To do this, we can leverage the `balance_of_private` unconstrained view function of the private token contract:
Let's start by showing our user's private balance for the token across their accounts. To do this, we can leverage the `balance_of_private` unconstrained view function of the token contract:

#include_code balance_of_private yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust

:::info
Note that this function will only return a valid response for accounts registered in the RPC Server, since it requires access to the [user's private state](../../wallets/main.md#private-state). In other words, you cannot query the balance of another user for a private token contract.
Note that this function will only return a valid response for accounts registered in the RPC Server, since it requires access to the [user's private state](../../wallets/main.md#private-state). In other words, you cannot query the private balance of another user for the token contract.
:::

To do this, let's first initialise a new `Contract` instance using `aztec.js` that represents our deployed token contracts. Create a new `src/contracts.mjs` file with the imports for our artifacts and other dependencies:
Expand All @@ -18,8 +18,7 @@ To do this, let's first initialise a new `Contract` instance using `aztec.js` th
// src/contracts.mjs
import { Contract } from "@aztec/aztec.js";
import { readFileSync } from "fs";
import PrivateTokenArtifact from "../contracts/private_token/target/PrivateToken.json" assert { type: "json" };
import PublicTokenArtifact from "../contracts/public_token/target/PublicToken.json" assert { type: "json" };
import TokenContractAbi from "../contracts/token/target/Token.json" assert { type: "json" };
```

And then add the following code for initialising the `Contract` instances:
Expand All @@ -30,7 +29,7 @@ And then add the following code for initialising the `Contract` instances:
You can use the typescript autogenerated interface instead of the generic `Contract` class to get type-safe methods.
:::

We can now get the private 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:
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:

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

Expand All @@ -46,7 +45,7 @@ Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0

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 RPC Server and also provides an interface to craft and sign transactions on behalf of one of the user accounts.

We can initialise a wallet using one of the `getAccount` methods from `aztec.js``, along with the corresponding signing and encryption keys:
We can initialise a wallet using one of the `getAccount` methods from `aztec.js`, along with the corresponding signing and encryption keys:

```js
import { getSchnorrAccount } from "@aztec/aztec.js";
Expand All @@ -57,7 +56,13 @@ const wallet = await getSchnorrAccount(
).getWallet();
```

For ease of use, `aztec.js` also ships with a helper `getSandboxAccountsWallets` method that returns a wallet for each of the pre-initialised accounts in the Sandbox, so you can send transactions as any of them. We'll use one of these wallets to initialise the `Contract` instance that represents our private token contract, so every transaction sent through it will be sent through that wallet.
For ease of use, `aztec.js` also ships with a helper `getSandboxAccountsWallets` method that returns a wallet for each of the pre-initialised accounts in the Sandbox, so you can send transactions as any of them.

```js
import { getSandboxAccountsWallets } from '@aztec/aztec.js';
```

We'll use one of these wallets to initialise the `Contract` 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 Down Expand Up @@ -116,20 +121,14 @@ Balance of 0x226f8087792beff8d5009eb94e65d2a4a505b70baf4a9f28d33c8d620b0ba972: 0
Balance of 0x0e1f60e8566e2c6d32378bdcadb7c63696e853281be798c107266b8c3a88ea9b: 0
```

Public functions can emit [unencrypted public logs](../../contracts/events.md#unencrypted-events), which we can query via the RPC Server interface. In particular, the public token contract emits a generic `Coins minted` whenever the `mint` method is called:
Public functions can emit [unencrypted public logs](../../contracts/events.md#unencrypted-events), which we can query via the RPC Server interface. For example, here we have a `mint` method that emits a generic `Coins minted` whenever it is called:

#include_code unencrypted_log yarn-project/noir-contracts/src/contracts/public_token_contract/src/main.nr rust

We can extend our code by querying the logs emitted on the last block when the minting transaction is mined:

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

Running the code again would now show an extra line with:

```text
Log: Coins minted
```

:::info
At the time of this writing, there is no event-based mechanism in the `aztec.js` library to subscribe to events. The only option to consume them is to poll on every new block detected. This will change in a future version.
:::
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/dev_docs/dapps/tutorials/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ Create a new file `src/index.test.mjs` with the imports we'll be using and an em
```js
import { createSandbox } from "@aztec/aztec-sandbox";
import { Contract, createAccount } from "@aztec/aztec.js";
import PrivateTokenArtifact from "../contracts/private_token/target/PrivateToken.json" assert { type: "json" };
import TokenContractAbi from "../contracts/token/target/Token.json" assert { type: "json" };

describe("private token", () => {});
describe("token", () => {});
```

Let's set up our test suite. We'll start [a new Sandbox instance within the test](../../testing/testing.md#running-sandbox-in-the-nodejs-process), create two fresh accounts to test with, and deploy an instance of our contract. The `aztec-sandbox` and `aztec.js` provide the helper functions we need to do this:
Expand All @@ -40,7 +40,7 @@ Note that, since we are starting a new Sandbox instance, we need to `stop` it in

## Writing our test

Now that we have a working test environment, we can write our first test for exercising the `transfer` function on the private token contract. We will use the same `aztec.js` methods we used when building our dapp:
Now that we have a working test environment, we can write our first test for exercising the `transfer` function on the token contract. We will use the same `aztec.js` methods we used when building our dapp:

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

Expand Down
5 changes: 3 additions & 2 deletions yarn-project/end-to-end/src/sample-dapp/deploy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ async function main() {
const [owner] = await getSandboxAccountsWallets(client);

const token = await Contract.deploy(client, TokenContractAbi, []).send().deployed();

await token.withWallet(owner).methods._initialize({ address: owner.getAddress() }).send().wait();

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

const addresses = { token: token.address.toString() };
const addresses = {
token: token.address.toString(),
};
writeFileSync('addresses.json', JSON.stringify(addresses, null, 2));
}
// docs:end:dapp-deploy
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// docs:start:token_all
mod types;
mod util;

Expand Down Expand Up @@ -421,3 +422,4 @@ contract Token {
}

}
// docs:end:token_all
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// docs:start:token_types_all
use dep::std::hash::pedersen;
use dep::std::hash::pedersen_with_separator;
use dep::aztec::note::{
Expand Down Expand Up @@ -125,4 +126,5 @@ global TransparentNoteMethods = NoteInterface {
compute_nullifier,
get_header,
set_header,
};
};
// docs:end:token_types_all
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// docs:start:token_util_all
use dep::std::hash::{pedersen_with_separator};
use dep::aztec::constants_gen::GENERATOR_INDEX__SIGNATURE_PAYLOAD;

fn compute_message_hash<N>(args: [Field; N]) -> Field {
// @todo @lherskind We should probably use a separate generator for this,
// to avoid any potential collisions with payloads.
pedersen_with_separator(args, GENERATOR_INDEX__SIGNATURE_PAYLOAD)[0]
}
}
// docs:end:token_util_all

0 comments on commit 027530f

Please sign in to comment.