Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

chore(tests): use new account class in e2e tests #1433

Merged
merged 2 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions yarn-project/aztec.js/src/account/account.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Fr, PublicKey, getContractDeploymentInfo } from '@aztec/circuits.js';
import { AztecRPC, PrivateKey } from '@aztec/types';

import { AccountWallet, ContractDeployer, WaitOpts, Wallet, generatePublicKey } from '../index.js';
import { AccountWallet, ContractDeployer, DeployMethod, WaitOpts, Wallet, generatePublicKey } from '../index.js';
import { CompleteAddress, isCompleteAddress } from './complete_address.js';
import { DeployAccountSentTx } from './deploy_account_sent_tx.js';
import { AccountContract, Salt } from './index.js';
import { AccountContract, Entrypoint, Salt } from './index.js';

/**
* Manages a user account. Provides methods for calculating the account's address, deploying the account contract,
Expand All @@ -16,6 +16,7 @@ export class Account {

private completeAddress?: CompleteAddress;
private encryptionPublicKey?: PublicKey;
private deployMethod?: DeployMethod;

constructor(
private rpc: AztecRPC,
Expand All @@ -37,6 +38,16 @@ export class Account {
return this.encryptionPublicKey;
}

/**
* Returns the entrypoint for this account as defined by its account contract.
* @returns An entrypoint.
*/
public async getEntrypoint(): Promise<Entrypoint> {
const nodeInfo = await this.rpc.getNodeInfo();
const completeAddress = await this.getCompleteAddress();
return this.accountContract.getEntrypoint(completeAddress, nodeInfo);
}

/**
* Gets the calculated complete address associated with this account.
* Does not require the account to be deployed or registered.
Expand All @@ -61,10 +72,8 @@ export class Account {
* @returns A Wallet instance.
*/
public async getWallet(): Promise<Wallet> {
const nodeInfo = await this.rpc.getNodeInfo();
const completeAddress = await this.getCompleteAddress();
const account = await this.accountContract.getEntrypoint(completeAddress, nodeInfo);
return new AccountWallet(this.rpc, account);
const entrypoint = await this.getEntrypoint();
return new AccountWallet(this.rpc, entrypoint);
}

/**
Expand All @@ -79,6 +88,24 @@ export class Account {
return this.getWallet();
}

/**
* Returns the pre-populated deployment method to deploy the account contract that backs this account.
* Typically you will not need this method and can call `deploy` directly. Use this for having finer
* grained control on when to create, simulate, and send the deployment tx.
* @returns A DeployMethod instance that deploys this account contract.
*/
public async getDeployMethod() {
if (!this.deployMethod) {
if (!this.salt) throw new Error(`Cannot deploy account contract without known salt.`);
await this.register();
const encryptionPublicKey = await this.getEncryptionPublicKey();
const deployer = new ContractDeployer(this.accountContract.getContractAbi(), this.rpc, encryptionPublicKey);
const args = await this.accountContract.getDeploymentArgs();
this.deployMethod = deployer.deploy(...args);
}
return this.deployMethod;
}

/**
* Deploys the account contract that backs this account.
* Uses the salt provided in the constructor or a randomly generated one.
Expand All @@ -88,12 +115,9 @@ export class Account {
* @returns A SentTx object that can be waited to get the associated Wallet.
*/
public async deploy(): Promise<DeployAccountSentTx> {
if (!this.salt) throw new Error(`Cannot deploy account contract without known salt.`);
const wallet = await this.register();
const encryptionPublicKey = await this.getEncryptionPublicKey();
const deployer = new ContractDeployer(this.accountContract.getContractAbi(), this.rpc, encryptionPublicKey);
const args = await this.accountContract.getDeploymentArgs();
const sentTx = deployer.deploy(...args).send({ contractAddressSalt: this.salt });
const deployMethod = await this.getDeployMethod();
const wallet = await this.getWallet();
const sentTx = deployMethod.send({ contractAddressSalt: this.salt });
return new DeployAccountSentTx(wallet, sentTx.getTxHash());
}

