Skip to content

Commit

Permalink
chore(tests): Use account class for e2e browser tests (#1446)
Browse files Browse the repository at this point in the history
Use the `Account` class introduced in #1429 for the e2e browser tests.
This checks that the ABIs of the account contracts are properly packaged
by webpack. Also removes the usage of custom utils for creating and
retrieving wallets (we just need to remove them from the CLI now).
  • Loading branch information
spalladino authored Aug 8, 2023
1 parent 9bbe79e commit ff7ad30
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 61 deletions.
13 changes: 7 additions & 6 deletions yarn-project/aztec.js/src/account/account.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Fr, PublicKey, getContractDeploymentInfo } from '@aztec/circuits.js';
import { AztecRPC, PrivateKey } from '@aztec/types';

import { AccountWallet, ContractDeployer, DeployMethod, WaitOpts, Wallet, generatePublicKey } from '../index.js';
import { AccountWallet, ContractDeployer, DeployMethod, WaitOpts, generatePublicKey } from '../index.js';
import { CompleteAddress, isCompleteAddress } from './complete_address.js';
import { DeployAccountSentTx } from './deploy_account_sent_tx.js';
import { AccountContract, Entrypoint, Salt } from './index.js';
Expand Down Expand Up @@ -71,9 +71,9 @@ export class Account {
* instances to be interacted with from this account.
* @returns A Wallet instance.
*/
public async getWallet(): Promise<Wallet> {
public async getWallet(): Promise<AccountWallet> {
const entrypoint = await this.getEntrypoint();
return new AccountWallet(this.rpc, entrypoint);
return new AccountWallet(this.rpc, entrypoint, await this.getCompleteAddress());
}

/**
Expand All @@ -82,7 +82,7 @@ export class Account {
* Use the returned wallet to create Contract instances to be interacted with from this account.
* @returns A Wallet instance.
*/
public async register(): Promise<Wallet> {
public async register(): Promise<AccountWallet> {
const { address, partialAddress } = await this.getCompleteAddress();
await this.rpc.addAccount(this.encryptionPrivateKey, address, partialAddress);
return this.getWallet();
Expand Down Expand Up @@ -130,7 +130,8 @@ export class Account {
* @param opts - Options to wait for the tx to be mined.
* @returns A Wallet instance.
*/
public async waitDeploy(opts: WaitOpts = {}): Promise<Wallet> {
return (await this.deploy()).getWallet(opts);
public async waitDeploy(opts: WaitOpts = {}): Promise<AccountWallet> {
await this.deploy().then(tx => tx.wait(opts));
return this.getWallet();
}
}
36 changes: 35 additions & 1 deletion yarn-project/aztec.js/src/account/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AztecRPC, PrivateKey } from '@aztec/types';

import { Fr } from '../index.js';
import { AccountContract, AccountWallet, AztecAddress, Fr } from '../index.js';
import { Account } from './account.js';
import { CompleteAddress } from './complete_address.js';
import { EcdsaAccountContract } from './contract/ecdsa_account_contract.js';
Expand Down Expand Up @@ -65,3 +65,37 @@ export function getUnsafeSchnorrAccount(
saltOrAddress,
);
}

/**
* Gets a wallet for an already registered account using Schnorr signatures with a single key for encryption and authentication.
* @param rpc - An AztecRPC server instance.
* @param address - Address for the account.
* @param signingPrivateKey - Grumpkin key used for note encryption and signing transactions.
* @returns A wallet for this account that can be used to interact with a contract instance.
*/
export function getUnsafeSchnorrWallet(
rpc: AztecRPC,
address: AztecAddress,
signingKey: PrivateKey,
): Promise<AccountWallet> {
return getWallet(rpc, address, new SingleKeyAccountContract(signingKey));
}

/**
* Gets a wallet for an already registered account.
* @param rpc - An AztecRPC server instance.
* @param address - Address for the account.
* @param accountContract - Account contract implementation.
* * @returns A wallet for this account that can be used to interact with a contract instance.
*/
export async function getWallet(
rpc: AztecRPC,
address: AztecAddress,
accountContract: AccountContract,
): Promise<AccountWallet> {
const [publicKey, partialAddress] = await rpc.getPublicKeyAndPartialAddress(address);
const nodeInfo = await rpc.getNodeInfo();
const completeAddress: CompleteAddress = { publicKey, partialAddress, address };
const entrypoint = await accountContract.getEntrypoint(completeAddress, nodeInfo);
return new AccountWallet(rpc, entrypoint, completeAddress);
}
19 changes: 17 additions & 2 deletions yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@aztec/types';

import { CreateTxRequestOpts, Entrypoint } from '../account/entrypoint/index.js';
import { CompleteAddress } from '../index.js';

/**
* The wallet interface.
Expand Down Expand Up @@ -99,13 +100,27 @@ export abstract class BaseWallet implements Wallet {
}

/**
* A simple wallet implementation that forwards authentication requests to a provided account implementation.
* A simple wallet implementation that forwards authentication requests to a provided entrypoint implementation.
*/
export class AccountWallet extends BaseWallet {
export class EntrypointWallet extends BaseWallet {
constructor(rpc: AztecRPC, protected accountImpl: Entrypoint) {
super(rpc);
}
createTxExecutionRequest(executions: FunctionCall[], opts: CreateTxRequestOpts = {}): Promise<TxExecutionRequest> {
return this.accountImpl.createTxExecutionRequest(executions, opts);
}
}

/**
* A wallet implementation that forwards authentication requests to a provided account.
*/
export class AccountWallet extends EntrypointWallet {
constructor(rpc: AztecRPC, protected accountImpl: Entrypoint, protected address: CompleteAddress) {
super(rpc, accountImpl);
}

/** Returns the complete address of the account that implements this wallet. */
public getCompleteAddress() {
return this.address;
}
}
6 changes: 3 additions & 3 deletions yarn-project/aztec.js/src/utils/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createDebugLogger } from '@aztec/foundation/log';
import { AztecRPC, TxStatus } from '@aztec/types';

import { SingleKeyAccountEntrypoint } from '../account/entrypoint/single_key_account_entrypoint.js';
import { AccountWallet, Wallet } from '../aztec_rpc_client/wallet.js';
import { EntrypointWallet, Wallet } from '../aztec_rpc_client/wallet.js';
import { ContractDeployer, EntrypointCollection, generatePublicKey } from '../index.js';

/**
Expand Down Expand Up @@ -47,7 +47,7 @@ export async function createAccounts(
new SingleKeyAccountEntrypoint(address, deploymentInfo.partialAddress, privKey, await Schnorr.new()),
);
}
return new AccountWallet(aztecRpcClient, accountImpls);
return new EntrypointWallet(aztecRpcClient, accountImpls);
}

/**
Expand All @@ -71,5 +71,5 @@ export async function getAccountWallet(
address,
new SingleKeyAccountEntrypoint(address, deploymentInfo.partialAddress, privateKey, await Schnorr.new()),
);
return new AccountWallet(aztecRpcClient, accountCollection);
return new EntrypointWallet(aztecRpcClient, accountCollection);
}
85 changes: 38 additions & 47 deletions yarn-project/end-to-end/src/e2e_aztec_js_browser.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable no-console */
import * as AztecJs from '@aztec/aztec.js';
import { AztecAddress, PrivateKey } from '@aztec/circuits.js';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { PrivateTokenContractAbi, SchnorrSingleKeyAccountContractAbi } from '@aztec/noir-contracts/artifacts';
import { PrivateTokenContractAbi } from '@aztec/noir-contracts/artifacts';

import { Server } from 'http';
import Koa from 'koa';
Expand Down Expand Up @@ -33,6 +34,7 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
let contractAddress: AztecAddress;

let logger: DebugLogger;
let pageLogger: DebugLogger;
let app: Koa;
let testClient: AztecJs.AztecRPC;
let server: Server;
Expand All @@ -50,6 +52,7 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
});

logger = createDebugLogger('aztec:aztec.js:web');
pageLogger = createDebugLogger('aztec:aztec.js:web:page');

browser = await launch({
executablePath: process.env.CHROME_BIN,
Expand All @@ -68,10 +71,10 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
});
page = await browser.newPage();
page.on('console', msg => {
logger('PAGE MSG:', msg.text());
pageLogger(msg.text());
});
page.on('pageerror', err => {
logger('PAGE ERROR:', err.toString());
pageLogger.error(err.toString());
});
await page.goto(`http://localhost:${PORT}/index.html`);
});
Expand All @@ -88,21 +91,20 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
});
expect(createAccountsExists).toBe(true);
});

