Skip to content

Commit

Permalink
feat: deploy gas token as part of sandbox
Browse files Browse the repository at this point in the history
  • Loading branch information
alexghr committed Mar 6, 2024
1 parent c1d1865 commit 4438694
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 28 deletions.
1 change: 1 addition & 0 deletions yarn-project/aztec/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
21 changes: 21 additions & 0 deletions yarn-project/aztec/src/sandbox.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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';
Expand Down Expand Up @@ -141,6 +144,8 @@ export async function createSandbox(config: Partial<SandboxConfig> = {}) {
const node = await createAztecNode(aztecNodeConfig);
const pxe = await createAztecPXE(node);

await deployProtocolContracts(new SignerlessWallet(pxe));

const stop = async () => {
await pxe.stop();
await node.stop();
Expand Down Expand Up @@ -168,3 +173,19 @@ export async function createAztecPXE(node: AztecNode, config: Partial<PXEService
const pxe = await createPXEService(node, pxeServiceConfig);
return pxe;
}

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();
}
3 changes: 3 additions & 0 deletions yarn-project/aztec/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
{
"path": "../p2p"
},
{
"path": "../protocol-contracts"
},
{
"path": "../pxe"
}
Expand Down
38 changes: 14 additions & 24 deletions yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

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

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

Expand All @@ -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,
});
Expand Down Expand Up @@ -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);
Expand All @@ -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 () => {
Expand Down Expand Up @@ -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],
);
});

Expand Down Expand Up @@ -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],
);
});

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

Expand Down
32 changes: 32 additions & 0 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -221,6 +222,9 @@ type SetupOptions = {
stateLoad?: string;
/** Previously deployed contracts on L1 */
deployL1ContractsValues?: DeployL1Contracts;

/** Deploy protocol contracts */
deployProtocolContracts?: boolean;
} & Partial<AztecNodeConfig>;

/** Context for an end-to-end test as returned by the `setup` function */
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -458,3 +468,25 @@ export async function expectMapping<K, V>(

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();
}
4 changes: 3 additions & 1 deletion yarn-project/protocol-contracts/src/gas-token/index.ts
Original file line number Diff line number Diff line change
@@ -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;
19 changes: 16 additions & 3 deletions yarn-project/protocol-contracts/src/protocol_contract.ts
Original file line number Diff line number Diff line change
@@ -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. */
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions yarn-project/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4438694

Please sign in to comment.