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

feat(aztec.js): Remove attach method #2715

Merged
merged 3 commits into from
Oct 6, 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
10 changes: 3 additions & 7 deletions yarn-project/aztec-sandbox/src/examples/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 1 addition & 34 deletions yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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]);
}
});
});
8 changes: 7 additions & 1 deletion yarn-project/aztec.js/src/contract/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ 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<Contract> {
const extendedContractData = await wallet.getExtendedContractData(address);
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,
);
}

/**
Expand Down
36 changes: 7 additions & 29 deletions yarn-project/aztec.js/src/contract/contract_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]) => {
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type DeployTxReceipt<TContract extends ContractBase = Contract> = FieldsO
/**
* A contract deployment transaction sent to the network, extending SentTx with methods to create a contract instance.
*/
export class DeploySentTx<TContract extends ContractBase = Contract> extends SentTx {
export class DeploySentTx<TContract extends Contract = Contract> extends SentTx {
constructor(private abi: ContractAbi, wallet: PXE | Wallet, txHashPromise: Promise<TxHash>) {
super(wallet, txHashPromise);
}
Expand Down
24 changes: 6 additions & 18 deletions yarn-project/boxes/blank-react/src/artifacts/blank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import {
AztecAddress,
CompleteAddress,
Contract,
ContractBase,
ContractFunctionInteraction,
ContractMethod,
DeployMethod,
EthAddress,
FieldLike,
AztecAddressLike,
EthAddressLike,
Expand All @@ -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);
}

/**
Expand All @@ -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<BlankContract>;
}

/**
Expand Down
24 changes: 6 additions & 18 deletions yarn-project/boxes/blank/src/artifacts/blank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import {
AztecAddress,
CompleteAddress,
Contract,
ContractBase,
ContractFunctionInteraction,
ContractMethod,
DeployMethod,
EthAddress,
FieldLike,
AztecAddressLike,
EthAddressLike,
Expand All @@ -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);
}

/**
Expand All @@ -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<BlankContract>;
}

/**
Expand Down
24 changes: 6 additions & 18 deletions yarn-project/boxes/private-token/src/artifacts/private_token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import {
AztecAddress,
CompleteAddress,
Contract,
ContractBase,
ContractFunctionInteraction,
ContractMethod,
DeployMethod,
EthAddress,
FieldLike,
AztecAddressLike,
EthAddressLike,
Expand All @@ -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);
}

/**
Expand All @@ -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<PrivateTokenContract>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down
15 changes: 5 additions & 10 deletions yarn-project/canary/src/utils.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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}`);
Expand Down
29 changes: 8 additions & 21 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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}`);

Expand All @@ -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,
);

Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down
Loading