diff --git a/yarn-project/aztec-sandbox/src/examples/util.ts b/yarn-project/aztec-sandbox/src/examples/util.ts index d3462673cce..581e16514fd 100644 --- a/yarn-project/aztec-sandbox/src/examples/util.ts +++ b/yarn-project/aztec-sandbox/src/examples/util.ts @@ -46,13 +46,9 @@ export async function deployAndInitializeNonNativeL2TokenContracts( }); // deploy l2 contract and attach to portal - const tx = NonNativeTokenContract.deploy(wallet, initialBalance, owner).send({ - portalContract: tokenPortalAddress, - }); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); - const l2Contract = await NonNativeTokenContract.at(receipt.contractAddress!, wallet); - await l2Contract.attach(tokenPortalAddress); + const l2Contract = await NonNativeTokenContract.deploy(wallet, initialBalance, owner) + .send({ portalContract: tokenPortalAddress }) + .deployed(); const l2TokenAddress = l2Contract.address.toString() as `0x${string}`; // initialize portal diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 3faef893055..541a9c588b7 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -1,17 +1,7 @@ import { AztecAddress, CompleteAddress, EthAddress } from '@aztec/circuits.js'; import { L1ContractAddresses } from '@aztec/ethereum'; import { ABIParameterVisibility, ContractAbi, FunctionType } from '@aztec/foundation/abi'; -import { - DeployedContract, - ExtendedContractData, - NodeInfo, - Tx, - TxExecutionRequest, - TxHash, - TxReceipt, - randomContractAbi, - randomDeployedContract, -} from '@aztec/types'; +import { ExtendedContractData, NodeInfo, Tx, TxExecutionRequest, TxHash, TxReceipt } from '@aztec/types'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -155,27 +145,4 @@ describe('Contract Class', () => { expect(() => fooContract.methods.bar().view()).toThrow(); expect(() => fooContract.methods.baz().view()).toThrow(); }); - - it('should add contract and dependencies to PXE', async () => { - const entry: DeployedContract = { - abi: randomContractAbi(), - completeAddress: resolvedExtendedContractData.getCompleteAddress(), - portalContract: EthAddress.random(), - }; - const contract = await Contract.at(entry.completeAddress.address, entry.abi, wallet); - - { - await contract.attach(entry.portalContract); - expect(wallet.addContracts).toHaveBeenCalledTimes(1); - expect(wallet.addContracts).toHaveBeenCalledWith([entry]); - wallet.addContracts.mockClear(); - } - - { - const dependencies = [await randomDeployedContract(), await randomDeployedContract()]; - await contract.attach(entry.portalContract, dependencies); - expect(wallet.addContracts).toHaveBeenCalledTimes(1); - expect(wallet.addContracts).toHaveBeenCalledWith([entry, ...dependencies]); - } - }); }); diff --git a/yarn-project/aztec.js/src/contract/contract.ts b/yarn-project/aztec.js/src/contract/contract.ts index 4fa1a4f9ff7..9249184c491 100644 --- a/yarn-project/aztec.js/src/contract/contract.ts +++ b/yarn-project/aztec.js/src/contract/contract.ts @@ -19,6 +19,7 @@ export class Contract extends ContractBase { * @param address - The deployed contract's address. * @param abi - The Application Binary Interface for the contract. * @param wallet - The wallet to use when interacting with the contract. + * @param portalContract - The portal contract address on L1, if any. * @returns A promise that resolves to a new Contract instance. */ public static async at(address: AztecAddress, abi: ContractAbi, wallet: Wallet): Promise { @@ -26,7 +27,12 @@ export class Contract extends ContractBase { if (extendedContractData === undefined) { throw new Error('Contract ' + address.toString() + ' is not deployed'); } - return new Contract(extendedContractData.getCompleteAddress(), abi, wallet); + return new Contract( + extendedContractData.getCompleteAddress(), + abi, + wallet, + extendedContractData.contractData.portalContractAddress, + ); } /** diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index b408d386bf5..4ac143fc47a 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -19,25 +19,21 @@ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & /** * Abstract implementation of a contract extended by the Contract class and generated contract types. */ -export class ContractBase { +export class ContractBase implements DeployedContract { /** * An object containing contract methods mapped to their respective names. */ public methods: { [name: string]: ContractMethod } = {}; protected constructor( - /** - * The deployed contract's complete address. - */ + /** The deployed contract's complete address. */ public readonly completeAddress: CompleteAddress, - /** - * The Application Binary Interface for the contract. - */ + /** The Application Binary Interface for the contract. */ public readonly abi: ContractAbi, - /** - * The wallet. - */ + /** The wallet used for interacting with this contract. */ protected wallet: Wallet, + /** The portal contract address on L1, if any. */ + public readonly portalContract: EthAddress, ) { abi.functions.forEach((f: FunctionAbi) => { const interactionFunction = (...args: any[]) => { @@ -69,24 +65,6 @@ export class ContractBase { * @returns A new contract instance. */ public withWallet(wallet: Wallet): this { - return new ContractBase(this.completeAddress, this.abi, wallet) as this; - } - - /** - * Attach the current contract instance to a portal contract and optionally add its dependencies. - * The function will return a promise that resolves when all contracts have been added to the PXE. - * This is useful when you need to interact with a deployed contract that has multiple nested contracts. - * - * @param portalContract - The Ethereum address of the portal contract. - * @param dependencies - An optional array of additional DeployedContract instances to be attached. - * @returns A promise that resolves when all contracts are successfully added to the PXE. - */ - public attach(portalContract: EthAddress, dependencies: DeployedContract[] = []) { - const deployedContract: DeployedContract = { - abi: this.abi, - completeAddress: this.completeAddress, - portalContract, - }; - return this.wallet.addContracts([deployedContract, ...dependencies]); + return new ContractBase(this.completeAddress, this.abi, wallet, this.portalContract) as this; } } diff --git a/yarn-project/aztec.js/src/contract_deployer/deploy_sent_tx.ts b/yarn-project/aztec.js/src/contract_deployer/deploy_sent_tx.ts index a442f3bee3c..8b0fc0a2a0f 100644 --- a/yarn-project/aztec.js/src/contract_deployer/deploy_sent_tx.ts +++ b/yarn-project/aztec.js/src/contract_deployer/deploy_sent_tx.ts @@ -19,7 +19,7 @@ export type DeployTxReceipt = FieldsO /** * A contract deployment transaction sent to the network, extending SentTx with methods to create a contract instance. */ -export class DeploySentTx extends SentTx { +export class DeploySentTx extends SentTx { constructor(private abi: ContractAbi, wallet: PXE | Wallet, txHashPromise: Promise) { super(wallet, txHashPromise); } diff --git a/yarn-project/boxes/blank-react/src/artifacts/blank.ts b/yarn-project/boxes/blank-react/src/artifacts/blank.ts index 75cba5b04dd..672d4ba566a 100644 --- a/yarn-project/boxes/blank-react/src/artifacts/blank.ts +++ b/yarn-project/boxes/blank-react/src/artifacts/blank.ts @@ -4,10 +4,12 @@ import { AztecAddress, CompleteAddress, + Contract, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, + EthAddress, FieldLike, AztecAddressLike, EthAddressLike, @@ -23,13 +25,8 @@ export const BlankContractAbi = BlankContractAbiJson as ContractAbi; * Type-safe interface for contract Blank; */ export class BlankContract extends ContractBase { - private constructor( - /** The deployed contract's complete address. */ - completeAddress: CompleteAddress, - /** The wallet. */ - wallet: Wallet, - ) { - super(completeAddress, BlankContractAbi, wallet); + private constructor(completeAddress: CompleteAddress, wallet: Wallet, portalContract = EthAddress.ZERO) { + super(completeAddress, BlankContractAbi, wallet, portalContract); } /** @@ -38,17 +35,8 @@ export class BlankContract extends ContractBase { * @param wallet - The wallet to use when interacting with the contract. * @returns A promise that resolves to a new Contract instance. */ - public static async at( - /** The deployed contract's address. */ - address: AztecAddress, - /** The wallet. */ - wallet: Wallet, - ) { - const extendedContractData = await wallet.getExtendedContractData(address); - if (extendedContractData === undefined) { - throw new Error('Contract ' + address.toString() + ' is not deployed'); - } - return new BlankContract(extendedContractData.getCompleteAddress(), wallet); + public static async at(address: AztecAddress, wallet: Wallet) { + return Contract.at(address, BlankContract.abi, wallet) as Promise; } /** diff --git a/yarn-project/boxes/blank/src/artifacts/blank.ts b/yarn-project/boxes/blank/src/artifacts/blank.ts index 75cba5b04dd..672d4ba566a 100644 --- a/yarn-project/boxes/blank/src/artifacts/blank.ts +++ b/yarn-project/boxes/blank/src/artifacts/blank.ts @@ -4,10 +4,12 @@ import { AztecAddress, CompleteAddress, + Contract, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, + EthAddress, FieldLike, AztecAddressLike, EthAddressLike, @@ -23,13 +25,8 @@ export const BlankContractAbi = BlankContractAbiJson as ContractAbi; * Type-safe interface for contract Blank; */ export class BlankContract extends ContractBase { - private constructor( - /** The deployed contract's complete address. */ - completeAddress: CompleteAddress, - /** The wallet. */ - wallet: Wallet, - ) { - super(completeAddress, BlankContractAbi, wallet); + private constructor(completeAddress: CompleteAddress, wallet: Wallet, portalContract = EthAddress.ZERO) { + super(completeAddress, BlankContractAbi, wallet, portalContract); } /** @@ -38,17 +35,8 @@ export class BlankContract extends ContractBase { * @param wallet - The wallet to use when interacting with the contract. * @returns A promise that resolves to a new Contract instance. */ - public static async at( - /** The deployed contract's address. */ - address: AztecAddress, - /** The wallet. */ - wallet: Wallet, - ) { - const extendedContractData = await wallet.getExtendedContractData(address); - if (extendedContractData === undefined) { - throw new Error('Contract ' + address.toString() + ' is not deployed'); - } - return new BlankContract(extendedContractData.getCompleteAddress(), wallet); + public static async at(address: AztecAddress, wallet: Wallet) { + return Contract.at(address, BlankContract.abi, wallet) as Promise; } /** diff --git a/yarn-project/boxes/private-token/src/artifacts/private_token.ts b/yarn-project/boxes/private-token/src/artifacts/private_token.ts index 1d2e2900220..4812265609d 100644 --- a/yarn-project/boxes/private-token/src/artifacts/private_token.ts +++ b/yarn-project/boxes/private-token/src/artifacts/private_token.ts @@ -4,10 +4,12 @@ import { AztecAddress, CompleteAddress, + Contract, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, + EthAddress, FieldLike, AztecAddressLike, EthAddressLike, @@ -23,13 +25,8 @@ export const PrivateTokenContractAbi = PrivateTokenContractAbiJson as ContractAb * Type-safe interface for contract PrivateToken; */ export class PrivateTokenContract extends ContractBase { - private constructor( - /** The deployed contract's complete address. */ - completeAddress: CompleteAddress, - /** The wallet. */ - wallet: Wallet, - ) { - super(completeAddress, PrivateTokenContractAbi, wallet); + private constructor(completeAddress: CompleteAddress, wallet: Wallet, portalContract = EthAddress.ZERO) { + super(completeAddress, PrivateTokenContractAbi, wallet, portalContract); } /** @@ -38,17 +35,8 @@ export class PrivateTokenContract extends ContractBase { * @param wallet - The wallet to use when interacting with the contract. * @returns A promise that resolves to a new Contract instance. */ - public static async at( - /** The deployed contract's address. */ - address: AztecAddress, - /** The wallet. */ - wallet: Wallet, - ) { - const extendedContractData = await wallet.getExtendedContractData(address); - if (extendedContractData === undefined) { - throw new Error('Contract ' + address.toString() + ' is not deployed'); - } - return new PrivateTokenContract(extendedContractData.getCompleteAddress(), wallet); + public static async at(address: AztecAddress, wallet: Wallet) { + return Contract.at(address, PrivateTokenContract.abi, wallet) as Promise; } /** diff --git a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts index 1b6c4fcb6a1..a478d20a908 100644 --- a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts @@ -115,7 +115,6 @@ async function deployAllContracts( const uniswapL2Contract = await UniswapContract.deploy(ownerWallet) .send({ portalContract: uniswapPortalAddress }) .deployed(); - await uniswapL2Contract.attach(uniswapPortalAddress); await uniswapPortal.write.initialize( [l1ContractsAddresses!.registryAddress.toString(), uniswapL2Contract.address.toString()], diff --git a/yarn-project/canary/src/utils.ts b/yarn-project/canary/src/utils.ts index 0bcc6926632..4a05c6713f5 100644 --- a/yarn-project/canary/src/utils.ts +++ b/yarn-project/canary/src/utils.ts @@ -1,4 +1,4 @@ -import { AztecAddress, EthAddress, Fr, TxStatus, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, EthAddress, TxStatus, Wallet } from '@aztec/aztec.js'; import { PortalERC20Abi, PortalERC20Bytecode, TokenPortalAbi, TokenPortalBytecode } from '@aztec/l1-artifacts'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types'; @@ -72,15 +72,10 @@ export async function deployAndInitializeTokenAndBridgeContracts( const token = await TokenContract.at(deployReceipt.contractAddress!, wallet); // deploy l2 token bridge and attach to the portal - const bridgeTx = TokenBridgeContract.deploy(wallet, token.address).send({ - portalContract: tokenPortalAddress, - contractAddressSalt: Fr.random(), - }); - - const bridgeReceipt = await bridgeTx.wait(); - const bridge = await TokenBridgeContract.at(bridgeReceipt.contractAddress!, wallet); - await bridge.attach(tokenPortalAddress); - const bridgeAddress = bridge.address.toString() as `0x${string}`; + const bridge = await TokenBridgeContract.deploy(wallet, token.address) + .send({ portalContract: tokenPortalAddress }) + .deployed(); + const bridgeAddress = bridge.address.toString(); // now we wait for the txs to be mined. This way we send all tx in the same rollup. if ((await token.methods.admin().view()) !== owner.toBigInt()) throw new Error(`Token admin is not ${owner}`); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 35b5693b385..ea37f3056c5 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -17,7 +17,6 @@ import { deployL1Contract, deployL1Contracts, } from '@aztec/ethereum'; -import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { retryUntil } from '@aztec/foundation/retry'; import { @@ -412,15 +411,9 @@ export async function deployAndInitializeTokenAndBridgeContracts( const token = await TokenContract.at(deployReceipt.contractAddress!, wallet); // deploy l2 token bridge and attach to the portal - const bridgeTx = TokenBridgeContract.deploy(wallet, token.address).send({ - portalContract: tokenPortalAddress, - contractAddressSalt: Fr.random(), - }); - const bridgeReceipt = await bridgeTx.wait(); - if (bridgeReceipt.status !== TxStatus.MINED) throw new Error(`Deploy bridge tx status is ${bridgeReceipt.status}`); - const bridge = await TokenBridgeContract.at(bridgeReceipt.contractAddress!, wallet); - await bridge.attach(tokenPortalAddress); - const bridgeAddress = bridge.address.toString() as `0x${string}`; + const bridge = await TokenBridgeContract.deploy(wallet, token.address) + .send({ portalContract: tokenPortalAddress }) + .deployed(); if ((await token.methods.admin().view()) !== owner.toBigInt()) throw new Error(`Token admin is not ${owner}`); @@ -436,7 +429,7 @@ export async function deployAndInitializeTokenAndBridgeContracts( // initialize portal await tokenPortal.write.initialize( - [rollupRegistryAddress.toString(), underlyingERC20Address.toString(), bridgeAddress], + [rollupRegistryAddress.toString(), underlyingERC20Address.toString(), bridge.address.toString()], {} as any, ); @@ -485,16 +478,10 @@ export async function deployAndInitializeNonNativeL2TokenContracts( }); // deploy l2 contract and attach to portal - const tx = NonNativeTokenContract.deploy(wallet, initialBalance, owner).send({ - portalContract: tokenPortalAddress, - contractAddressSalt: Fr.random(), - }); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); - if (receipt.status !== TxStatus.MINED) throw new Error(`Tx status is ${receipt.status}`); - const l2Contract = await NonNativeTokenContract.at(receipt.contractAddress!, wallet); - await l2Contract.attach(tokenPortalAddress); - const l2TokenAddress = l2Contract.address.toString() as `0x${string}`; + const l2Contract = await NonNativeTokenContract.deploy(wallet, initialBalance, owner) + .send({ portalContract: tokenPortalAddress }) + .deployed(); + const l2TokenAddress = l2Contract.address.toString(); // initialize portal await tokenPortal.write.initialize( diff --git a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts index b5e8481d265..8e26fb3a817 100644 --- a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts @@ -124,7 +124,6 @@ describe('uniswap_trade_on_l1_from_l2', () => { uniswapL2Contract = await UniswapContract.deploy(ownerWallet) .send({ portalContract: uniswapPortalAddress }) .deployed(); - await uniswapL2Contract.attach(uniswapPortalAddress); await uniswapPortal.write.initialize( [deployL1ContractsValues!.l1ContractAddresses.registryAddress!.toString(), uniswapL2Contract.address.toString()], diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts index 31ddb4ad10b..210776234ba 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts @@ -91,12 +91,11 @@ function generateDeploy(input: ContractAbi) { function generateConstructor(name: string) { return ` private constructor( - /** The deployed contract's complete address. */ completeAddress: CompleteAddress, - /** The wallet. */ wallet: Wallet, + portalContract = EthAddress.ZERO ) { - super(completeAddress, ${name}ContractAbi, wallet); + super(completeAddress, ${name}ContractAbi, wallet, portalContract); } `; } @@ -116,16 +115,10 @@ function generateAt(name: string) { * @returns A promise that resolves to a new Contract instance. */ public static async at( - /** The deployed contract's address. */ address: AztecAddress, - /** The wallet. */ wallet: Wallet, ) { - const extendedContractData = await wallet.getExtendedContractData(address); - if (extendedContractData === undefined) { - throw new Error('Contract ' + address.toString() + ' is not deployed'); - } - return new ${name}Contract(extendedContractData.getCompleteAddress(), wallet); + return Contract.at(address, ${name}Contract.abi, wallet) as Promise<${name}Contract>; }`; } @@ -178,7 +171,7 @@ export function generateTypescriptContractInterface(input: ContractAbi, abiImpor /* Autogenerated file, do not edit! */ /* eslint-disable */ -import { AztecAddress, CompleteAddress, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, FieldLike, AztecAddressLike, EthAddressLike, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, CompleteAddress, Contract, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, EthAddress, FieldLike, AztecAddressLike, EthAddressLike, Wallet } from '@aztec/aztec.js'; import { Fr, Point } from '@aztec/foundation/fields'; import { PXE, PublicKey } from '@aztec/types'; import { ContractAbi } from '@aztec/foundation/abi';