Expand All @@ -106,7 +130,7 @@ 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> {
public async waitDeploy(opts: WaitOpts = {}): Promise<Wallet> {
return (await this.deploy()).getWallet(opts);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AztecAddress } from '@aztec/circuits.js';
import { FunctionCall, TxExecutionRequest } from '@aztec/types';

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

/**
Expand All @@ -10,6 +11,25 @@ import { CreateTxRequestOpts, Entrypoint } from './index.js';
export class EntrypointCollection implements Entrypoint {
private entrypoints: Map<string, Entrypoint> = new Map();

constructor(entrypoints: [AztecAddress, Entrypoint][] = []) {
for (const [key, value] of entrypoints) {
this.registerAccount(key, value);
}
}

/**
* Creates a new instance out of a set of Accounts.
* @param accounts - Accounts to register in this entrypoint.
* @returns A new instance.
*/
static async fromAccounts(accounts: Account[]) {
const collection = new EntrypointCollection();
for (const account of accounts) {
collection.registerAccount((await account.getCompleteAddress()).address, await account.getEntrypoint());
}
return collection;
}

/**
* Registers an entrypoint against an aztec address
* @param addr - The aztec address agianst which to register the implementation.
Expand Down
8 changes: 4 additions & 4 deletions yarn-project/end-to-end/src/e2e_escrow_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ describe('e2e_escrow_contract', () => {

// Generate private key for escrow contract, register key in rpc server, and deploy
// Note that we need to register it first if we want to emit an encrypted note for it in the constructor
// TODO: We need a nicer interface for deploying contracts!
escrowPrivateKey = PrivateKey.random();
escrowPublicKey = await generatePublicKey(escrowPrivateKey);
const salt = Fr.random();
const deployInfo = await getContractDeploymentInfo(EscrowContractAbi, [owner], salt, escrowPublicKey);
await aztecRpcServer.addAccount(escrowPrivateKey, deployInfo.address, deployInfo.partialAddress);
const escrowDeployTx = EscrowContract.deployWithPublicKey(wallet, escrowPublicKey, owner);
await escrowDeployTx.send({ contractAddressSalt: salt }).wait();
escrowContract = await EscrowContract.create(escrowDeployTx.completeContractAddress!, wallet);

escrowContract = await EscrowContract.deployWithPublicKey(wallet, escrowPublicKey, owner)
.send({ contractAddressSalt: salt })
.deployed();
logger(`Escrow contract deployed at ${escrowContract.address}`);

// Deploy ZK token contract and mint funds for the escrow contract
Expand Down
40 changes: 10 additions & 30 deletions yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { AztecNodeService } from '@aztec/aztec-node';
import { AztecRPCServer } from '@aztec/aztec-rpc';
import { AztecAddress, StoredKeyAccountEntrypoint, Wallet, generatePublicKey } from '@aztec/aztec.js';
import { AztecAddress, Wallet, generatePublicKey, getSchnorrAccount } from '@aztec/aztec.js';
import { PrivateKey } from '@aztec/circuits.js';
import { Schnorr } from '@aztec/circuits.js/barretenberg';
import { DebugLogger } from '@aztec/foundation/log';
import { SchnorrMultiKeyAccountContractAbi } from '@aztec/noir-contracts/artifacts';
import { ZkTokenContract } from '@aztec/noir-contracts/types';
import { AztecRPC, TxStatus } from '@aztec/types';

import {
createNewAccount,
expectUnencryptedLogsFromLastBlockToBe,
expectsNumOfEncryptedLogsInTheLastBlockToBe,
setup,
Expand All @@ -31,28 +28,13 @@ describe('e2e_multiple_accounts_1_enc_key', () => {
({ aztecNode, aztecRpcServer, logger } = await setup(0));

const encryptionPrivateKey = PrivateKey.random();

for (let i = 0; i < numAccounts; i++) {
logger(`Deploying account contract ${i}/3...`);
const signingPrivateKey = PrivateKey.random();
const createWallet = async (address: AztecAddress, useProperKey: boolean) =>
new StoredKeyAccountEntrypoint(
address,
useProperKey ? signingPrivateKey : PrivateKey.random(),
await Schnorr.new(),
);

const schnorr = await Schnorr.new();
const signingPublicKey = schnorr.computePublicKey(signingPrivateKey);
const constructorArgs = [signingPublicKey.x, signingPublicKey.y];

const { wallet, address } = await createNewAccount(
aztecRpcServer,
SchnorrMultiKeyAccountContractAbi,
constructorArgs,
encryptionPrivateKey,
true,
createWallet,
);
const account = getSchnorrAccount(aztecRpcServer, encryptionPrivateKey, signingPrivateKey);
const wallet = await account.waitDeploy({ interval: 0.1 });
const { address } = await account.getCompleteAddress();
wallets.push(wallet);
accounts.push(address);
}
Expand All @@ -66,13 +48,11 @@ describe('e2e_multiple_accounts_1_enc_key', () => {
}

logger(`Deploying ZK Token...`);
const tx = ZkTokenContract.deploy(aztecRpcServer, initialBalance, accounts[0]).send();
const receipt = await tx.getReceipt();
zkTokenAddress = receipt.contractAddress!;
await tx.isMined({ interval: 0.1 });
const minedReceipt = await tx.getReceipt();
expect(minedReceipt.status).toEqual(TxStatus.MINED);
logger('ZK Token deployed');
zkTokenAddress = await ZkTokenContract.deploy(wallets[0], initialBalance, accounts[0])
.send()
.deployed()
.then(c => c.address);
logger(`ZK Token deployed at ${zkTokenAddress}`);
}, 100_000);

afterEach(async () => {
Expand Down
Loading