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

feat!: nuking private token #2822

Merged
merged 16 commits into from
Oct 16, 2023
14 changes: 0 additions & 14 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -631,18 +631,6 @@ jobs:
command: cond_run_script end-to-end ./scripts/run_tests_local e2e_private_airdrop.test.ts
environment: { DEBUG: "aztec:*" }

e2e-private-token-contract:
machine:
image: ubuntu-2204:2023.07.2
resource_class: large
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: cond_run_script end-to-end ./scripts/run_tests_local e2e_private_token_contract.test.ts
environment: { DEBUG: "aztec:*" }

e2e-sandbox-example:
machine:
image: ubuntu-2204:2023.07.2
Expand Down Expand Up @@ -1355,7 +1343,6 @@ workflows:
- e2e-lending-contract: *e2e_test
- e2e-token-contract: *e2e_test
- e2e-private-airdrop: *e2e_test
- e2e-private-token-contract: *e2e_test
- e2e-sandbox-example: *e2e_test
- e2e-multi-transfer-contract: *e2e_test
- e2e-block-building: *e2e_test
Expand Down Expand Up @@ -1394,7 +1381,6 @@ workflows:
- e2e-lending-contract
- e2e-token-contract
- e2e-private-airdrop
- e2e-private-token-contract
- e2e-sandbox-example
- e2e-multi-transfer-contract
- e2e-block-building
Expand Down
2 changes: 1 addition & 1 deletion bootstrap_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ build_local $PROJECT_NAME
if [ -z "$PROJECT_NAME" ]; then
echo
echo "Success! You could now run e.g.:"
echo " docker run -ti --rm aztecprotocol/end-to-end:latest e2e_private_token_contract.test"
echo " docker run -ti --rm aztecprotocol/end-to-end:latest e2e_token_contract.test"
fi
56 changes: 23 additions & 33 deletions docs/docs/dev_docs/cli/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export ADDRESS2=<Account address printed by the above command>

## Deploying a Token Contract

We will now deploy the private token contract using the `deploy` command, minting 1000000 initial tokens to address `0x175310d40cd3412477db1c2a2188efd586b63d6830115fbb46c592a6303dbf6c`. Make sure to replace this address with one of the two you created earlier.
We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument.
Make sure to replace this address with one of the two you created earlier.

#include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

