From 16b0e993bd7a729cbb9fb40bc88b31c78800a104 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 19 Sep 2023 15:06:56 +0000 Subject: [PATCH] refactor: not calling getContractDeploymentInfo twice when setting up account --- .../aztec.js/src/account/manager/index.ts | 57 +++++++------------ .../src/contract_deployer/deploy_method.ts | 8 +++ .../src/e2e_account_contracts.test.ts | 2 +- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/yarn-project/aztec.js/src/account/manager/index.ts b/yarn-project/aztec.js/src/account/manager/index.ts index 7c5d5ceecf3e..0b90e0d3b5cb 100644 --- a/yarn-project/aztec.js/src/account/manager/index.ts +++ b/yarn-project/aztec.js/src/account/manager/index.ts @@ -1,10 +1,10 @@ -import { Fr, PublicKey, getContractDeploymentInfo } from '@aztec/circuits.js'; +import { Fr, PublicKey } from '@aztec/circuits.js'; import { AztecRPC, CompleteAddress, GrumpkinPrivateKey } from '@aztec/types'; +import { DeploySentTx } from '../../contract_deployer/deploy_sent_tx.js'; import { AccountWallet, ContractDeployer, DeployMethod, WaitOpts, generatePublicKey } from '../../index.js'; import { AccountContract, Salt } from '../index.js'; import { AccountInterface } from '../interface.js'; -import { DeployAccountSentTx } from './deploy_account_sent_tx.js'; /** * Manages a user account. Provides methods for calculating the account's address, deploying the account contract, @@ -14,7 +14,7 @@ export class AccountManager { /** Deployment salt for the account contract. */ public readonly salt?: Fr; - private completeAddress?: Promise; + private completeAddress?: CompleteAddress; private encryptionPublicKey?: PublicKey; private deployMethod?: DeployMethod; @@ -25,7 +25,7 @@ export class AccountManager { saltOrAddress?: Salt | CompleteAddress, ) { if (saltOrAddress instanceof CompleteAddress) { - this.completeAddress = Promise.resolve(saltOrAddress); + this.completeAddress = saltOrAddress; } else { this.salt = saltOrAddress ? new Fr(saltOrAddress) : Fr.random(); } @@ -44,27 +44,18 @@ export class AccountManager { */ public async getAccount(): Promise { const nodeInfo = await this.rpc.getNodeInfo(); - const completeAddress = await this.getCompleteAddress(); + const completeAddress = this.getCompleteAddress(); return this.accountContract.getInterface(completeAddress, nodeInfo); } /** - * Gets the calculated complete address associated with this account. - * Does not require the account to be deployed or registered. - * @returns The address, partial address, and encryption public key. + * Gets the complete address associated with this account. + * @throws If the account contract has not been deployed yet. + * @returns The account's complete address. */ - public getCompleteAddress(): Promise { + public getCompleteAddress(): CompleteAddress { if (!this.completeAddress) { - this.completeAddress = (async () => { - const encryptionPublicKey = await generatePublicKey(this.encryptionPrivateKey); - const contractDeploymentInfo = await getContractDeploymentInfo( - this.accountContract.getContractAbi(), - await this.accountContract.getDeploymentArgs(), - this.salt!, - encryptionPublicKey, - ); - return contractDeploymentInfo.completeAddress; - })(); + throw new Error(`Cannot get complete address without first deploying the account contract.`); } return this.completeAddress; } @@ -79,18 +70,6 @@ export class AccountManager { return new AccountWallet(this.rpc, entrypoint); } - /** - * Registers this account in the RPC server and returns the associated wallet. Registering - * the account on the RPC server is required for managing private state associated with it. - * Use the returned wallet to create Contract instances to be interacted with from this account. - * @returns A Wallet instance. - */ - public async register(): Promise { - const completeAddress = await this.getCompleteAddress(); - await this.rpc.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); - 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 @@ -100,7 +79,6 @@ export class AccountManager { 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(); @@ -115,13 +93,18 @@ export class AccountManager { * Note that if the Account is constructed with an explicit complete address * it is assumed that the account contract has already been deployed and this method will throw. * Registers the account in the RPC server before deploying the contract. - * @returns A SentTx object that can be waited to get the associated Wallet. + * @returns A DeploySentTx object. */ - public async deploy(): Promise { + public async deploy(): Promise { + if (this.completeAddress) { + throw new Error(`Cannot deploy account contract when complete address is already set.`); + } const deployMethod = await this.getDeployMethod(); - const wallet = await this.getWallet(); - const sentTx = deployMethod.send({ contractAddressSalt: this.salt }); - return new DeployAccountSentTx(wallet, sentTx.getTxHash()); + const postDeploymentCallback = async (completeAddress: CompleteAddress) => { + this.completeAddress = completeAddress; + await this.rpc.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); + }; + return deployMethod.send({ contractAddressSalt: this.salt, postDeploymentCallback }); } /** diff --git a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts index 9e80b8d45a02..c76130053519 100644 --- a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts @@ -27,6 +27,10 @@ export interface DeployOptions extends SendMethodOptions { * An optional salt value used to deterministically calculate the contract address. */ contractAddressSalt?: Fr; + /** + * An optional callback function to register the deployed contract with the RPC server. + */ + postDeploymentCallback?: (completeAddress: CompleteAddress) => Promise; } /** @@ -105,6 +109,10 @@ export class DeployMethod extends Bas // TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined? await this.rpc.addContracts([{ abi: this.abi, completeAddress, portalContract }]); + if (options.postDeploymentCallback) { + await options.postDeploymentCallback(completeAddress); + } + return this.txRequest; } diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index e315c6ea8920..ebf3bccbde9a 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -89,7 +89,7 @@ describe('e2e_account_contracts', () => { address?: CompleteAddress, ) => { const account = new AccountManager(rpc, encryptionPrivateKey, accountContract, address); - const wallet = !address ? await account.deploy().then(tx => tx.getWallet()) : await account.getWallet(); + const wallet = !address ? await account.waitDeploy() : await account.getWallet(); return { account, wallet }; };