it('Creates an account', async () => {
const result = await page.evaluate(
async (rpcUrl, privateKey, schnorrAbi) => {
const { Fr, PrivateKey, createAztecRpcClient, createAccounts, mustSucceedFetch } = window.AztecJs;
async (rpcUrl, privateKeyString) => {
const { PrivateKey, createAztecRpcClient, mustSucceedFetch, getUnsafeSchnorrAccount } = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, mustSucceedFetch);

await createAccounts(client, schnorrAbi, PrivateKey.fromString(privateKey)!, Fr.ZERO);
const privateKey = PrivateKey.fromString(privateKeyString);
await getUnsafeSchnorrAccount(client, privateKey).waitDeploy();
const accounts = await client.getAccounts();
// eslint-disable-next-line no-console
console.log(`Created Account: ${accounts[0].toString()}`);
return accounts[0].toString();
},
SANDBOX_URL,
privKey.toString(),
SchnorrSingleKeyAccountContractAbi,
);
const account = (await testClient.getAccounts())[0];
expect(result).toEqual(account.toString());
Expand All @@ -115,11 +117,10 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
const client = createAztecRpcClient(rpcUrl!, mustSucceedFetch);
const owner = (await client.getAccounts())[0];
const publicKey = await client.getPublicKey(owner);
const tx = new DeployMethod(publicKey, client, PrivateTokenContractAbi, [33n, owner]).send();
await tx.isMined();
// eslint-disable-next-line no-console
console.log('Contract Deployed');
const tx = new DeployMethod(publicKey, client, PrivateTokenContractAbi, [initialBalance, owner]).send();
await tx.wait();
const receipt = await tx.getReceipt();
console.log(`Contract Deployed: ${receipt.contractAddress}`);
return receipt.txHash.toString();
},
SANDBOX_URL,
Expand All @@ -134,17 +135,13 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {

it("Gets the owner's balance", async () => {
const result = await page.evaluate(
async (rpcUrl, privateKey, SchnorrSingleKeyAccountContractAbi, contractAddress, PrivateTokenContractAbi) => {
const { Contract, AztecAddress, Fr, PrivateKey, createAztecRpcClient, getAccountWallet, mustSucceedFetch } =
async (rpcUrl, privateKeyString, contractAddress, PrivateTokenContractAbi) => {
const { Contract, AztecAddress, PrivateKey, createAztecRpcClient, getUnsafeSchnorrWallet, mustSucceedFetch } =
window.AztecJs;
const privateKey = PrivateKey.fromString(privateKeyString);
const client = createAztecRpcClient(rpcUrl!, mustSucceedFetch);
const owner = (await client.getAccounts())[0];
const wallet = await getAccountWallet(
client,
SchnorrSingleKeyAccountContractAbi,
PrivateKey.fromString(privateKey!),
Fr.ZERO,
);
const [owner] = await client.getAccounts();
const wallet = await getUnsafeSchnorrWallet(client, owner, privateKey);
const contract = await Contract.create(
AztecAddress.fromString(contractAddress),
PrivateTokenContractAbi,
Expand All @@ -155,7 +152,6 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
},
SANDBOX_URL,
privKey.toString(),
SchnorrSingleKeyAccountContractAbi,
contractAddress.toString(),
PrivateTokenContractAbi,
);
Expand All @@ -165,35 +161,31 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {

it('Sends a transfer TX', async () => {
const result = await page.evaluate(
async (
rpcUrl,
privateKey,
contractAddress,
transferAmount,
PrivateTokenContractAbi,
SchnorrSingleKeyAccountContractAbi,
) => {
const { AztecAddress, Contract, Fr, PrivateKey, createAztecRpcClient, getAccountWallet, mustSucceedFetch } =
window.AztecJs;
async (rpcUrl, privateKeyString, contractAddress, transferAmount, PrivateTokenContractAbi) => {
console.log(`Starting transfer tx`);
const {
AztecAddress,
Contract,
PrivateKey,
createAztecRpcClient,
getUnsafeSchnorrAccount,
getUnsafeSchnorrWallet,
mustSucceedFetch,
} = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, mustSucceedFetch);
await AztecJs.createAccounts(client, SchnorrSingleKeyAccountContractAbi, PrivateKey.random(), Fr.random());
const [owner, receiver] = await client.getAccounts();
// eslint-disable-next-line no-console
const privateKey = PrivateKey.fromString(privateKeyString);
const { address: receiver } = await getUnsafeSchnorrAccount(client, PrivateKey.random())
.register()
.then(w => w.getCompleteAddress());
console.log(`Created 2nd Account: ${receiver.toString()}`);
const wallet = await getAccountWallet(
client,
SchnorrSingleKeyAccountContractAbi,
PrivateKey.fromString(privateKey!),
Fr.ZERO,
);
const [owner] = await client.getAccounts();
const wallet = await getUnsafeSchnorrWallet(client, owner, privateKey);
const contract = await Contract.create(
AztecAddress.fromString(contractAddress),
PrivateTokenContractAbi,
wallet,
);
const tx = contract.methods.transfer(transferAmount, owner, receiver).send({ origin: owner });
await tx.isMined();
// eslint-disable-next-line no-console
await contract.methods.transfer(transferAmount, owner, receiver).send({ origin: owner }).wait();
console.log(`Transfered ${transferAmount} tokens to new Account`);
const [balance] = await contract.methods.getBalance(receiver).view({ from: receiver });
return balance;
Expand All @@ -203,8 +195,7 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
contractAddress.toString(),
transferAmount,
PrivateTokenContractAbi,
SchnorrSingleKeyAccountContractAbi,
);
expect(result).toEqual(transferAmount);
}, 45_000);
}, 60_000);
});
4 changes: 2 additions & 2 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
import { RpcServerConfig, createAztecRPCServer, getConfigEnvVars as getRpcConfigEnvVars } from '@aztec/aztec-rpc';
import {
AccountWallet,
Account as AztecAccount,
AztecAddress,
Contract,
ContractDeployer,
EntrypointCollection,
EntrypointWallet,
EthAddress,
Wallet,
createAztecRpcClient as createJsonRpcClient,
Expand Down Expand Up @@ -168,7 +168,7 @@ export async function setupAztecRPCServer(
await Promise.all(txs.map(tx => tx.wait({ interval: 0.1 })));

// Assemble them into a single wallet
const wallet = new AccountWallet(aztecRpcServer, await EntrypointCollection.fromAccounts(accounts));
const wallet = new EntrypointWallet(aztecRpcServer, await EntrypointCollection.fromAccounts(accounts));

return {
aztecRpcServer: aztecRpcServer!,
Expand Down

0 comments on commit ff7ad30

Please sign in to comment.