Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(docs): fix tutorial in dapp development #2421

Merged
merged 4 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Now we will import the generated contract artifacts 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
28 changes: 14 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 pprivate balance of another user for the token contract.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the pprivate

:::

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,8 @@ 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" };
import PublicTokenContractAbi from "../contracts/public_token/target/PublicToken.json" assert { type: "json" };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove as unneeded.

```

And then add the following code for initialising the `Contract` instances:
Expand All @@ -30,7 +30,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 +46,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 +57,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 +122,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
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