Expand All @@ -97,52 +98,41 @@ Save the contract address as an environment variable. We will use it later.
export CONTRACT_ADDRESS=<Your new contract address>
```

:::info
If you use a different address in the constructor above, you will get an error when running the deployment. This is because you need to register an account in the sandbox before it can receive private notes. When you create a new account, it gets automatically registered. Alternatively, you can register an account you do not own along with its public key using the `register-recipient` command.
:::

This command takes 1 mandatory positional argument which is the path to the contract artifact file in a JSON format (e.g. `contracts/target/PrivateToken.json`).
Alternatively you can pass the name of an example contract as exported by `@aztec/noir-contracts` (run `aztec-cli example-contracts` to see the full list of contracts available).

The command takes a few optional arguments while the most important one is:

- `--args` - Arguments to the constructor of the contract. In this case we have minted 1000000 initial tokens to the aztec address 0x20d3321707d53cebb168568e25c5c62a853ae1f0766d965e00d6f6c4eb05d599.
- `--args` - Arguments to the constructor of the contract. In this case we have set an address as admin.

The CLI tells us that the contract was successfully deployed. We can use the `check-deploy` command to verify that a contract has been successfully deployed to that address:

#include_code check-deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

## Calling a View Method

When we deployed the token contract, an initial supply of tokens was minted to the address provided in the constructor. We can now query the `getBalance()` method on the contract to retrieve the balance of that address. Make sure to replace the `contract-address` with the deployment address you got from the previous command, and the `args` with the account you used in the constructor.

#include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are:

- `--args` - The address for which we want to retrieve the balance.
- `--contract-artifact` - The artifact of the contract we are calling.
- `--contract-address` - The address of the deployed contract

As you can see from the result, this address has a balance of 1000000, as expected. When using the Sandbox, you are able to query the balance of any account that has been created in the system, even the accounts created by default. You may wonder why this is, as you haven't provided the private keys for these accounts. The Sandbox contains a component known as the Private Execution Environment (PXE). When an account is created, this component stores the provided encryption private key and is able to read the account's private state meaning that the Sandbox can report the balance of any of it's accounts. More information about the account model can be found [here](../../concepts/foundation/accounts/main.md).

## Sending a Transaction

We can now send a transaction to the network. We will transfer funds from the owner of the initial minted tokens to our other account. For this we will use the `send` command, which expects as arguments the quantity of tokens to be transferred, the sender's address, and the recipient's address. Make sure to replace all addresses in this command with the ones for your run.

#include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

We called the `transfer` function of the contract and provided these arguments:
We can now send a transaction to the network. We will mint funds in the public domain.
To form and submit the transaction we will use the `send` command of `aztec-cli`.
The `send` command expect the function name as the first unnamed argument and the following named arguments:

- `--args` - The list of arguments to the function call.
- `--contract-artifact` - The artifact of the contract to call.
- `--contract-address` - The deployed address of the contract to call.
- `--private-key` - The private key of the sender
- `--private-key` - The private key of the sender.

#include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

We called the `mint_public` function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours.

The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time:

#include_code get-tx-receipt yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

Let's now call `getBalance()` on each of our accounts and we should see updated values:
## Calling an Unconstrained (View) Function

Now that the `mint_public` tx has been settled we can call the `balance_of_public` unconstrained function:

#include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash

The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are:

- `--args` - The address for which we want to retrieve the balance.
- `--contract-artifact` - The artifact of the contract we are calling.
- `--contract-address` - The address of the deployed contract

#include_code calls yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash
As you can see from the result, this address has a public balance of 543, as expected.
168 changes: 138 additions & 30 deletions docs/docs/dev_docs/contracts/compiling.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,85 @@ You can also generate these interfaces from prebuilt artifacts using the `genera
aztec-cli generate-typescript ./path/to/my_aztec_contract_project
```

Example code generated from the [PrivateToken](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr) contract:
Below is typescript code generated from the [Token](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr) contract:

```ts showLineNumbers
export class PrivateTokenContract extends ContractBase {
/** Creates a contract instance at the given address. */
public static async at(address: AztecAddress, wallet: Wallet) { ... }
export class TokenContract extends ContractBase {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this refer to some actual generated code with include code such that we don't need to change it if we are updating stuff in the contract?

private constructor(completeAddress: CompleteAddress, wallet: Wallet, portalContract = EthAddress.ZERO) {
super(completeAddress, TokenContractArtifact, wallet, portalContract);
}

/**
* Creates a contract instance.
* @param address - The deployed contract's address.
* @param wallet - The wallet to use when interacting with the contract.
* @returns A promise that resolves to a new Contract instance.
*/
public static async at(address: AztecAddress, wallet: Wallet) {
return Contract.at(address, TokenContract.artifact, wallet) as Promise<TokenContract>;
}

/**
* Creates a tx to deploy a new instance of this contract.
*/
public static deploy(pxe: PXE, admin: AztecAddressLike) {
return new DeployMethod<TokenContract>(Point.ZERO, pxe, TokenContractArtifact, Array.from(arguments).slice(1));
}

/**
* Creates a tx to deploy a new instance of this contract using the specified public key to derive the address.
*/
public static deployWithPublicKey(pxe: PXE, publicKey: PublicKey, admin: AztecAddressLike) {
return new DeployMethod<TokenContract>(publicKey, pxe, TokenContractArtifact, Array.from(arguments).slice(2));
}

/** Creates a tx to deploy a new instance of this contract. */
public static deploy(pxe: PXE, initial_supply: FieldLike, owner: FieldLike) { ... }
/**
* Returns this contract's artifact.
*/
public static get artifact(): ContractArtifact {
return TokenContractArtifact;
}

/** Type-safe wrappers for the public methods exposed by the contract. */
public methods!: {
/** getBalance(owner: field) */
getBalance: ((owner: FieldLike) => ContractFunctionInteraction) & Pick<ContractMethod, 'selector'>;

/** mint(amount: field, owner: field) */
mint: ((amount: FieldLike, owner: FieldLike) => ContractFunctionInteraction) & Pick<ContractMethod, 'selector'>;
/** balance_of_private(owner: struct) */
balance_of_private: ((owner: AztecAddressLike) => ContractFunctionInteraction) & Pick<ContractMethod, 'selector'>;

/** balance_of_public(owner: struct) */
balance_of_public: ((owner: AztecAddressLike) => ContractFunctionInteraction) & Pick<ContractMethod, 'selector'>;

/** shield(from: struct, amount: field, secret_hash: field, nonce: field) */
shield: ((
from: AztecAddressLike,
amount: FieldLike,
secret_hash: FieldLike,
nonce: FieldLike,
) => ContractFunctionInteraction) &
Pick<ContractMethod, 'selector'>;

/** total_supply() */
total_supply: (() => ContractFunctionInteraction) & Pick<ContractMethod, 'selector'>;

/** transfer(from: struct, to: struct, amount: field, nonce: field) */
transfer: ((
from: AztecAddressLike,
to: AztecAddressLike,
amount: FieldLike,
nonce: FieldLike,
) => ContractFunctionInteraction) &
Pick<ContractMethod, 'selector'>;

/** transfer(amount: field, sender: field, recipient: field) */
transfer: ((amount: FieldLike, sender: FieldLike, recipient: FieldLike) => ContractFunctionInteraction) &
/** transfer_public(from: struct, to: struct, amount: field, nonce: field) */
transfer_public: ((
from: AztecAddressLike,
to: AztecAddressLike,
amount: FieldLike,
nonce: FieldLike,
) => ContractFunctionInteraction) &
Pick<ContractMethod, 'selector'>;

...
};
}
```
Expand All @@ -91,37 +149,87 @@ You can also generate these interfaces from prebuilt artifacts using the `genera
aztec-cli generate-noir-interface ./path/to/my_aztec_contract_project
```

Example code generated from the [PrivateToken](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr) contract:
Below is an example interface, also generated from the [Token](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr) contract:

```rust
impl PrivateTokenPrivateContextInterface {
fn at(address: Field) -> Self {
Self { address }
impl TokenPrivateContextInterface {
pub fn at(address: Field) -> Self {
Self {
address,
}
}

fn mint(
self, context: &mut PrivateContext, amount: Field, owner: Field

pub fn burn(
self,
context: &mut PrivateContext,
from: FromBurnStruct,
amount: Field,
nonce: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = owner;
let mut serialized_args = [0; 3];
serialized_args[0] = from.address;
serialized_args[1] = amount;
serialized_args[2] = nonce;

// 0x1dc9c3c0 is the function selector for `mint(field,field)`
context.call_private_function(self.address, 0x1dc9c3c0, serialized_args)
context.call_private_function(self.address, 0xd4fcc96e, serialized_args)
}


pub fn burn_public(
self,
context: &mut PrivateContext,
from: FromBurnPublicStruct,
amount: Field,
nonce: Field
) {
let mut serialized_args = [0; 3];
serialized_args[0] = from.address;
serialized_args[1] = amount;
serialized_args[2] = nonce;

context.call_public_function(self.address, 0xb0e964d5, serialized_args)
}
...

}

fn transfer(
self, context: &mut PrivateContext, amount: Field, sender: Field, recipient: Field
impl TokenPublicContextInterface {
pub fn at(address: Field) -> Self {
Self {
address,
}
}

pub fn burn_public(
self,
context: PublicContext,
from: FromBurnPublicStruct,
amount: Field,
nonce: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 3];
serialized_args[0] = from.address;
serialized_args[1] = amount;
serialized_args[2] = nonce;

context.call_public_function(self.address, 0xb0e964d5, serialized_args)
}


pub fn mint_private(
self,
context: PublicContext,
amount: Field,
secret_hash: Field
) -> [Field; RETURN_VALUES_LENGTH] {
let mut serialized_args = [0; 2];
serialized_args[0] = amount;
serialized_args[1] = sender;
serialized_args[2] = recipient;
serialized_args[1] = secret_hash;

// 0xdcd4c318 is the function selector for `transfer(field,field,field)`
context.call_private_function(self.address, 0xdcd4c318, serialized_args)
context.call_public_function(self.address, 0x10763932, serialized_args)
}


}
```

Expand Down
Loading