Skip to content

Commit

Permalink
refactor: add gas portal to l1 contract addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
alexghr committed Mar 17, 2024
1 parent a5e7327 commit 0b94879
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 50 deletions.
11 changes: 5 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ setup_env: &setup_env
command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" "$CIRCLE_PULL_REQUEST"

defaults_e2e_test: &defaults_e2e_test
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small

jobs:
# Dynamically filter our code, quickly figuring out which jobs we can skip.
Expand Down Expand Up @@ -868,7 +868,6 @@ jobs:
aztec_manifest_key: end-to-end
<<: *defaults_e2e_test


e2e-outbox:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -968,7 +967,7 @@ jobs:
- *setup_env
- run:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_fees.test.ts
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml DEPLOY_GAS_PORTAL=1 TEST=e2e_fees.test.ts
aztec_manifest_key: end-to-end
<<: *defaults_e2e_test

Expand Down Expand Up @@ -1231,7 +1230,7 @@ defaults: &defaults
- slack/notify:
event: fail
branch_pattern: "master"

bb_acir_tests: &bb_acir_tests
requires:
- barretenberg-x86_64-linux-clang-assert
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/archiver/src/archiver/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function getConfigEnvVars(): ArchiverConfig {
INBOX_CONTRACT_ADDRESS,
OUTBOX_CONTRACT_ADDRESS,
REGISTRY_CONTRACT_ADDRESS,
GAS_PORTAL_CONTRACT_ADDRESS,
DATA_DIRECTORY,
} = process.env;
// Populate the relevant addresses for use by the archiver.
Expand All @@ -73,6 +74,9 @@ export function getConfigEnvVars(): ArchiverConfig {
registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO,
inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
outboxAddress: OUTBOX_CONTRACT_ADDRESS ? EthAddress.fromString(OUTBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
gasPortalAddress: GAS_PORTAL_CONTRACT_ADDRESS
? EthAddress.fromString(GAS_PORTAL_CONTRACT_ADDRESS)
: EthAddress.ZERO,
};
return {
rpcUrl: ETHEREUM_HOST || 'http://127.0.0.1:8545/',
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('Contract Class', () => {
registryAddress: EthAddress.random(),
inboxAddress: EthAddress.random(),
outboxAddress: EthAddress.random(),
gasPortalAddress: EthAddress.random(),
};
const mockNodeInfo: NodeInfo = {
nodeVersion: 'vx.x.x',
Expand Down
24 changes: 16 additions & 8 deletions yarn-project/aztec.js/src/fee/native_fee_payment_method.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
import { FunctionCall } from '@aztec/circuit-types';
import { FunctionData } from '@aztec/circuits.js';
import { AztecAddress, FunctionData } from '@aztec/circuits.js';
import { FunctionSelector } from '@aztec/foundation/abi';
import { Fr } from '@aztec/foundation/fields';
import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';

import { Wallet } from '../account/wallet.js';
import { FeePaymentMethod } from './fee_payment_method.js';

/**
* Pay fee directly in the native gas token.
*/
export class NativeFeePaymentMethod implements FeePaymentMethod {
static #GAS_TOKEN = GasTokenAddress;
#gasTokenAddress: AztecAddress;

constructor() {}
private constructor(canonicalGasTokenAddress: AztecAddress) {
this.#gasTokenAddress = canonicalGasTokenAddress;
}

static async create(wallet: Wallet): Promise<NativeFeePaymentMethod> {
const nodeInfo = await wallet.getNodeInfo();
return new NativeFeePaymentMethod(getCanonicalGasTokenAddress(nodeInfo.l1ContractAddresses.gasPortalAddress));
}

/**
* Gets the native gas asset used to pay the fee.
* @returns The asset used to pay the fee.
*/
getAsset() {
return NativeFeePaymentMethod.#GAS_TOKEN;
return this.#gasTokenAddress;
}

/**
* The contract responsible for fee payment. This will be the same as the asset.
* @returns The contract address responsible for holding the fee payment.
*/
getPaymentContract() {
return NativeFeePaymentMethod.#GAS_TOKEN;
return this.#gasTokenAddress;
}

/**
Expand All @@ -46,12 +54,12 @@ export class NativeFeePaymentMethod implements FeePaymentMethod {
getFunctionCalls(feeLimit: Fr): Promise<FunctionCall[]> {
return Promise.resolve([
{
to: NativeFeePaymentMethod.#GAS_TOKEN,
to: this.#gasTokenAddress,
functionData: new FunctionData(FunctionSelector.fromSignature('check_balance(Field)'), false),
args: [feeLimit],
},
{
to: NativeFeePaymentMethod.#GAS_TOKEN,
to: this.#gasTokenAddress,
functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false),
args: [feeLimit],
},
Expand Down
9 changes: 9 additions & 0 deletions yarn-project/aztec/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
InboxBytecode,
OutboxAbi,
OutboxBytecode,
PortalERC20Abi,
PortalERC20Bytecode,
RegistryAbi,
RegistryBytecode,
RollupAbi,
Expand Down Expand Up @@ -98,6 +100,13 @@ export async function deployContractsToL1(
contractAbi: RollupAbi,
contractBytecode: RollupBytecode,
},
gasPortal:
process.env.DEPLOY_GAS_PORTAL === '1'
? {
contractAbi: PortalERC20Abi,
contractBytecode: PortalERC20Bytecode,
}
: undefined,
};

aztecNodeConfig.l1Contracts = (
Expand Down
1 change: 1 addition & 0 deletions yarn-project/end-to-end/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ e2e-avm-simulator:
DO +E2E_TEST --test=e2e_avm_simulator.test.ts

e2e-fees:
ENV DEPLOY_GAS_PORTAL=1
DO +E2E_TEST --test=e2e_fees.test.ts

e2e-dapp-subscription:
Expand Down
1 change: 1 addition & 0 deletions yarn-project/end-to-end/scripts/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ services:
PXE_BLOCK_POLLING_INTERVAL_MS: 50
ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500
AVM_ENABLED: ${AVM_ENABLED:-}
DEPLOY_GAS_PORTAL: ${DEPLOY_GAS_PORTAL:-}
ports:
- '8080:8080'

Expand Down
7 changes: 4 additions & 3 deletions yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AccountWalletWithPrivateKey,
AztecAddress,
EthAddress,
FeePaymentMethod,
Fr,
PrivateFeePaymentMethod,
Expand All @@ -16,7 +17,7 @@ import {
FPCContract,
GasTokenContract,
} from '@aztec/noir-contracts.js';
import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';

import { jest } from '@jest/globals';

Expand Down Expand Up @@ -63,13 +64,13 @@ describe('e2e_dapp_subscription', () => {

beforeAll(async () => {
process.env.PXE_URL = '';
e2eContext = await setup(3, { deployProtocolContracts: true });
e2eContext = await setup(3, { deployGasToken: true });
await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts);

const { wallets, accounts, aztecNode } = e2eContext;

// this should be a SignerlessWallet but that can't call public functions directly
gasTokenContract = await GasTokenContract.at(GasTokenAddress, wallets[0]);
gasTokenContract = await GasTokenContract.at(getCanonicalGasTokenAddress(EthAddress.ZERO), wallets[0]);

aliceAddress = accounts.at(0)!.address;
bobAddress = accounts.at(1)!.address;
Expand Down
6 changes: 4 additions & 2 deletions yarn-project/end-to-end/src/e2e_fees.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ describe('e2e_fees', () => {
let bananaPrivateBalances: BalancesFn;

beforeAll(async () => {
process.env.PXE_URL = '';
e2eContext = await setup(3);
e2eContext = await setup(3, {
deployGasToken: true,
deployGasPortal: true,
});

const { accounts, logger, aztecNode, pxe, deployL1ContractsValues, wallets } = e2eContext;

Expand Down
37 changes: 26 additions & 11 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { deployInstance, registerContractClass } from '@aztec/aztec.js/deploymen
import {
AvailabilityOracleAbi,
AvailabilityOracleBytecode,
GasPortalAbi,
GasPortalBytecode,
InboxAbi,
InboxBytecode,
OutboxAbi,
Expand Down Expand Up @@ -96,6 +98,7 @@ export const setupL1Contracts = async (
l1RpcUrl: string,
account: HDAccount | PrivateKeyAccount,
logger: DebugLogger,
enableGas = false,
) => {
const l1Artifacts: L1ContractArtifactsForDeployment = {
registry: {
Expand All @@ -118,6 +121,12 @@ export const setupL1Contracts = async (
contractAbi: RollupAbi,
contractBytecode: RollupBytecode,
},
gasPortal: enableGas
? {
contractAbi: GasPortalAbi,
contractBytecode: GasPortalBytecode,
}
: undefined,
};
return await deployL1Contracts(l1RpcUrl, account, foundry, logger, l1Artifacts);
};
Expand Down Expand Up @@ -183,7 +192,7 @@ async function setupWithRemoteEnvironment(
config: AztecNodeConfig,
logger: DebugLogger,
numberOfAccounts: number,
deployProtocolContracts = false,
deployGasToken = false,
) {
// we are setting up against a remote environment, l1 contracts are already deployed
const aztecNodeUrl = getAztecUrl();
Expand Down Expand Up @@ -221,8 +230,10 @@ async function setupWithRemoteEnvironment(
const cheatCodes = CheatCodes.create(config.rpcUrl, pxeClient!);
const teardown = () => Promise.resolve();

if (deployProtocolContracts) {
await deployPublicProtocolContracts(wallets[0]);
if (deployGasToken) {
// this contract might already have been deployed
// the following function is idempotent
await deployCanonicalGasToken(wallets[0]);
}

return {
Expand All @@ -247,8 +258,11 @@ type SetupOptions = {
/** Previously deployed contracts on L1 */
deployL1ContractsValues?: DeployL1Contracts;

/** Deploy protocol contracts */
deployProtocolContracts?: boolean;
/** Deploy the gas token contract on L2 */
deployGasToken?: boolean;

/** Deploy gas portal on L1. This is used to bridge assets to the gas token contract */
deployGasPortal?: boolean;
} & Partial<AztecNodeConfig>;

/** Context for an end-to-end test as returned by the `setup` function */
Expand Down Expand Up @@ -308,11 +322,11 @@ 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, opts.deployProtocolContracts);
return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts, opts.deployGasToken);
}

const deployL1ContractsValues =
opts.deployL1ContractsValues ?? (await setupL1Contracts(config.rpcUrl, hdAccount, logger));
opts.deployL1ContractsValues ?? (await setupL1Contracts(config.rpcUrl, hdAccount, logger, opts.deployGasPortal));

config.publisherPrivateKey = `0x${publisherPrivKey!.toString('hex')}`;
config.l1Contracts = deployL1ContractsValues.l1ContractAddresses;
Expand All @@ -330,10 +344,10 @@ export async function setup(

const { pxe, accounts, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger);

if (opts.deployProtocolContracts) {
if (opts.deployGasToken) {
// 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]);
await deployCanonicalGasToken(wallets[0]);
}

const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!);
Expand Down Expand Up @@ -503,9 +517,10 @@ export async function expectMapping<K, V>(
/**
* Deploy the protocol contracts to a running instance.
*/
export async function deployPublicProtocolContracts(deployer: Wallet) {
export async function deployCanonicalGasToken(deployer: Wallet) {
// "deploy" the Gas token as it contains public functions
const canonicalGasToken = getCanonicalGasToken();
const gasPortalAddress = (await deployer.getNodeInfo()).l1ContractAddresses.gasPortalAddress;
const canonicalGasToken = getCanonicalGasToken(gasPortalAddress);

if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) {
return;
Expand Down
24 changes: 12 additions & 12 deletions yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
deployL1Contract,
sleep,
} from '@aztec/aztec.js';
import { GasPortalAbi, GasPortalBytecode, OutboxAbi, PortalERC20Abi, PortalERC20Bytecode } from '@aztec/l1-artifacts';
import { GasPortalAbi, OutboxAbi, PortalERC20Abi, PortalERC20Bytecode } from '@aztec/l1-artifacts';
import { GasTokenContract } from '@aztec/noir-contracts.js';
import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
import { getCanonicalGasToken, getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';

import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract } from 'viem';

Expand Down Expand Up @@ -62,21 +62,21 @@ export async function deployAndInitializeTokenAndBridgeContracts(
client: walletClient,
});

// deploy the gas portal
const gasPortalAddress = await deployL1Contract(walletClient, publicClient, GasPortalAbi, GasPortalBytecode);
// the gas portal should have been deployed already
// we need to initialize it though
const gasPortalAddress = (await wallet.getNodeInfo()).l1ContractAddresses.gasPortalAddress;
if (gasPortalAddress.isZero()) {
throw new Error('Gas portal not deployed on L1');
}

const gasPortal = getContract({
address: gasPortalAddress.toString(),
abi: GasPortalAbi,
client: walletClient,
});

// deploy l2 token
const gasL2 = await GasTokenContract.deploy(wallet)
.send({
portalContract: gasPortalAddress,
contractAddressSalt: getCanonicalGasToken().instance.salt,
})
.deployed();
// the gas token on L2 should have been deployed as part of bootstrap
const gasL2 = await GasTokenContract.at(getCanonicalGasTokenAddress(gasPortalAddress), wallet);

// initialize portal
await gasPortal.write.initialize(
Expand Down Expand Up @@ -104,7 +104,7 @@ export class GasPortalTestingHarnessFactory {

const gasL2 = await GasTokenContract.deploy(wallet)
.send({
contractAddressSalt: getCanonicalGasToken().instance.salt,
contractAddressSalt: getCanonicalGasToken(EthAddress.ZERO).instance.salt,
})
.deployed();
return Promise.resolve(new MockGasBridgingTestHarness(gasL2));
Expand Down
Loading

0 comments on commit 0b94879

Please sign in to comment.