diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index e106b1f97bf0..4338c9875fd5 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -40,6 +40,7 @@ "@aztec/noir-compiler": "workspace:^", "@aztec/noir-contracts.js": "workspace:^", "@aztec/p2p": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@aztec/pxe": "workspace:^", "abitype": "^0.8.11", "commander": "^11.1.0", diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 4c4b378ba678..ff33d459c0bc 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -1,5 +1,7 @@ #!/usr/bin/env -S node --no-warnings import { AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node'; +import { BatchCall, SignerlessWallet, Wallet } from '@aztec/aztec.js'; +import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; import { AztecNode } from '@aztec/circuit-types'; import { DeployL1Contracts, @@ -24,6 +26,7 @@ import { RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; +import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { HDAccount, PrivateKeyAccount, createPublicClient, http as httpViemTransport } from 'viem'; @@ -141,6 +144,8 @@ export async function createSandbox(config: Partial = {}) { const node = await createAztecNode(aztecNodeConfig); const pxe = await createAztecPXE(node); + await deployProtocolContracts(new SignerlessWallet(pxe)); + const stop = async () => { await pxe.stop(); await node.stop(); @@ -168,3 +173,19 @@ export async function createAztecPXE(node: AztecNode, config: Partial { let gasTokenContract: GasTokenContract; let bananaFPC: FPCContract; let e2eContext: EndToEndContext; - let gasBridgeTestHarness: IGasBridgingTestHarness; let gasBalances: BalancesFn; let bananasPublicBalances: BalancesFn; let bananasPrivateBalances: BalancesFn; const SUBSCRIPTION_AMOUNT = 100n; - const BRIDGED_GAS_BALANCE = 1000n; + const INITIAL_GAS_BALANCE = 1000n; const PUBLICLY_MINTED_BANANAS = 500n; const PRIVATELY_MINTED_BANANAS = 600n; @@ -64,25 +63,18 @@ describe('e2e_dapp_subscription', () => { beforeAll(async () => { process.env.PXE_URL = ''; - e2eContext = await setup(3); + e2eContext = await setup(3, { deployProtocolContracts: true }); + await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); + + const { wallets, accounts, aztecNode } = e2eContext; - const { wallets, accounts, aztecNode, deployL1ContractsValues, logger, pxe } = e2eContext; + // this should be a SignerlessWallet but that can't call public functions directly + gasTokenContract = await GasTokenContract.at(GasTokenAddress, wallets[0]); aliceAddress = accounts.at(0)!.address; bobAddress = accounts.at(1)!.address; sequencerAddress = accounts.at(2)!.address; - gasBridgeTestHarness = await GasPortalTestingHarnessFactory.create({ - pxeService: pxe, - publicClient: deployL1ContractsValues.publicClient, - walletClient: deployL1ContractsValues.walletClient, - wallet: wallets[0], - logger, - mockL1: true, - }); - - gasTokenContract = gasBridgeTestHarness.l2Token; - await aztecNode.setConfig({ feeRecipient: sequencerAddress, }); @@ -113,8 +105,8 @@ describe('e2e_dapp_subscription', () => { // she'll pay for the subscription with these await bananaCoin.methods.privately_mint_private_note(PRIVATELY_MINTED_BANANAS).send().wait(); await bananaCoin.methods.mint_public(aliceAddress, PUBLICLY_MINTED_BANANAS).send().wait(); - await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, subscriptionContract.address); - await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, bananaFPC.address); + await gasTokenContract.methods.mint_public(subscriptionContract.address, INITIAL_GAS_BALANCE).send().wait(); + await gasTokenContract.methods.mint_public(bananaFPC.address, INITIAL_GAS_BALANCE).send().wait(); gasBalances = getBalancesFn('⛽', gasTokenContract.methods.balance_of_public, e2eContext.logger); bananasPublicBalances = getBalancesFn('Public 🍌', bananaCoin.methods.balance_of_public, e2eContext.logger); @@ -123,10 +115,8 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [aliceAddress, sequencerAddress, subscriptionContract.address, bananaFPC.address], - [0n, 0n, BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE], + [0n, 0n, INITIAL_GAS_BALANCE, INITIAL_GAS_BALANCE], ); - - await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); }); it('should allow Alice to subscribe by paying privately with bananas', async () => { @@ -160,7 +150,7 @@ describe('e2e_dapp_subscription', () => { gasBalances, // note the subscription contract hasn't paid any fees yet [bananaFPC.address, subscriptionContract.address, sequencerAddress], - [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE, FEE_AMOUNT], + [INITIAL_GAS_BALANCE - FEE_AMOUNT, INITIAL_GAS_BALANCE, FEE_AMOUNT], ); }); @@ -201,7 +191,7 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [subscriptionContract.address, bananaFPC.address, sequencerAddress], - [BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, 2n * FEE_AMOUNT], + [INITIAL_GAS_BALANCE, INITIAL_GAS_BALANCE - 2n * FEE_AMOUNT, 2n * FEE_AMOUNT], ); }); @@ -219,7 +209,7 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [subscriptionContract.address, bananaFPC.address, sequencerAddress], - [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, FEE_AMOUNT * 3n], + [INITIAL_GAS_BALANCE - FEE_AMOUNT, INITIAL_GAS_BALANCE - 2n * FEE_AMOUNT, FEE_AMOUNT * 3n], ); }); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index c8a118bee3e1..de855f1d885a 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -40,6 +40,7 @@ import { RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; +import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { PXEService, PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { SequencerClient } from '@aztec/sequencer-client'; @@ -221,6 +222,9 @@ type SetupOptions = { stateLoad?: string; /** Previously deployed contracts on L1 */ deployL1ContractsValues?: DeployL1Contracts; + + /** Deploy protocol contracts */ + deployProtocolContracts?: boolean; } & Partial; /** Context for an end-to-end test as returned by the `setup` function */ @@ -295,6 +299,12 @@ export async function setup( const { pxe, accounts, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger); + if (opts.deployProtocolContracts) { + // this should be a neutral wallet, but the SignerlessWallet only accepts a single function call + // and this needs two: one to register the class and another to deploy the instance + await deployProtocolContracts(wallets[0]); + } + const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); const teardown = async () => { @@ -458,3 +468,25 @@ export async function expectMapping( expect(outputs).toEqual(expectedOutputs); } + +/** + * Deploy the protocol contracts to a running instance. + */ +export async function deployProtocolContracts(deployer: Wallet) { + // "deploy" the Gas token as it contains public functions + const canonicalGasToken = getCanonicalGasToken(); + + if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { + return; + } + + await new BatchCall(deployer, [ + (await registerContractClass(deployer, canonicalGasToken.artifact)).request(), + deployInstance(deployer, canonicalGasToken.instance, { universalDeploy: true }).request(), + ]) + .send() + .wait(); + + await expect(deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)).resolves.toBe(true); + await expect(deployer.getContractInstance(canonicalGasToken.instance.address)).resolves.toBeDefined(); +} diff --git a/yarn-project/protocol-contracts/src/gas-token/index.ts b/yarn-project/protocol-contracts/src/gas-token/index.ts index b86cb89fba1f..c3daa5dd96e7 100644 --- a/yarn-project/protocol-contracts/src/gas-token/index.ts +++ b/yarn-project/protocol-contracts/src/gas-token/index.ts @@ -1,9 +1,11 @@ +import { EthAddress, Point } from '@aztec/circuits.js'; + import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; import { GasTokenArtifact } from './artifact.js'; /** Returns the canonical deployment of the gas token. */ export function getCanonicalGasToken(): ProtocolContract { - return getCanonicalProtocolContract(GasTokenArtifact, 1); + return getCanonicalProtocolContract(GasTokenArtifact, 1, [], Point.ZERO, EthAddress.ZERO); } export const GasTokenAddress = getCanonicalGasToken().address; diff --git a/yarn-project/protocol-contracts/src/protocol_contract.ts b/yarn-project/protocol-contracts/src/protocol_contract.ts index 4f798ed4f480..c3fa3c7d50da 100644 --- a/yarn-project/protocol-contracts/src/protocol_contract.ts +++ b/yarn-project/protocol-contracts/src/protocol_contract.ts @@ -1,6 +1,11 @@ -import { AztecAddress, getContractClassFromArtifact, getContractInstanceFromDeployParams } from '@aztec/circuits.js'; +import { + AztecAddress, + EthAddress, + getContractClassFromArtifact, + getContractInstanceFromDeployParams, +} from '@aztec/circuits.js'; import { ContractArtifact } from '@aztec/foundation/abi'; -import { Fr } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; /** Represents a canonical contract in the protocol. */ @@ -20,10 +25,18 @@ export function getCanonicalProtocolContract( artifact: ContractArtifact, salt: Fr | number | bigint, initArgs: any[] = [], + publicKey: Point = Point.ZERO, + portalContractAddress = EthAddress.ZERO, ): ProtocolContract { // TODO(@spalladino): This computes the contract class from the artifact twice. const contractClass = getContractClassFromArtifact(artifact); - const instance = getContractInstanceFromDeployParams(artifact, initArgs, new Fr(salt)); + const instance = getContractInstanceFromDeployParams( + artifact, + initArgs, + new Fr(salt), + publicKey, + portalContractAddress, + ); return { instance, contractClass, diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index ba2110329892..da11d98a2d56 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -233,6 +233,7 @@ __metadata: "@aztec/noir-compiler": "workspace:^" "@aztec/noir-contracts.js": "workspace:^" "@aztec/p2p": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/pxe": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0