diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index 0bd639aae32..915b3640c37 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -16,6 +16,7 @@ import { FPCContract, GasTokenContract, } from '@aztec/noir-contracts.js'; +import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { jest } from '@jest/globals'; @@ -27,7 +28,6 @@ import { publicDeployAccounts, setup, } from './fixtures/utils.js'; -import { GasPortalTestingHarnessFactory, IGasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; jest.setTimeout(1_000_000); @@ -48,13 +48,12 @@ describe('e2e_dapp_subscription', () => { 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 a0eae07fc89..a18f70cb847 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -41,6 +41,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'; @@ -188,6 +189,7 @@ async function setupWithRemoteEnvironment( config: AztecNodeConfig, logger: DebugLogger, numberOfAccounts: number, + deployProtocolContracts = false, ) { // we are setting up against a remote environment, l1 contracts are already deployed const aztecNodeUrl = getAztecUrl(); @@ -225,6 +227,10 @@ async function setupWithRemoteEnvironment( const cheatCodes = CheatCodes.create(config.rpcUrl, pxeClient!); const teardown = () => Promise.resolve(); + if (deployProtocolContracts) { + await deployPublicProtocolContracts(wallets[0]); + } + return { aztecNode, sequencer: undefined, @@ -246,6 +252,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 */ @@ -305,7 +314,7 @@ export async function setup( if (PXE_URL) { // we are setting up against a remote environment, l1 contracts are assumed to already be deployed - return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts); + return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts, opts.deployProtocolContracts); } const deployL1ContractsValues = @@ -327,6 +336,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 deployPublicProtocolContracts(wallets[0]); + } + const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); const teardown = async () => { @@ -490,3 +505,25 @@ export async function expectMapping( expect(outputs).toEqual(expectedOutputs); } + +/** + * Deploy the protocol contracts to a running instance. + */ +export async function deployPublicProtocolContracts(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 b86cb89fba1..c3daa5dd96e 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 4f798ed4f48..c3fa3c7d50d 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,