diff --git a/docs/docs/aztec/concepts/accounts/authwit.md b/docs/docs/aztec/concepts/accounts/authwit.md index a0d1cbe32c1..79cb828ccb3 100644 --- a/docs/docs/aztec/concepts/accounts/authwit.md +++ b/docs/docs/aztec/concepts/accounts/authwit.md @@ -205,7 +205,7 @@ In order for another user to be able to take actions on your behalf, they would ### Other use-cases -We don't need to limit ourselves to the `transfer` function, we can use the same scheme for any function that requires authentication. For example, for authenticating to burn or shield assets or to vote in a governance contract or perform an operation on a lending protocol. +We don't need to limit ourselves to the `transfer` function, we can use the same scheme for any function that requires authentication. For example, for authenticating to burn, transferring assets from public to private, or to vote in a governance contract or perform an operation on a lending protocol. ### Next Steps diff --git a/docs/docs/guides/developer_guides/getting_started.md b/docs/docs/guides/developer_guides/getting_started.md index ce015ba29db..cceabca3bfd 100644 --- a/docs/docs/guides/developer_guides/getting_started.md +++ b/docs/docs/guides/developer_guides/getting_started.md @@ -182,25 +182,16 @@ Simulation result: 100n ## Playing with hybrid state and private functions -In the following steps, we'll shield a token (moving it from public to private state), and check our private and public balance. - -First we need to generate a secret and secret hash with the alias `shield`: - -```bash -aztec-wallet create-secret -a shield -``` - -Call the `shield` function like this: +In the following steps, we'll moving some tokens from public to private state, and check our private and public balance. ```bash -aztec-wallet send shield --from accounts:my-wallet --contract-address testtoken --args accounts:my-wallet 25 secrets:shield:hash 0 +aztec-wallet send transfer_to_private --from accounts:my-wallet --contract-address testtoken --args accounts:my-wallet 25 ``` -This takes the same parameters as our previous `send` call, with the arguments for `shield` function which are: +The arguments for `transfer_to_private` function are: -- the number of tokens to shield (`25`) -- a `secret_hash` (`SECRET_HASH` which has been derived from a secret that you generated in the CLI) -- a `nonce` (`0` in this case). +- the account address to transfer to +- the amount of tokens to send to private A successful call should print something similar to what you've seen before. @@ -216,30 +207,6 @@ This should print Simulation result: 75n ``` -Now we will need to add these shielded tokens into our account's environment so that we have the correct information to claim them. - -```bash -aztec-wallet add-note TransparentNote pending_shields --contract-address testtoken --transaction-hash last --address accounts:my-wallet --body 25 secrets:shield:hash -``` - -This takes - -- the type of note you are claiming (`TransparentNote`) -- the name of the storage (`pending_shields`) -- the contract address -- the transaction hash the note was created in (automatically aliased as `last`) -- the address to claim the note into (`accounts:my-wallet`) - -Don't worry if you don't understand what `TransparentNote` or `add-note` mean just yet. When you follow the tutorials, you'll learn more. - -A successful result will not print anything. - -Now you can redeem the shielded tokens: - -```bash -aztec-wallet send redeem_shield --contract-address testtoken --args accounts:my-wallet 25 secrets:shield --from accounts:my-wallet -``` - And then call `balance_of_private` to check that you have your tokens! ```bash diff --git a/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md b/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md index 902230fa304..8775d976f55 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md +++ b/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md @@ -43,9 +43,18 @@ You can use the code generator to autogenerate type-safe typescript classes for aztec codegen ./aztec-nargo/output/target/path -o src/artifacts ``` -Below is typescript code generated from the [Token (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/token_contract/src/main.nr) contract: +Below is typescript code generated from the example [Token contract (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/token_contract/src/main.nr) contract: ```ts showLineNumbers +export type Transfer = { + from: AztecAddressLike; + to: AztecAddressLike; + amount: FieldLike; +}; + +/** + * Type-safe interface for contract Token; + */ export class TokenContract extends ContractBase { private constructor(instance: ContractInstanceWithAddress, wallet: Wallet) { super(instance, TokenContractArtifact, wallet); @@ -58,7 +67,11 @@ export class TokenContract extends ContractBase { * @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; + return Contract.at( + address, + TokenContract.artifact, + wallet + ) as Promise; } /** @@ -69,51 +82,51 @@ export class TokenContract extends ContractBase { admin: AztecAddressLike, name: string, symbol: string, - decimals: bigint | number, + decimals: bigint | number ) { return new DeployMethod( - Fr.ZERO, + PublicKeys.default(), wallet, TokenContractArtifact, TokenContract.at, - Array.from(arguments).slice(1), + Array.from(arguments).slice(1) ); } /** * Creates a tx to deploy a new instance of this contract using the specified public keys hash to derive the address. */ - public static deployWithPublicKeysHash( - publicKeysHash: Fr, + public static deployWithPublicKeys( + publicKeys: PublicKeys, wallet: Wallet, admin: AztecAddressLike, name: string, symbol: string, - decimals: bigint | number, + decimals: bigint | number ) { return new DeployMethod( - publicKeysHash, + publicKeys, wallet, TokenContractArtifact, TokenContract.at, - Array.from(arguments).slice(2), + Array.from(arguments).slice(2) ); } /** * Creates a tx to deploy a new instance of this contract using the specified constructor method. */ - public static deployWithOpts( - opts: { publicKeysHash?: Fr; method?: M; wallet: Wallet }, - ...args: Parameters + public static deployWithOpts( + opts: { publicKeys?: PublicKeys; method?: M; wallet: Wallet }, + ...args: Parameters ) { return new DeployMethod( - opts.publicKeysHash ?? Fr.ZERO, + opts.publicKeys ?? PublicKeys.default(), opts.wallet, TokenContractArtifact, TokenContract.at, Array.from(arguments).slice(1), - opts.method ?? 'constructor', + opts.method ?? "constructor" ); } @@ -125,101 +138,309 @@ export class TokenContract extends ContractBase { } public static get storage(): ContractStorageLayout< - | 'admin' - | 'minters' - | 'balances' - | 'total_supply' - | 'pending_shields' - | 'public_balances' - | 'symbol' - | 'name' - | 'decimals' + | "admin" + | "minters" + | "balances" + | "total_supply" + | "public_balances" + | "symbol" + | "name" + | "decimals" > { return { admin: { slot: new Fr(1n), - typ: 'PublicMutable', }, minters: { slot: new Fr(2n), - typ: 'Map>', }, balances: { slot: new Fr(3n), - typ: 'BalancesMap', }, total_supply: { slot: new Fr(4n), - typ: 'PublicMutable', - }, - pending_shields: { - slot: new Fr(5n), - typ: 'PrivateSet', }, public_balances: { - slot: new Fr(6n), - typ: 'Map>', + slot: new Fr(5n), }, symbol: { - slot: new Fr(7n), - typ: 'SharedImmutable', + slot: new Fr(6n), }, name: { - slot: new Fr(8n), - typ: 'SharedImmutable', + slot: new Fr(7n), }, decimals: { - slot: new Fr(9n), - typ: 'SharedImmutable', + slot: new Fr(8n), }, } as ContractStorageLayout< - | 'admin' - | 'minters' - | 'balances' - | 'total_supply' - | 'pending_shields' - | 'public_balances' - | 'symbol' - | 'name' - | 'decimals' + | "admin" + | "minters" + | "balances" + | "total_supply" + | "public_balances" + | "symbol" + | "name" + | "decimals" >; } - public static get notes(): ContractNotes<'TransparentNote' | 'UintNote'> { - const notes = this.artifact.outputs.globals.notes ? (this.artifact.outputs.globals.notes as any) : []; + public static get notes(): ContractNotes<"UintNote"> { return { - TransparentNote: { - id: new Fr(84114971101151129711410111011678111116101n), - }, UintNote: { - id: new Fr(8411110710111078111116101n), + id: new NoteSelector(202136239), }, - } as ContractNotes<'TransparentNote' | 'UintNote'>; + } as ContractNotes<"UintNote">; } /** Type-safe wrappers for the public methods exposed by the contract. */ - public override methods!: { - /** transfer_in_public(from: struct, to: struct, amount: field, nonce: field) */ - transfer_in_public: (( + public declare methods: { + /** balance_of_private(owner: struct) */ + balance_of_private: (( + owner: AztecAddressLike + ) => ContractFunctionInteraction) & + Pick; + + /** balance_of_public(owner: struct) */ + balance_of_public: (( + owner: AztecAddressLike + ) => ContractFunctionInteraction) & + Pick; + + /** burn_private(from: struct, amount: field, nonce: field) */ + burn_private: (( + from: AztecAddressLike, + amount: FieldLike, + nonce: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** burn_public(from: struct, amount: field, nonce: field) */ + burn_public: (( from: AztecAddressLike, - to: AztecAddressLike, amount: FieldLike, + nonce: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** cancel_authwit(inner_hash: field) */ + cancel_authwit: ((inner_hash: FieldLike) => ContractFunctionInteraction) & + Pick; + + /** compute_note_hash_and_optionally_a_nullifier(contract_address: struct, nonce: field, storage_slot: field, note_type_id: field, compute_nullifier: boolean, serialized_note: array) */ + compute_note_hash_and_optionally_a_nullifier: (( + contract_address: AztecAddressLike, nonce: FieldLike, + storage_slot: FieldLike, + note_type_id: FieldLike, + compute_nullifier: boolean, + serialized_note: FieldLike[] + ) => ContractFunctionInteraction) & + Pick; + + /** constructor(admin: struct, name: string, symbol: string, decimals: integer) */ + constructor: (( + admin: AztecAddressLike, + name: string, + symbol: string, + decimals: bigint | number + ) => ContractFunctionInteraction) & + Pick; + + /** finalize_mint_to_private(amount: field, hiding_point_slot: field) */ + finalize_mint_to_private: (( + amount: FieldLike, + hiding_point_slot: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** finalize_transfer_to_private(amount: field, hiding_point_slot: field) */ + finalize_transfer_to_private: (( + amount: FieldLike, + hiding_point_slot: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** get_admin() */ + get_admin: (() => ContractFunctionInteraction) & + Pick; + + /** is_minter(minter: struct) */ + is_minter: ((minter: AztecAddressLike) => ContractFunctionInteraction) & + Pick; + + /** mint_to_private(from: struct, to: struct, amount: field) */ + mint_to_private: (( + from: AztecAddressLike, + to: AztecAddressLike, + amount: FieldLike ) => ContractFunctionInteraction) & - Pick; + Pick; - /** transfer(from: struct, to: struct, amount: field, nonce: field) */ + /** mint_to_public(to: struct, amount: field) */ + mint_to_public: (( + to: AztecAddressLike, + amount: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** prepare_transfer_to_private(to: struct) */ + prepare_transfer_to_private: (( + to: AztecAddressLike + ) => ContractFunctionInteraction) & + Pick; + + /** private_get_decimals() */ + private_get_decimals: (() => ContractFunctionInteraction) & + Pick; + + /** private_get_name() */ + private_get_name: (() => ContractFunctionInteraction) & + Pick; + + /** private_get_symbol() */ + private_get_symbol: (() => ContractFunctionInteraction) & + Pick; + + /** public_dispatch(selector: field) */ + public_dispatch: ((selector: FieldLike) => ContractFunctionInteraction) & + Pick; + + /** public_get_decimals() */ + public_get_decimals: (() => ContractFunctionInteraction) & + Pick; + + /** public_get_name() */ + public_get_name: (() => ContractFunctionInteraction) & + Pick; + + /** public_get_symbol() */ + public_get_symbol: (() => ContractFunctionInteraction) & + Pick; + + /** set_admin(new_admin: struct) */ + set_admin: ((new_admin: AztecAddressLike) => ContractFunctionInteraction) & + Pick; + + /** set_minter(minter: struct, approve: boolean) */ + set_minter: (( + minter: AztecAddressLike, + approve: boolean + ) => ContractFunctionInteraction) & + Pick; + + /** setup_refund(fee_payer: struct, user: struct, funded_amount: field, nonce: field) */ + setup_refund: (( + fee_payer: AztecAddressLike, + user: AztecAddressLike, + funded_amount: FieldLike, + nonce: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** total_supply() */ + total_supply: (() => ContractFunctionInteraction) & + Pick; + + /** transfer(to: struct, amount: field) */ transfer: (( + to: AztecAddressLike, + amount: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** transfer_in_private(from: struct, to: struct, amount: field, nonce: field) */ + transfer_in_private: (( from: AztecAddressLike, to: AztecAddressLike, amount: FieldLike, - nonce: FieldLike, + nonce: FieldLike ) => ContractFunctionInteraction) & - Pick; + Pick; - ... + /** transfer_in_public(from: struct, to: struct, amount: field, nonce: field) */ + transfer_in_public: (( + from: AztecAddressLike, + to: AztecAddressLike, + amount: FieldLike, + nonce: FieldLike + ) => ContractFunctionInteraction) & + Pick; + /** transfer_to_private(to: struct, amount: field) */ + transfer_to_private: (( + to: AztecAddressLike, + amount: FieldLike + ) => ContractFunctionInteraction) & + Pick; + + /** transfer_to_public(from: struct, to: struct, amount: field, nonce: field) */ + transfer_to_public: (( + from: AztecAddressLike, + to: AztecAddressLike, + amount: FieldLike, + nonce: FieldLike + ) => ContractFunctionInteraction) & + Pick; }; + + public static get events(): { + Transfer: { + abiType: AbiType; + eventSelector: EventSelector; + fieldNames: string[]; + }; + } { + return { + Transfer: { + abiType: { + fields: [ + { + name: "from", + type: { + fields: [ + { + name: "inner", + type: { + kind: "field", + }, + }, + ], + kind: "struct", + path: "authwit::aztec::protocol_types::address::aztec_address::AztecAddress", + }, + }, + { + name: "to", + type: { + fields: [ + { + name: "inner", + type: { + kind: "field", + }, + }, + ], + kind: "struct", + path: "authwit::aztec::protocol_types::address::aztec_address::AztecAddress", + }, + }, + { + name: "amount", + type: { + kind: "field", + }, + }, + ], + kind: "struct", + path: "Token::Transfer", + }, + eventSelector: EventSelector.fromSignature( + "Transfer((Field),(Field),Field)" + ), + fieldNames: ["from", "to", "amount"], + }, + }; + } } ``` diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md index 0e601ef307b..b002d3dd13f 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -77,24 +77,17 @@ In this situation, try to mark the public function as `internal`. This ensures y ### Moving public data into the private domain -Let's say you have some storage in public and want to move them into the private domain. If you pass your aztec address that should receive the data, then that leaks privacy (as everyone will know who has the private notes). So what do you do? - -1. You have to create a note in public domain and can't encrypt it, because you can't leak the public key of the receiver. -2. So how do you control who can claim this note? Pass a hash of a secret instead of the address. And then in the private domain, pass the preimage (the secret) to later claim your funds - -So you have to create a custom note in the public domain that is not encrypted by some owner - we call such notes a "TransparentNote" since it is created in public, anyone can see the amount and the note is not encrypted by some owner. +See [partial notes](../../../../../aztec/concepts/storage/partial_notes.md). Partial notes are how public balances are transferred to private [in the token contract](../../../../../tutorials/codealong/contract_tutorials/token_contract.md). ### Discovering my notes When you send someone a note, the note hash gets added to the note hash tree. To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: -1. When sending someone a note, use `encrypt_and_emit_note` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../how_to_emit_event.md) -2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`encrypt_and_emit_note` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public. +1. When sending someone a note, emit the note contents to the recipient (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../how_to_emit_event.md) +2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`encrypt_and_emit_note` shouldn't be called in the public domain because everything is public), like in the previous section where we created a note in public that doesn't have a designated owner. #include_code pxe_add_note yarn-project/end-to-end/src/composed/e2e_persistence.test.ts typescript -In the token contract, TransparentNotes are stored in a set called "pending_shields" which is in storage slot 5tutorials/tutorials/codealong/contract_tutorials/token_contract.md#contract-storage) - ### Revealing encrypted logs conditionally An encrypted log can contain any information for a recipient, typically in the form of a note. One could think this log is emitted as part of the transaction execution, so it wouldn't be revealed if the transaction fails. diff --git a/docs/docs/protocol-specs/gas-and-fees/tx-setup-and-teardown.md b/docs/docs/protocol-specs/gas-and-fees/tx-setup-and-teardown.md index b5b4783462c..8e5ef1e0468 100644 --- a/docs/docs/protocol-specs/gas-and-fees/tx-setup-and-teardown.md +++ b/docs/docs/protocol-specs/gas-and-fees/tx-setup-and-teardown.md @@ -52,7 +52,7 @@ Suppose there is a Fee Payment Contract (FPC) that has been deployed by another - Alice performs an arbitrary computation in public, potentially consuming DA and L2 gas. 5. Public teardown: - The FPC looks at `transaction_fee` to compute Alice's corresponding refund of BananaCoin. - - The FPC transfers the refund to Alice via a pending shield. + - The FPC transfers the refund to Alice via a partial note. 6. Base rollup: - The Base rollup kernel circuit injects a public data write that levies the transaction fee on the `fee_payer`. diff --git a/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md b/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md index 0cbbcf69ccb..72095bf8c31 100644 --- a/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md +++ b/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md @@ -2,6 +2,7 @@ title: Cheat Codes tags: [sandbox] --- + import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; ## Introduction @@ -525,17 +526,6 @@ Loads the value stored at the given slot in the private storage of the given con Note: One Field element occupies a storage slot. Hence, structs with multiple field elements will be spread over multiple sequential slots. Using loadPublic will only load a single field of the struct (depending on the size of the attributes within it). #### Example -```rust -#[storage] -struct Storage { - ... - pending_shields: PrivateSet, -} - -contract Token { - ... -} -``` #include_code load_private_cheatcode yarn-project/end-to-end/src/e2e_cheat_codes.test.ts typescript diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md b/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md index cfe794984f6..a2f84a70456 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md +++ b/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md @@ -184,7 +184,7 @@ Functionally similar to `get_note`, but executed unconstrained and can be used b You can view the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr). -And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for public -> private communication). +And can be added to the `Storage` struct as follows. Here adding a set for a custom note. #include_code storage-set-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -206,7 +206,7 @@ A hash of the note will be generated, and inserted into the note hash tree, allo ### `insert_from_public` -The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that have been initiated in public, such as shielding in the [token contract codealong tutorial](../../../../tutorials/codealong/contract_tutorials/token_contract.md). +The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that have been initiated in public. The usage is similar to using the `insert` method with the difference that this one is called in public functions. diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md b/docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md index d30597935f0..6ba216f1283 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md +++ b/docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md @@ -10,7 +10,7 @@ A typical example of shared state is some kind of system configuration, such as A naive way to solve this is to enqueue a public call that will assert the current public value, but this leaks _which_ public value is being read, severely reducing privacy. Even if the value itself is already public, the fact that we're using it because we're interacting with some related contract is not. For example, we may leak that we're interacting with a certain DeFi protocol by reading its fee. -An alternative approach is to create notes in public that are then nullified in private, but this introduces contention: only a single user may use the note and therefore read the state, since nullifying it will prevent all others from doing the same. In some schemes there's only one account that will read the state anyway (such as when shielding token balances), but this is not the general case. +An alternative approach is to create notes in public that are then nullified in private, but this introduces contention: only a single user may use the note and therefore read the state, since nullifying it will prevent all others from doing the same. In some schemes there's only one account that will read the state anyway, but this is not the general case. Shared state works around this by introducing **delays**: while public values are mutable, they cannot change _immediately_. Instead, a value change must be scheduled ahead of time, and some minimum amount of time must pass between the scheduling and the new value taking effect. This means that we can privately prove that a historical public value cannot possibly change before some point in the future (due to the minimum delay), and therefore that our transaction will be valid **as long as it gets included before this future time**. diff --git a/docs/docs/tutorials/codealong/aztecjs-getting-started.md b/docs/docs/tutorials/codealong/aztecjs-getting-started.md index 72168fc5da5..d4eeae0b976 100644 --- a/docs/docs/tutorials/codealong/aztecjs-getting-started.md +++ b/docs/docs/tutorials/codealong/aztecjs-getting-started.md @@ -83,6 +83,9 @@ yarn add @aztec/aztec.js @aztec/accounts @aztec/noir-contracts.js typescript @ty ```ts #include_code imports /yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts raw +#include_code token_utils /yarn-project/end-to-end/src/fixtures/token_utils.ts raw + +const { PXE_URL = 'http://localhost:8080' } = process.env; async function main() { #include_code setup /yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts raw @@ -176,8 +179,7 @@ We can break this down as follows: 3. We retrieve the transaction receipt containing the transaction status and contract address. 4. We connect to the contract with Alice 5. Alice initialize the contract with herself as the admin and a minter. -6. Alice mints 1,000,000 tokens to be claimed by herself in private. -7. Alice redeems the tokens privately. +6. Alice privately mints 1,000,000 tokens to herself ## View the balance of an account @@ -234,12 +236,12 @@ We can see that each account has the expected balance of tokens. ## Create and submit a transaction -Now lets transfer some funds from Alice to Bob by calling the `transfer` function on the contract. This function takes 4 arguments: +### Transfer + +Now lets transfer some funds from Alice to Bob by calling the `transfer` function on the contract. This function takes 2 arguments: -1. The sender. -2. The recipient. -3. The quantity of tokens to be transferred. -4. The nonce for the [authentication witness](../../aztec/concepts/accounts/index.md#authorizing-actions), or 0 if msg.sender equal sender. +1. The recipient. +2. The quantity of tokens to be transferred. Here is the Typescript code to call the `transfer` function, add this to your `index.ts` at the bottom of the `main` function: @@ -282,17 +284,18 @@ Our output should now look like this: Here, we used the same contract abstraction as was previously used for reading Alice's balance. But this time we called `send()` generating and sending a transaction to the network. After waiting for the transaction to settle we were able to check the new balance values. -Finally, the contract has 2 `mint` functions that can be used to generate new tokens for an account. +### Mint + +Finally, the contract has several `mint` functions that can be used to generate new tokens for an account. We will focus only on `mint_to_private`. -This function is public but it mints tokens privately. +This function has private and public execution components, but it mints tokens privately. This function takes: -1. A quantity of tokens to be minted. -2. A secret hash. - -This function is public and it inserts a new note into the note hash tree and increases the total token supply by the amount minted. +1. A minter (`from`) +2. A recipient +3. An amount of tokens to mint -To make the note spendable the note has to be redeemed. A user can do that by calling the `redeem_shield` function. +This function starts as private to set up the creation of a [partial note](../../aztec/concepts/storage/partial_notes.md). The private function calls a public function that checks that the minter is authorized to mint new tokens an increments the public total supply. The recipient of the tokens remains private, but the minter and the amount of tokens minted are public. Let's now use these functions to mint some tokens to Bob's account using Typescript, add this to `index.ts`: diff --git a/docs/docs/tutorials/codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md b/docs/docs/tutorials/codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md index 8effc323e74..194628c5877 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md +++ b/docs/docs/tutorials/codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md @@ -44,14 +44,10 @@ Now we will create a function to mint the amount privately. Paste this into your #include_code claim_private /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust -#include_code call_mint_on_token /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust - The `get_mint_to_private_content_hash` function is imported from the `token_portal_content_hash_lib`. If the content hashes were constructed similarly for `mint_to_private` and `mint_to_public`, then content intended for private execution could have been consumed by calling the `claim_public` method. By making these two content hashes distinct, we prevent this scenario. -While we mint the tokens on L2, we _still don’t actually mint them to a certain address_. Instead we continue to pass the `secret_hash_for_redeeming_minted_notes` like we did on L1. This means that a user could reveal their secret for L2 message consumption for anyone to mint tokens on L2 but they can redeem these notes at a later time. **This enables a paradigm where an app can manage user’s secrets for L2 message consumption on their behalf**. **The app or any external party can also mint tokens on the user’s behalf should they be comfortable with leaking the secret for L2 Message consumption.** This doesn’t leak any new information to the app because their smart contract on L1 knew that a user wanted to move some amount of tokens to L2. The app still doesn’t know which address on L2 the user wants these notes to be in, but they can mint tokens nevertheless on their behalf. - -To mint tokens privately, `claim_private` calls an internal function `_call_mint_on_token()` which then calls [token.mint_to_private()](../../token_contract.md#mint_to_private). +Note that the `TokenBridge` contract should be an authorized minter in the corresponding `Token` contract so that it is able to complete the private mint to the intended recipient. In the next step we will see how we can cancel a message. diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md b/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md index c94c39534e7..e272dbe5850 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md +++ b/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md @@ -65,35 +65,51 @@ There is one `initializer` function in this contract, and it will be selected an These are functions that have transparent logic, will execute in a publicly verifiable context and can update public storage. -- `set_admin` enables the admin to be updated -- `set_minter` enables accounts to be added / removed from the approved minter list -- `mint_to_public` enables tokens to be minted to the public balance of an account -- `mint_to_private` enables tokens to be minted to the private balance of an account (with some caveats we will dig into) -- `transfer_to_public` enables tokens to be moved from a public balance to a private balance, not necessarily the same account (step 1 of a 2 step process) -- `transfer_in_public` enables users to transfer tokens from one account's public balance to another account's public balance -- `burn_public` enables users to burn tokens +- [`set_admin`](#set_admin) enables the admin to be updated +- [`set_minter](#set_minter)` enables accounts to be added / removed from the approved minter list +- [`mint_to_public`](#mint_to_public) enables tokens to be minted to the public balance of an account +- [`transfer_in_public`](#transfer_in_public) enables users to transfer tokens from one account's public balance to another account's public balance +- [`burn_public`](#burn_public) enables users to burn tokens +- [`finalize_mint_to_private`](#finalize_mint_to_private) finalizes a `prepare_private_balance_increase` call +- [`finalize_transfer_to_private`](#finalize_transfer_to_private) finalizes a `prepare_private_balance_increase` call ### Private functions These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data commitments and nullifiers, so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. -- `transfer` enables an account to send tokens from their private balance to another account's private balance -- `transfer_in_private` enables an account to send tokens from another account's private balance to another account's private balance -- `cancel_authwit` enables an account to cancel an authorization to spend tokens -- `burn` enables tokens to be burned privately +- [`transfer`](#transfer) enables an account to send tokens from their private balance to another account's private balance +- [`transfer_in_private`](#transfer_in_private) enables an account to send tokens from another account's private balance to another account's private balance +- [`transfer_to_private`](#transfer_to_private) transfers a specified `amount` from an accounts public balance to a designated recipient. This flow starts in private, but will be completed in public. +- [`transfer_to_public`](#transfer_to_public) transfers tokens from a private balance, to a (potentially different account's) public balance +- [`mint_to_private`](#mint_to_private) enables an authorized minter to mint tokens to a specified address +- [`cancel_authwit`](#cancel_authwit) enables an account to cancel an authorization to spend tokens +- [`burn_private`](#burn_private) enables tokens to be burned privately +- [`setup_refund`](#setup_refund) allows users using a fee paying contract to receive unspent transaction fees +- [`prepare_private_balance_increase`](#prepare_private_balance_increase) is used to set up a [partial note](../../../aztec/concepts/storage/partial_notes.md) to be completed in public + +#### Private `view` functions + +These functions provide an interface to allow other contracts to read state variables in private: + +- `private_get_name` +- `private_get_symbol` +- `private_get_decimals` ### Internal functions Internal functions are functions that can only be called by the contract itself. These can be used when the contract needs to call one of it's public functions from one of it's private functions. -- `_increase_public_balance` increases the public balance of an account when `transfer_to_public` is called -- `_reduce_total_supply` reduces the total supply of tokens when a token is privately burned +- [`_increase_public_balance`](#_increase_public_balance) increases the public balance of an account when `transfer_to_public` is called +- [`_reduce_total_supply`](#_reduce_total_supply) reduces the total supply of tokens when a token is privately burned +- [`complete_refund`](#complete_refund) used in the fee payment flow. There is more detail on the [partial note](../../../aztec/concepts/storage/partial_notes.md#private-fee-payment-implementation) page. +- [`_finalize_transfer_to_private_unsafe`](#_finalize_transfer_to_private_unsafe) is the public component for finalizing a transfer from a public balance to private balance. It is considered `unsafe` because `from` is not enforced in this function, but it is in enforced the private function that calls this one (so it's safe). +- [`_finalize_mint_to_private_unsafe`](#_finalize_mint_to_private_unsafe) finalizes a private mint. Like the function above, it is considered `unsafe` because `from` is not enforced in this function, but it is in enforced the private function that calls this one (so it's safe). To clarify, let's review some details of the Aztec transaction lifecycle, particularly how a transaction "moves through" these contexts. #### Execution contexts -Transactions are initiated in the private context, then move to the L2 public context, then to the Ethereum L1 context. +Transactions are initiated in the private context (executed client-side), then move to the L2 public context (executed remotely by an Aztec sequencer), then to the Ethereum L1 context (executed by an Ethereum node). Step 1. Private Execution @@ -105,7 +121,7 @@ This happens remotely by the sequencer, which takes inputs from the private exec Step 3. Ethereum execution -Aztec transactions can pass data to Ethereum contracts through the rollup via the outbox. The data can consumed by Ethereum contracts at a later time, but this is not part of the transaction flow for an Aztec transaction. The technical details of this are beyond the scope of this tutorial, but we will cover them in an upcoming piece. +Aztec transactions can pass messages to Ethereum contracts through the rollup via the outbox. The data can be consumed by Ethereum contracts at a later time, but this is not part of the transaction flow for an Aztec transaction. The technical details of this are beyond the scope of this tutorial, but we will cover them in an upcoming piece. ### Unconstrained functions @@ -138,12 +154,12 @@ We are importing: We are also importing types from a `types.nr` file, which imports types from the `types` folder. You can view them [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src). -The main thing to note from this types folder is the `TransparentNote` definition. This defines how the contract moves value from the public domain into the private domain. It is similar to the `value_note` that we imported, but with some modifications namely, instead of a defined nullifier key, it allows anyone that can produce the pre-image to the stored `secret_hash` to spend the note. - -### Note on private state +:::note Private state in Aztec is all [UTXOs](../../../aztec/concepts/storage/index.md). +::: + ## Contract Storage Now that we have dependencies imported into our contract we can define the storage for the contract. @@ -175,7 +191,7 @@ This function sets the creator of the contract (passed as `msg_sender` from the Public functions are declared with the `#[public]` macro above the function name. -As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize prepared in a private context (partial notes flow). +As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize notes prepared in a private context ([partial notes flow](../../../aztec/concepts/storage/partial_notes.md)). Storage is referenced as `storage.variable`. @@ -199,33 +215,15 @@ First, storage is initialized. Then the function checks that the `msg_sender` is #include_code mint_to_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust -#### `mint_to_private` - -This public function allows an account approved in the public `minters` mapping to create new private tokens. - -First, partial note is prepared by the call to `_prepare_private_balance_increase` for the minted tokens recipient. Then a public call to `_finalize_mint_to_private_unsafe` is enqueued while `msg_sender`, `amount` and the `hiding_point_slot` are passed in via arguments. Since we set `from` to `msg_sender` here the usage of the unsafe function is safe. The enqueued call then checks the minter permissions of `from` and it finalizes the partial note for `to`. - -#include_code mint_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `transfer_to_private` - -This public function enables an account to send tokens from its `public_balance` to a private balance of an arbitrary recipient. - -First a partial note is prepared then a call to `_finalize_transfer_to_private_unsafe` is enqueued. The enqueued public call subtracts the `amount` from public balance of `msg_sender` and finalizes the partial note with the `amount`. - -#include_code transfer_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - #### `transfer_in_public` This public function enables public transfers between Aztec accounts. The sender's public balance will be debited the specified `amount` and the recipient's public balances will be credited with that amount. ##### Authorizing token spends -If the `msg_sender` is **NOT** the same as the account to debit from, the function checks that the account has authorized the `msg_sender` contract to debit tokens on its behalf. This check is done by computing the function selector that needs to be authorized (in this case, the `shield` function), computing the hash of the message that the account contract has approved. This is a hash of the contract that is approved to spend (`context.msg_sender`), the token contract that can be spent from (`context.this_address()`), the `selector`, the account to spend from (`from.address`), the `amount`, the `secret_hash` and a `nonce` to prevent multiple spends. This hash is passed to `assert_valid_public_message_for` to ensure that the Account Contract has approved tokens to be spent on it's behalf. +If the `msg_sender` is **NOT** the same as the account to debit from, the function checks that the account has authorized the `msg_sender` contract to debit tokens on its behalf. This check is done by computing the function selector that needs to be authorized, computing the hash of the message that the account contract has approved. This is a hash of the contract that is approved to spend (`context.msg_sender`), the token contract that can be spent from (`context.this_address()`), the `selector`, the account to spend from (`from`), the `amount` and a `nonce` to prevent multiple spends. This hash is passed to `assert_inner_hash_valid_authwit_public` to ensure that the Account Contract has approved tokens to be spent on it's behalf. -If the `msg_sender` is the same as the account to debit tokens from, the authorization check is bypassed and the function proceeds to update the account's `public_balance` and adds a new `TransparentNote` to the `pending_shields`. - -It returns `1` to indicate successful execution. +If the `msg_sender` is the same as the account to debit tokens from, the authorization check is bypassed and the function proceeds to update the account's `public_balance`. #include_code transfer_in_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust @@ -237,6 +235,18 @@ After storage is initialized, the [authorization flow specified above](#authoriz #include_code burn_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +#### `finalize_mint_to_private` + +This public function finalizes a transfer that has been set up by a call to `prepare_private_balance_increase` by reducing the public balance of the associated account and emitting the note for the intended recipient. + +#include_code finalize_mint_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `finalize_transfer_to_private` + +Similar to `finalize_mint_to_private`, this public function finalizes a transfer that has been set up by a call to `prepare_private_balance_increase` by reducing the public balance of the associated account and emitting the note for the intended recipient. + +#include_code finalize_transfer_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + ### Private function implementations Private functions are declared with the `#[private]` macro above the function name like so: @@ -254,7 +264,7 @@ Storage is referenced as `storage.variable`. This private function enables transferring of private balance (`UintNote` stored in `balances`) to any Aztec account's `public_balance`. -After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After the authorization check, the sender's private balance is decreased using the `decrement` helper function for the `value_note` library. Then it stages a public function call on this contract ([`_increase_public_balance`](#_increase_public_balance)) to be executed in the [public execution phase](#execution-contexts) of transaction execution. `_increase_public_balance` is marked as an `internal` function, so can only be called by this token contract. +After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_inner_hash_valid_authwit` in the authwit check is modified to work specifically in the private context. After the authorization check, the sender's private balance is decreased using the `decrement` helper function for the `value_note` library. Then it stages a public function call on this contract ([`_increase_public_balance`](#_increase_public_balance)) to be executed in the [public execution phase](#execution-contexts) of transaction execution. `_increase_public_balance` is marked as an `internal` function, so can only be called by this token contract. The function returns `1` to indicate successful execution. @@ -274,6 +284,26 @@ This private function enables an account to transfer tokens on behalf of another #include_code transfer_in_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +#### `transfer_to_private` + +This function execution flow starts in the private context and is completed with a call to a public internal function. It enables an account to send tokens from its `public_balance` to a private balance of an arbitrary recipient. + +First a partial note is prepared then a call to the public, internal `_finalize_transfer_to_private_unsafe` is enqueued. The enqueued public call subtracts the `amount` from public balance of `msg_sender` and finalizes the partial note with the `amount`. + +#include_code transfer_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `mint_to_private` + +This private function prepares a partial `UintNote` at the recipients storage slot in the contract and enqueues a public call to `_finalize_mint_to_private_unsafe`, which asserts that the `msg_sender` is an authorized minter and finalized the mint by incrementing the total supply and emitting the complete, encrypted `UintNote` to the intended recipient. Note that the `amount` and the minter (`from`) are public, but the recipient is private. + +#include_code mint_to_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `cancel_authwit` + +This private function allows a user to cancel an authwit that was previously granted. This is achieved by emitting the corresponding nullifier before it is used. + +#include_code cancel_authwit /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + #### `burn_private` This private function enables accounts to privately burn (destroy) tokens. @@ -282,6 +312,20 @@ After initializing storage, the function checks that the `msg_sender` is authori #include_code burn_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +#### `setup_refund` + +This private function may be called by a Fee Paying Contract (FPC) in order to allow users to pay transaction fees privately on the network. This function ensures that the user has enough funds in their account to pay the transaction fees for the transaction, sets up partial notes for paying the fees to the `fee_payer` and sending any unspent fees back to the user, and enqueues a call to the internal, public [`complete_refund`](#complete_refund) function to be run as part of the public execution step. + +#include_code setup_refund /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `prepare_private_balance_increase` + +TODO: update from `prepare_transfer_to_private` + +This private function prepares to transfer from a public balance to a private balance by setting up a partial note for the recipient. The function returns the `hiding_point_slot`. After this, the public [`finalize_transfer_to_private`](#finalize_transfer_to_private) must be called, passing the amount and the hiding point slot. + +#include_code prepare_private_balance_increase /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + ### Internal function implementations Internal functions are functions that can only be called by this contract. The following 3 functions are public functions that are called from the [private execution context](#execution-contexts). Marking these as `internal` ensures that only the desired private functions in this contract are able to call them. Private functions defer execution to public functions because private functions cannot update public state directly. @@ -298,6 +342,26 @@ This function is called from [`burn`](#burn). The account's private balance is d #include_code reduce_total_supply /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +#### `complete_refund` + +This public function is intended to be called during the public teardown at the end of public transaction execution. The call to this function is staged in [`setup_refund`](#setup_refund). This function ensures that the user has sufficient funds to cover the transaction costs and emits encrypted notes to the fee payer and the remaining, unused transaction fee back to the user. + +#include_code complete_refund /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `_finalize_transfer_to_private_unsafe` + +This public internal function decrements the public balance of the `from` account and finalizes the partial note for the recipient, which is hidden in the `hiding_point_slot`. + +This function is called by the private function [`transfer_to_private`](#transfer_to_private) to finalize the transfer. The `transfer_to_private` enforces the `from` argument, which is why using it `unsafe` is okay. + +#include_code finalize_transfer_to_private_unsafe /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `_finalize_mint_to_private_unsafe` + +Similar to `_finalize_transfer_to_private_unsafe`, this public internal function increments the private balance of the recipient by finalizing the partial note and emitting the encrypted note. It also increments the public total supply and ensures that the sender of the transaction is authorized to mint tokens on the contract. + +#include_code finalize_mint_to_private_unsafe /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + ### View function implementations View functions in Aztec are similar to `view` functions in Solidity in that they only return information from the contract storage or compute and return data without modifying contract storage. These functions are different from unconstrained functions in that the return values are constrained by their definition in the contract. @@ -365,8 +429,8 @@ It builds on the Token contract described here and goes into more detail about A ### Optional: Dive deeper into this contract and concepts mentioned here - Review [the end to end tests (Github link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/end-to-end/src/e2e_token_contract/) for reference. -- [Commitments (Wikipedia link)](https://en.wikipedia.org/wiki/Commitment_scheme) -- [Nullifiers](../../../aztec/concepts/storage/trees/index.md#nullifier-tree) -- [Public / Private function calls](../../../aztec/smart_contracts/functions/public_private_calls.md). -- [Contract Storage](../../../aztec/concepts/storage/index.md) -- [Authwit](../../../aztec/concepts/accounts/authwit.md) +- [Commitments (Wikipedia link)](https://en.wikipedia.org/wiki/Commitment_scheme) +- [Nullifiers](../../../aztec/concepts/storage/trees/index.md#nullifier-tree) +- [Public / Private function calls](../../../aztec/smart_contracts/functions/public_private_calls.md). +- [Contract Storage](../../../aztec/concepts/storage/index.md) +- [Authwit](../../../aztec/concepts/accounts/authwit.md) diff --git a/docs/docs/tutorials/examples/uniswap/l2_contract.md b/docs/docs/tutorials/examples/uniswap/l2_contract.md index f1f31104325..9d428e6332b 100644 --- a/docs/docs/tutorials/examples/uniswap/l2_contract.md +++ b/docs/docs/tutorials/examples/uniswap/l2_contract.md @@ -12,7 +12,6 @@ This page goes over the code in the L2 contract for Uniswap, which works alongsi #include_code uniswap_setup noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr rust We just need to store the portal address for the token that we want to swap. - ### Public swap #include_code swap_public noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr rust @@ -50,7 +49,7 @@ This flow works similarly to the public flow with a few notable changes: - In the public flow, the user calls `transfer_in_public()`. Here instead, the user calls `transfer_to_public()`. Why? The user can't directly transfer their private tokens (their notes) to the uniswap contract, because later the Uniswap contract has to approve the bridge to burn these notes and withdraw to L1. The authwit flow for the private domain requires a signature from the `sender`, which in this case would be the Uniswap contract. For the contract to sign, it would need a private key associated to it. But who would operate this key? - To work around this, the user can transfer to public their private tokens into Uniswap L2 contract. Transferring to public would convert user's private notes to public balance. It is a private method on the token contract that reduces a user’s private balance and then calls a public method to increase the recipient’s (ie Uniswap) public balance. **Remember that first all private methods are executed and then later all public methods will be - so the Uniswap contract won’t have the funds until public execution begins.** - Now uniswap has public balance (like with the public flow). Hence, `swap_private()` calls the internal public method which approves the input token bridge to burn Uniswap’s tokens and calls `exit_to_l1_public` to create an L2 → L1 message to exit to L1. -- Constructing the message content for swapping works exactly as the public flow except instead of specifying who would be the Aztec address that receives the swapped funds, we specify a secret hash (`secret_hash_for_redeeming_minted_notes`). Only those who know the preimage to the secret can later redeem the minted notes to themselves. +- Constructing the message content for swapping works exactly as the public flow except instead of specifying who would be the Aztec address that receives the swapped funds, we specify a secret hash. Only those who know the preimage to the secret can later redeem the minted notes to themselves. ### Approve the bridge to burn this contract's funds @@ -81,9 +80,3 @@ This method computes the L2 to L1 message content hash for the private. To find ## Redeeming assets So you emitted a message to withdraw input tokens to L1 and a message to swap. Then you or someone on your behalf can swap on L1 and emit a message to deposit swapped assets to L2. - -You still need to "claim" these swapped funds on L2. - -In the public flow, you can call [`claim_public()`](../../codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md) on the output token bridge which consumes the deposit message and mints your assets. - -In the private flow, you can choose to leak your secret for L1 → L2 message consumption to let someone mint the notes on L2 (by calling [`claim_private()`](../../codealong/contract_tutorials/advanced/token_bridge/2_minting_on_aztec.md) on the output token bridge) and then you can later redeem these notes to yourself by presenting the preimage to `secret_hash_for_redeeming_minted_notes` and calling the `redeem_shield()` method on the token contract. diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index e327690b2f1..e33553ba6b3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -444,6 +444,7 @@ contract Token { } // docs:end:transfer_to_private + // docs:start:prepare_private_balance_increase /// Prepares an increase of private balance of `to` (partial note). The increase needs to be finalized by calling /// some of the finalization functions (`finalize_transfer_to_private`, `finalize_mint_to_private`). /// Returns a hiding point slot. @@ -452,6 +453,7 @@ contract Token { let from = context.msg_sender(); _prepare_private_balance_increase(from, to, &mut context, storage) } + // docs:end:prepare_private_balance_increase /// This function exists separately from `prepare_private_balance_increase` solely as an optimization as it allows /// us to have it inlined in the `transfer_to_private` function which results in one less kernel iteration. @@ -504,6 +506,7 @@ contract Token { hiding_point_slot } + // docs:start:finalize_transfer_to_private /// Finalizes a transfer of token `amount` from public balance of `from` to a private balance of `to`. /// The transfer must be prepared by calling `prepare_private_balance_increase` first and the resulting /// `hiding_point_slot` must be passed as an argument to this function. @@ -512,7 +515,9 @@ contract Token { let from = context.msg_sender(); _finalize_transfer_to_private(from, amount, hiding_point_slot, &mut context, storage); } + // docs:end:finalize_transfer_to_private + // docs:start:finalize_transfer_to_private_unsafe #[public] #[internal] fn _finalize_transfer_to_private_unsafe( @@ -522,6 +527,7 @@ contract Token { ) { _finalize_transfer_to_private(from, amount, hiding_point_slot, &mut context, storage); } + // docs:end:finalize_transfer_to_private_unsafe #[contract_library_method] fn _finalize_transfer_to_private( @@ -569,6 +575,7 @@ contract Token { } // docs:end:mint_to_private + // docs:start:finalize_mint_to_private /// Finalizes a mint of token `amount` to a private balance of `to`. The mint must be prepared by calling /// `prepare_private_balance_increase` first and the resulting /// `hiding_point_slot` must be passed as an argument to this function. @@ -582,7 +589,9 @@ contract Token { _finalize_mint_to_private(amount, hiding_point_slot, &mut context, storage); } + // docs:end:finalize_mint_to_private + // docs:start:finalize_mint_to_private_unsafe #[public] #[internal] fn _finalize_mint_to_private_unsafe( @@ -594,6 +603,7 @@ contract Token { assert(storage.minters.at(from).read(), "caller is not minter"); _finalize_mint_to_private(amount, hiding_point_slot, &mut context, storage); } + // docs:end:finalize_mint_to_private_unsafe #[contract_library_method] fn _finalize_mint_to_private( diff --git a/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts b/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts index 9522bbf30ba..b2ed9d69432 100644 --- a/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts +++ b/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts @@ -5,10 +5,10 @@ import { Fr, GrumpkinScalar, type PXE, createDebugLogger, createPXEClient, waitF import { format } from 'util'; +// docs:end:imports import { deployToken, mintTokensToPrivate } from '../fixtures/token_utils.js'; const { PXE_URL = 'http://localhost:8080' } = process.env; -// docs:end:imports describe('e2e_sandbox_example', () => { it('sandbox example works', async () => { diff --git a/yarn-project/end-to-end/src/fixtures/token_utils.ts b/yarn-project/end-to-end/src/fixtures/token_utils.ts index 6769aae9daa..f623bcf3d5d 100644 --- a/yarn-project/end-to-end/src/fixtures/token_utils.ts +++ b/yarn-project/end-to-end/src/fixtures/token_utils.ts @@ -1,3 +1,4 @@ +// docs:start:token_utils import { type AztecAddress, type DebugLogger, type Wallet } from '@aztec/aztec.js'; import { TokenContract } from '@aztec/noir-contracts.js'; @@ -27,6 +28,7 @@ export async function mintTokensToPrivate( const from = minterWallet.getAddress(); // we are setting from to minter here because of TODO(#9887) await tokenAsMinter.methods.mint_to_private(from, recipient, amount).send().wait(); } +// docs:end:token_utils export async function expectTokenBalance( wallet: Wallet,