From d0a5b1912cf795519557a2f2659080f21be73d52 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:40:26 +0100 Subject: [PATCH] feat(AuthWit): simplify create authwit syntax (#5132) Fixes #4821 and #5075. Renames the functions related to `AuthWit` to use a similar naming scheme. Extends the `createAuthWit`, `setPublicAuthWit` and `cancelAuthWit` functions such that they can now take an object ```typescript { caller: AztecAddress; action: ContractFunctionInteraction | FunctionCall; }, ``` Allowing for adding a new authwit more simply. Example: ```typescript await user1Wallet.createAuthWit({ caller: l2Bridge.address, action: l2Token.methods.burn(ownerAddress, withdrawAmount, nonce) }); ``` --- .../resources/common_patterns/authwit.md | 6 +- docs/docs/developers/wallets/main.md | 2 +- noir-projects/aztec-nr/authwit/src/auth.nr | 4 +- .../src/defaults/account_interface.ts | 4 +- .../accounts/src/ecdsa/account_contract.ts | 2 +- .../accounts/src/schnorr/account_contract.ts | 2 +- .../src/single_key/account_contract.ts | 2 +- .../aztec.js/src/account/interface.ts | 20 ++- .../src/fee/private_fee_payment_method.ts | 2 +- .../src/fee/public_fee_payment_method.ts | 2 +- yarn-project/aztec.js/src/utils/authwit.ts | 10 +- .../aztec.js/src/wallet/account_wallet.ts | 85 ++++++++-- .../aztec.js/src/wallet/base_wallet.ts | 13 +- .../aztec.js/src/wallet/signerless_wallet.ts | 2 +- .../end-to-end/src/e2e_authwit.test.ts | 8 +- .../src/e2e_blacklist_token_contract.test.ts | 75 +++------ .../src/e2e_cross_chain_messaging.test.ts | 10 +- .../src/e2e_crowdfunding_and_claim.test.ts | 7 +- .../src/e2e_dapp_subscription.test.ts | 4 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 4 +- .../src/e2e_lending_contract.test.ts | 65 ++++---- .../e2e_public_cross_chain_messaging.test.ts | 2 +- .../end-to-end/src/e2e_token_contract.test.ts | 148 +++++++++++------- .../writing_an_account_contract.test.ts | 2 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 61 ++++---- .../entrypoints/src/account_entrypoint.ts | 4 +- .../entrypoints/src/dapp_entrypoint.ts | 2 +- 27 files changed, 325 insertions(+), 223 deletions(-) diff --git a/docs/docs/developers/contracts/resources/common_patterns/authwit.md b/docs/docs/developers/contracts/resources/common_patterns/authwit.md index bb3c5eb367a..10480a7de40 100644 --- a/docs/docs/developers/contracts/resources/common_patterns/authwit.md +++ b/docs/docs/developers/contracts/resources/common_patterns/authwit.md @@ -88,16 +88,12 @@ For our purposes here (not building a wallet), the most important part of the li ### General utilities -The primary general utility is the `compute_authwit_message_hash` function which computes the action hash from its components. This is useful for when you need to generate a hash that is not for the current call, such as when you want to update a public approval state value that is later used for [authentication in public](#updating-approval-state-in-noir). You can view the implementation of this function [here](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth.nr). +The primary general utility is the `compute_call_authwit_hash` function which computes the action hash from its components. This is useful for when you need to generate a hash that is not for the current call, such as when you want to update a public approval state value that is later used for [authentication in public](#updating-approval-state-in-noir). You can view the implementation of this function [here](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth.nr). #### TypeScript utilities To make it convenient to compute the message hashes in TypeScript, the `aztec.js` package includes a `computeAuthWitMessageHash` function that you can use. Implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/authwit.ts). -As you can see above, this function takes a `caller` and a `request`. The `request` can be easily prepared similarly to how we are making contract calls from TypeScript. - -#include_code authwit_computeAuthWitMessageHash /yarn-project/end-to-end/src/e2e_token_contract.test.ts typescript - ### Utilities for private calls For private calls where we allow execution on behalf of others, we generally want to check if the current call is authenticated by `on_behalf_of`. To easily do so, we can use the `assert_current_call_valid_authwit` which fetches information from the current context without us needing to provide much beyond the `on_behalf_of`. diff --git a/docs/docs/developers/wallets/main.md b/docs/docs/developers/wallets/main.md index 1e1b127ca7a..a35ce8a7f8f 100644 --- a/docs/docs/developers/wallets/main.md +++ b/docs/docs/developers/wallets/main.md @@ -44,7 +44,7 @@ There are no proofs generated as of the Sandbox release. This will be included i Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](../../learn/concepts/accounts/main.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. -Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWitness` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. +Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWit` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. ## Key management diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index e1904352cf2..e098fdd5fd7 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -27,14 +27,14 @@ pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_ } // docs:end:assert_current_call_valid_authwit_public -// docs:start:compute_authwit_message_hash +// docs:start:compute_call_authwit_hash // Compute the message hash to be used by an authentication witness pub fn compute_call_authwit_hash(caller: AztecAddress, consumer: AztecAddress, selector: FunctionSelector, args: [Field; N]) -> Field { let args_hash = hash_args(args); let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]); compute_outer_authwit_hash(consumer, inner_hash) } -// docs:end:compute_authwit_message_hash +// docs:end:compute_call_authwit_hash pub fn compute_inner_authwit_hash(args: [Field; N]) -> Field { pedersen_hash(args, GENERATOR_INDEX__AUTHWIT_INNER) diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index 16c93093328..f37833ea9a7 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -28,8 +28,8 @@ export class DefaultAccountInterface implements AccountInterface { return this.entrypoint.createTxExecutionRequest(executions, fee); } - createAuthWitness(message: Fr): Promise { - return this.authWitnessProvider.createAuthWitness(message); + createAuthWit(message: Fr): Promise { + return this.authWitnessProvider.createAuthWit(message); } getCompleteAddress(): CompleteAddress { diff --git a/yarn-project/accounts/src/ecdsa/account_contract.ts b/yarn-project/accounts/src/ecdsa/account_contract.ts index 250c1c0ce83..22c28d699a4 100644 --- a/yarn-project/accounts/src/ecdsa/account_contract.ts +++ b/yarn-project/accounts/src/ecdsa/account_contract.ts @@ -30,7 +30,7 @@ export class EcdsaAccountContract extends DefaultAccountContract { class EcdsaAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: Buffer) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const ecdsa = new Ecdsa(); const signature = ecdsa.constructSignature(message.toBuffer(), this.signingPrivateKey); return Promise.resolve(new AuthWitness(message, [...signature.r, ...signature.s])); diff --git a/yarn-project/accounts/src/schnorr/account_contract.ts b/yarn-project/accounts/src/schnorr/account_contract.ts index 38fc197b6d3..8e3f19c9154 100644 --- a/yarn-project/accounts/src/schnorr/account_contract.ts +++ b/yarn-project/accounts/src/schnorr/account_contract.ts @@ -30,7 +30,7 @@ export class SchnorrAccountContract extends DefaultAccountContract { class SchnorrAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: GrumpkinPrivateKey) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const schnorr = new Schnorr(); const signature = schnorr.constructSignature(message.toBuffer(), this.signingPrivateKey).toBuffer(); return Promise.resolve(new AuthWitness(message, [...signature])); diff --git a/yarn-project/accounts/src/single_key/account_contract.ts b/yarn-project/accounts/src/single_key/account_contract.ts index 4e7b70f3284..c790340266f 100644 --- a/yarn-project/accounts/src/single_key/account_contract.ts +++ b/yarn-project/accounts/src/single_key/account_contract.ts @@ -35,7 +35,7 @@ export class SingleKeyAccountContract extends DefaultAccountContract { class SingleKeyAuthWitnessProvider implements AuthWitnessProvider { constructor(private privateKey: GrumpkinPrivateKey, private partialAddress: PartialAddress) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const schnorr = new Schnorr(); const signature = schnorr.constructSignature(message.toBuffer(), this.privateKey); const publicKey = generatePublicKey(this.privateKey); diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 7f9ec40264b..7da5226b749 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -2,6 +2,7 @@ import { AuthWitness, CompleteAddress, FunctionCall, TxExecutionRequest } from ' import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; import { FeePaymentMethod } from '../fee/fee_payment_method.js'; /** @@ -18,10 +19,23 @@ export type FeeOptions = { /** Creates authorization witnesses. */ export interface AuthWitnessProvider { /** - * Create an authorization witness for the given message. - * @param message - Message to authorize. + * Computes an authentication witness from either a message hash or an intent (caller and an action). + * If a message hash is provided, it will create a witness for that directly. + * Otherwise, it will compute the message hash using the caller and the action of the intent. + * @param messageHashOrIntent - The message hash or the intent (caller and action) to approve + * @returns The authentication witness */ - createAuthWitness(message: Fr): Promise; + createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise; } /** Creates transaction execution requests out of a set of function calls. */ diff --git a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts index 5f6ebcfbd80..20be7695ccb 100644 --- a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts @@ -63,7 +63,7 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), to: this.asset, }); - await this.wallet.createAuthWitness(messageHash); + await this.wallet.createAuthWit(messageHash); const secretHashForRebate = computeMessageSecretHash(this.rebateSecret); diff --git a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts index 52342b0eb7c..bbc601d1505 100644 --- a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts @@ -61,7 +61,7 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { }); return Promise.resolve([ - this.wallet.setPublicAuth(messageHash, true).request(), + this.wallet.setPublicAuthWit(messageHash, true).request(), { to: this.getPaymentContract(), functionData: new FunctionData( diff --git a/yarn-project/aztec.js/src/utils/authwit.ts b/yarn-project/aztec.js/src/utils/authwit.ts index 865f278dfa5..2087730ca81 100644 --- a/yarn-project/aztec.js/src/utils/authwit.ts +++ b/yarn-project/aztec.js/src/utils/authwit.ts @@ -12,16 +12,16 @@ import { pedersenHash } from '@aztec/foundation/crypto'; * `bob` then signs the message hash and gives it to `alice` who can then perform the * action. * @param caller - The caller approved to make the call - * @param request - The request to be made (function call) + * @param action - The request to be made (function call) * @returns The message hash for the witness */ -export const computeAuthWitMessageHash = (caller: AztecAddress, request: FunctionCall) => { +export const computeAuthWitMessageHash = (caller: AztecAddress, action: FunctionCall) => { return computeOuterAuthWitHash( - request.to.toField(), + action.to.toField(), computeInnerAuthWitHash([ caller.toField(), - request.functionData.selector.toField(), - PackedArguments.fromArgs(request.args).hash, + action.functionData.selector.toField(), + PackedArguments.fromArgs(action.args).hash, ]), ); }; diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 5cbe9df38d3..10383dcea4c 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -1,9 +1,10 @@ import { AuthWitness, FunctionCall, PXE, TxExecutionRequest } from '@aztec/circuit-types'; -import { Fr } from '@aztec/circuits.js'; +import { AztecAddress, Fr } from '@aztec/circuits.js'; import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; import { AccountInterface, FeeOptions } from '../account/interface.js'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { computeAuthWitMessageHash } from '../utils/authwit.js'; import { BaseWallet } from './base_wallet.js'; /** @@ -18,21 +19,76 @@ export class AccountWallet extends BaseWallet { return this.account.createTxExecutionRequest(execs, fee); } - async createAuthWitness(message: Fr | Buffer): Promise { - message = Buffer.isBuffer(message) ? Fr.fromBuffer(message) : message; - const witness = await this.account.createAuthWitness(message); + /** + * Computes an authentication witness from either a message or a caller and an action. + * If a message is provided, it will create a witness for the message directly. + * Otherwise, it will compute the message using the caller and the action. + * @param messageHashOrIntent - The message or the caller and action to approve + * @returns The authentication witness + */ + async createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise { + const messageHash = this.getMessageHash(messageHashOrIntent); + const witness = await this.account.createAuthWit(messageHash); await this.pxe.addAuthWitness(witness); return witness; } /** - * Returns a function interaction to set a message hash as authorized in this account. + * Returns the message hash for the given message or authwit input. + * @param messageHashOrIntent - The message hash or the caller and action to authorize + * @returns The message hash + */ + private getMessageHash( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Fr { + if (Buffer.isBuffer(messageHashOrIntent)) { + return Fr.fromBuffer(messageHashOrIntent); + } else if (messageHashOrIntent instanceof Fr) { + return messageHashOrIntent; + } else if (messageHashOrIntent.action instanceof ContractFunctionInteraction) { + return computeAuthWitMessageHash(messageHashOrIntent.caller, messageHashOrIntent.action.request()); + } + return computeAuthWitMessageHash(messageHashOrIntent.caller, messageHashOrIntent.action); + } + + /** + * Returns a function interaction to set a message hash as authorized or revoked in this account. * Public calls can then consume this authorization. - * @param message - Message hash to authorize. + * @param messageHashOrIntent - The message or the caller and action to authorize/revoke * @param authorized - True to authorize, false to revoke authorization. * @returns - A function interaction. */ - public setPublicAuth(message: Fr | Buffer, authorized: boolean): ContractFunctionInteraction { + public setPublicAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + authorized: boolean, + ): ContractFunctionInteraction { + const message = this.getMessageHash(messageHashOrIntent); if (authorized) { return new ContractFunctionInteraction(this, this.getAddress(), this.getApprovePublicAuthwitAbi(), [message]); } else { @@ -42,10 +98,21 @@ export class AccountWallet extends BaseWallet { /** * Returns a function interaction to cancel a message hash as authorized in this account. - * @param message - Message hash to authorize. + * @param messageHashOrIntent - The message or the caller and action to authorize/revoke * @returns - A function interaction. */ - public cancelAuthWit(message: Fr | Buffer): ContractFunctionInteraction { + public cancelAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): ContractFunctionInteraction { + const message = this.getMessageHash(messageHashOrIntent); const args = [message]; return new ContractFunctionInteraction(this, this.getAddress(), this.getCancelAuthwitAbi(), args); } diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index f1cfa590f92..d6f88da973e 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -21,6 +21,7 @@ import { NodeInfo } from '@aztec/types/interfaces'; import { FeeOptions } from '../account/interface.js'; import { Wallet } from '../account/wallet.js'; +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; /** * A base class for Wallet implementations @@ -32,7 +33,17 @@ export abstract class BaseWallet implements Wallet { abstract createTxExecutionRequest(execs: FunctionCall[], fee?: FeeOptions): Promise; - abstract createAuthWitness(message: Fr): Promise; + abstract createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise; getAddress() { return this.getCompleteAddress().address; diff --git a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts index 135a3bc5b34..e99e383a757 100644 --- a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts @@ -31,7 +31,7 @@ export class SignerlessWallet extends BaseWallet { throw new Error('Method not implemented.'); } - createAuthWitness(_message: Fr): Promise { + createAuthWit(_message: Fr): Promise { throw new Error('Method not implemented.'); } } diff --git a/yarn-project/end-to-end/src/e2e_authwit.test.ts b/yarn-project/end-to-end/src/e2e_authwit.test.ts index bb45d12f586..8b9d57f5ab4 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -24,7 +24,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - const witness = await wallets[0].createAuthWitness(outerHash); + const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); @@ -36,7 +36,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - const witness = await wallets[0].createAuthWitness(outerHash); + const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); await wallets[0].cancelAuthWit(outerHash).send().wait(); @@ -55,7 +55,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x01')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - await wallets[0].setPublicAuth(outerHash, true).send().wait(); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); await c.withWallet(wallets[1]).methods.spend_public_authwit(innerHash).send().wait(); @@ -66,7 +66,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x02')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - await wallets[0].setPublicAuth(outerHash, true).send().wait(); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); await wallets[0].cancelAuthWit(outerHash).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts index 2d5bd054fa5..8d6e232fbb1 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts @@ -460,9 +460,8 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // docs:end:authwit_public_transfer_example // Perform the transfer @@ -519,10 +518,9 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); // We need to compute the message we want to sign and add it to the wallet as approved - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); @@ -542,9 +540,8 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -564,8 +561,7 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -636,10 +632,9 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); // docs:end:authwit_computeAuthWitMessageHash - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // docs:end:authwit_transfer_example await wallets[1].addCapsule( @@ -710,12 +705,10 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -770,10 +763,9 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await wallets[2].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -849,8 +841,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); const receipt = await action.send().wait(); @@ -901,8 +892,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -915,8 +905,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[2]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); @@ -968,12 +957,10 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await action.send().wait(); @@ -1035,12 +1022,10 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -1062,13 +1047,11 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await wallets[2].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -1127,8 +1110,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await action.send().wait(); @@ -1176,8 +1158,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -1190,8 +1171,7 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), @@ -1226,12 +1206,10 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), @@ -1281,12 +1259,10 @@ describe('e2e_blacklist_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), @@ -1324,10 +1300,9 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); const action = asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts index 6f965279378..8c68a9bd71f 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -100,12 +100,10 @@ describe('e2e_cross_chain_messaging', () => { // 4. Give approval to bridge to burn owner's funds: const withdrawAmount = 9n; const nonce = Fr.random(); - const burnMessageHash = computeAuthWitMessageHash( - l2Bridge.address, - l2Token.methods.burn(ownerAddress, withdrawAmount, nonce).request(), - ); - const witness = await user1Wallet.createAuthWitness(burnMessageHash); - await user1Wallet.addAuthWitness(witness); + await user1Wallet.createAuthWit({ + caller: l2Bridge.address, + action: l2Token.methods.burn(ownerAddress, withdrawAmount, nonce), + }); // docs:end:authwit_to_another_sc // 5. Withdraw owner's funds from L2 to L1 diff --git a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts index c92fdcf1a90..7b95950f124 100644 --- a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts +++ b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts @@ -9,7 +9,6 @@ import { Note, PXE, TxHash, - computeAuthWitMessageHash, computeMessageSecretHash, generatePublicKey, } from '@aztec/aztec.js'; @@ -198,8 +197,7 @@ describe('e2e_crowdfunding_and_claim', () => { const action = donationToken .withWallet(donorWallets[0]) .methods.transfer(donorWallets[0].getAddress(), crowdfundingContract.address, donationAmount, 0); - const messageHash = computeAuthWitMessageHash(crowdfundingContract.address, action.request()); - const witness = await donorWallets[0].createAuthWitness(messageHash); + const witness = await donorWallets[0].createAuthWit({ caller: crowdfundingContract.address, action }); await donorWallets[0].addAuthWitness(witness); } @@ -293,8 +291,7 @@ describe('e2e_crowdfunding_and_claim', () => { const action = donationToken .withWallet(donorWallets[1]) .methods.transfer(donorWallets[1].getAddress(), crowdfundingContract.address, donationAmount, 0); - const messageHash = computeAuthWitMessageHash(crowdfundingContract.address, action.request()); - const witness = await donorWallets[1].createAuthWitness(messageHash); + const witness = await donorWallets[1].createAuthWit({ caller: crowdfundingContract.address, action }); await donorWallets[1].addAuthWitness(witness); } diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index df9dfb64e20..1b793259c1a 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -6,7 +6,6 @@ import { PrivateFeePaymentMethod, PublicFeePaymentMethod, SentTx, - computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { DefaultDappEntrypoint } from '@aztec/entrypoints/dapp'; import { @@ -238,8 +237,7 @@ describe('e2e_dapp_subscription', () => { ) { const nonce = Fr.random(); const action = bananaCoin.methods.transfer(aliceAddress, bobAddress, SUBSCRIPTION_AMOUNT, nonce); - const messageHash = computeAuthWitMessageHash(subscriptionContract.address, action.request()); - await aliceWallet.createAuthWitness(messageHash); + await aliceWallet.createAuthWit({ caller: subscriptionContract.address, action }); return subscriptionContract .withWallet(aliceWallet) diff --git a/yarn-project/end-to-end/src/e2e_fees.test.ts b/yarn-project/end-to-end/src/e2e_fees.test.ts index 0a0064dbdbf..49309780080 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -670,7 +670,7 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { const tooMuchFee = new Fr(maxFee.toBigInt() * 2n); return Promise.resolve([ - this.wallet.setPublicAuth(messageHash, true).request(), + this.wallet.setPublicAuthWit(messageHash, true).request(), { to: this.getPaymentContract(), functionData: new FunctionData( @@ -698,7 +698,7 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { // authorize the FPC to take the maxFee // do this first because we only get 2 feepayload calls - await this.wallet.setPublicAuth(messageHash1, true).send().wait(); + await this.wallet.setPublicAuthWit(messageHash1, true).send().wait(); return Promise.resolve([ // in this, we're actually paying the fee in setup diff --git a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts index 10bae5d432e..1a29f947882 100644 --- a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts @@ -144,14 +144,10 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 : 💰 -> 🏦', async () => { const depositAmount = 420n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); - - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: collateralAsset.methods.unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPrivate(lendingAccount.address, lendingAccount.key(), depositAmount); @@ -177,13 +173,10 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 on behalf of recipient: 💰 -> 🏦', async () => { const depositAmount = 421n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: collateralAsset.methods.unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPrivate(lendingAccount.address, lendingAccount.address.toField(), depositAmount); @@ -210,15 +203,23 @@ describe('e2e_lending_contract', () => { const depositAmount = 211n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .transfer_public(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); // Add it to the wallet as approved - await wallet.setPublicAuth(messageHash, true).send().wait(); + await wallet + .setPublicAuthWit( + { + caller: lendingContract.address, + action: collateralAsset.methods.transfer_public( + lendingAccount.address, + lendingContract.address, + depositAmount, + nonce, + ), + }, + true, + ) + .send() + .wait(); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPublic(lendingAccount.address, lendingAccount.address.toField(), depositAmount); @@ -276,11 +277,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 : 🍌 -> 🏦', async () => { const repayAmount = 20n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPrivate(lendingAccount.address, lendingAccount.key(), repayAmount); @@ -301,11 +301,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 on behalf of public: 🍌 -> 🏦', async () => { const repayAmount = 21n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPrivate(lendingAccount.address, lendingAccount.address.toField(), repayAmount); @@ -333,7 +332,7 @@ describe('e2e_lending_contract', () => { ); // Add it to the wallet as approved - await wallet.setPublicAuth(messageHash, true).send().wait(); + await wallet.setPublicAuthWit(messageHash, true).send().wait(); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPublic(lendingAccount.address, lendingAccount.address.toField(), repayAmount); diff --git a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts index 1930fa216be..60469994cd6 100644 --- a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts @@ -110,7 +110,7 @@ describe('e2e_public_cross_chain_messaging', () => { l2Bridge.address, l2Token.methods.burn_public(ownerAddress, withdrawAmount, nonce).request(), ); - await user1Wallet.setPublicAuth(burnMessageHash, true).send().wait(); + await user1Wallet.setPublicAuthWit(burnMessageHash, true).send().wait(); // 5. Withdraw owner's funds from L2 to L1 const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount); diff --git a/yarn-project/end-to-end/src/e2e_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_token_contract.test.ts index 742a91b4be5..04420c05075 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract.test.ts @@ -336,9 +336,8 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // docs:end:authwit_public_transfer_example // Perform the transfer @@ -395,10 +394,9 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); // We need to compute the message we want to sign and add it to the wallet as approved - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); @@ -418,9 +416,8 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -440,8 +437,7 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -456,12 +452,56 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); const nonce = Fr.random(); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); + + await wallets[0].cancelAuthWit({ caller: accounts[1].address, action }).send().wait(); + + // Check that the authwit is no longer valid. Need to try to send since nullifiers are handled by sequencer. + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 2', async () => { + const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const nonce = Fr.random(); + + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, false).send().wait(); + + // Check that the authwit is no longer valid. Need to try to send since nullifiers are handled by sequencer. + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 3', async () => { + const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const nonce = Fr.random(); + const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit(messageHash, true).send().wait(); await wallets[0].cancelAuthWit(messageHash).send().wait(); @@ -524,10 +564,8 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // docs:end:authwit_computeAuthWitMessageHash - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // docs:end:authwit_transfer_example @@ -573,12 +611,11 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // Perform the transfer @@ -621,10 +658,9 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( @@ -643,12 +679,35 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); - await wallets[0].cancelAuthWit(messageHash).send().wait(); + await wallets[0].cancelAuthWit(witness.requestHash).send().wait(); + + // Perform the transfer, should fail because nullifier already emitted + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 2', async () => { + const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); + const amount = balance0 / 2n; + const nonce = Fr.random(); + expect(amount).toBeGreaterThan(0n); + + // We need to compute the message we want to sign and add it to the wallet as approved + const action = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); + + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); + await wallets[1].addAuthWitness(witness); + + await wallets[0].cancelAuthWit({ caller: accounts[1].address, action }).send().wait(); // Perform the transfer, should fail because nullifier already emitted const txCancelledAuthwit = asset @@ -707,8 +766,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); const receipt = await action.send().wait(); @@ -758,8 +816,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -772,8 +829,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[2]).methods.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); @@ -812,12 +868,10 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await action.send().wait(); @@ -862,12 +916,10 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); @@ -883,13 +935,11 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( @@ -918,8 +968,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await action.send().wait(); @@ -967,8 +1016,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -981,8 +1029,7 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), @@ -1008,12 +1055,10 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send().wait(); @@ -1051,12 +1096,10 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); @@ -1085,10 +1128,9 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( diff --git a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts index 01ddc35f00b..5501c8d9875 100644 --- a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts +++ b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts @@ -34,7 +34,7 @@ class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract { getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider { const privateKey = this.privateKey; return { - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const signer = new Schnorr(); const signature = signer.constructSignature(message.toBuffer(), privateKey); return Promise.resolve(new AuthWitness(message, [...signature.toBuffer()])); diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 740006650e5..d0bc6472b9b 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -203,13 +203,15 @@ export const uniswapL1L2TestSuite = ( // 3. Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(1n); - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. logger('Withdrawing weth to L1 and sending message to swap to dai'); @@ -345,7 +347,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // before swap - check nonce_for_burn_approval stored on uniswap // (which is used by uniswap to approve the bridge to burn funds on its behalf to exit to L1) @@ -373,7 +375,7 @@ export const uniswapL1L2TestSuite = ( nonceForSwap, ); const swapMessageHash = computeAuthWitMessageHash(sponsorAddress, action.request()); - await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // 4.2 Call swap_public from user2 on behalf of owner await action.send().wait(); @@ -488,13 +490,15 @@ export const uniswapL1L2TestSuite = ( // 2. owner gives uniswap approval to unshield funds: logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(3n); - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); // 3. Swap but send the wrong token address logger('Swap but send the wrong token address'); @@ -530,7 +534,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // No approval to call `swap` but should work even without it: const [_, secretHashForDepositingSwappedDai] = daiCrossChainHarness.generateClaimSecret(); @@ -578,7 +582,7 @@ export const uniswapL1L2TestSuite = ( nonceForSwap, ); const swapMessageHash = computeAuthWitMessageHash(approvedUser, action.request()); - await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // Swap! await expect(action.simulate()).rejects.toThrow( @@ -596,7 +600,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); await expect( uniswapL2Contract.methods @@ -628,14 +632,15 @@ export const uniswapL1L2TestSuite = ( // Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(4n); - - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); const wethL2BalanceBeforeSwap = await wethCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); // Swap @@ -691,7 +696,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // Call swap_public on L2 const secretHashForDepositingSwappedDai = Fr.random(); diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index ebb8f772d2b..c0c20c8089e 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -25,8 +25,8 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { const abi = this.getEntrypointAbi(); const entrypointPackedArgs = PackedArguments.fromArgs(encodeArguments(abi, [appPayload, feePayload])); - const appAuthWitness = await this.auth.createAuthWitness(hashPayload(appPayload, GeneratorIndex.SIGNATURE_PAYLOAD)); - const feeAuthWitness = await this.auth.createAuthWitness(hashPayload(feePayload, GeneratorIndex.FEE_PAYLOAD)); + const appAuthWitness = await this.auth.createAuthWit(hashPayload(appPayload, GeneratorIndex.SIGNATURE_PAYLOAD)); + const feeAuthWitness = await this.auth.createAuthWit(hashPayload(feePayload, GeneratorIndex.FEE_PAYLOAD)); const txRequest = TxExecutionRequest.from({ argsHash: entrypointPackedArgs.hash, diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 392d08512ba..877ba2a4a3d 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -34,7 +34,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { const innerHash = computeInnerAuthWitHash([Fr.ZERO, functionData.selector.toField(), entrypointPackedArgs.hash]); const outerHash = computeOuterAuthWitHash(this.dappEntrypointAddress, innerHash); - const authWitness = await this.userAuthWitnessProvider.createAuthWitness(outerHash); + const authWitness = await this.userAuthWitnessProvider.createAuthWit(outerHash); const txRequest = TxExecutionRequest.from({ argsHash: entrypointPackedArgs.hash,