Skip to content

Commit

Permalink
fix: don't use lazy FeeJuice in aztec.js (#12352)
Browse files Browse the repository at this point in the history
- Lazy json imports HAVE to be asserted in node.js. 
- Import assertions are incompatible with browsers
- Import attributes are compatible with both
- Import attributes are not supported on firefox
- aaaaaaaaaaaa


https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json

https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
  • Loading branch information
Thunkar authored Feb 27, 2025
1 parent 44c07a3 commit 2c1fe48
Show file tree
Hide file tree
Showing 23 changed files with 96 additions and 20 deletions.
5 changes: 5 additions & 0 deletions yarn-project/accounts/src/ecdsa/ecdsa_k/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import { EcdsaKBaseAccountContract } from './account_contract.js';
* @returns The contract artifact for the ecdsa K account contract
*/
export async function getEcdsaKAccountContractArtifact() {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: ecdsaKAccountContractJson } = await import('../../../artifacts/EcdsaKAccount.json');
return loadContractArtifact(ecdsaKAccountContractJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/accounts/src/ecdsa/ssh_ecdsa_r/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ import { EcdsaRSSHBaseAccountContract } from './account_contract.js';
*
*/
export async function getEcdsaRAccountContractArtifact() {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: ecdsaKAccountContractJson } = await import('../../../artifacts/EcdsaRAccount.json');
return loadContractArtifact(ecdsaKAccountContractJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/accounts/src/schnorr/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import { SchnorrBaseAccountContract } from './account_contract.js';
* @returns The contract artifact for the schnorr account contract
*/
export async function getSchnorrAccountContractArtifact() {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: schnorrAccountContractJson } = await import('../../artifacts/SchnorrAccount.json');
return loadContractArtifact(schnorrAccountContractJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/accounts/src/single_key/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import { SingleKeyBaseAccountContract } from './account_contract.js';
* @returns The contract artifact for the single key account contract
*/
export async function getSingleKeyAccountContractArtifact() {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: schnorrAccountContractJson } = await import('../../artifacts/SchnorrAccount.json');
return loadContractArtifact(schnorrAccountContractJson);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ProtocolContractAddress } from '@aztec/protocol-contracts';

import { UnsafeContract } from '../contract/unsafe_contract.js';
import type { Wallet } from '../wallet/index.js';
import { UnsafeContract } from './unsafe_contract.js';

/** Returns a Contract wrapper for the class registerer. */
export async function getRegistererContract(wallet: Wallet) {
Expand All @@ -23,3 +23,13 @@ export async function getDeployerContract(wallet: Wallet) {
const { artifact } = await wallet.getContractClassMetadata(contractInstance.currentContractClassId, true);
return new UnsafeContract(contractInstance!, artifact!, wallet);
}

/** Returns a Contract wrapper for the fee juice */
export async function getFeeJuice(wallet: Wallet) {
const { contractInstance } = await wallet.getContractMetadata(ProtocolContractAddress.FeeJuice);
if (!contractInstance) {
throw new Error("FeeJuice is not registered in this wallet's instance");
}
const { artifact } = await wallet.getContractClassMetadata(contractInstance.currentContractClassId, true);
return new UnsafeContract(contractInstance!, artifact!, wallet);
}
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/deployment/broadcast_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import {
import { Capsule } from '@aztec/stdlib/tx';

import type { ContractFunctionInteraction } from '../contract/contract_function_interaction.js';
import { getRegistererContract } from '../contract/protocol_contracts.js';
import type { Wallet } from '../wallet/index.js';
import { getRegistererContract } from './protocol_contracts.js';

/**
* Sets up a call to broadcast a private function's bytecode via the ClassRegisterer contract.
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/deployment/deploy_instance.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';

import type { ContractFunctionInteraction } from '../contract/contract_function_interaction.js';
import { getDeployerContract } from '../contract/protocol_contracts.js';
import type { Wallet } from '../wallet/index.js';
import { getDeployerContract } from './protocol_contracts.js';

/**
* Sets up a call to the canonical deployer contract to publicly deploy a contract instance.
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/deployment/register_class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
import { Capsule } from '@aztec/stdlib/tx';

import type { ContractFunctionInteraction } from '../contract/contract_function_interaction.js';
import { getRegistererContract } from '../contract/protocol_contracts.js';
import type { Wallet } from '../wallet/index.js';
import { getRegistererContract } from './protocol_contracts.js';

const defaultEmitPublicBytecode =
// guard against `process` not being defined (e.g. in the browser)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import { Fr } from '@aztec/foundation/fields';
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice/lazy';
import type { FunctionCall } from '@aztec/stdlib/abi';
import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
import type { AztecAddress } from '@aztec/stdlib/aztec-address';

import type { L2AmountClaim } from '../api/ethereum/portal_manager.js';
import { getFeeJuice } from '../contract/protocol_contracts.js';
import type { Wallet } from '../wallet/index.js';
import { FeeJuicePaymentMethod } from './fee_juice_payment_method.js';

/**
* Pay fee directly with Fee Juice claimed on the same tx.
*/
export class FeeJuicePaymentMethodWithClaim extends FeeJuicePaymentMethod {
constructor(
sender: AztecAddress,
private senderWallet: Wallet,
private claim: Pick<L2AmountClaim, 'claimAmount' | 'claimSecret' | 'messageLeafIndex'>,
) {
super(sender);
super(senderWallet.getAddress());
}

/**
* Creates a function call to pay the fee in Fee Juice.
* @returns A function call
*/
override async getFunctionCalls(): Promise<FunctionCall[]> {
const canonicalFeeJuice = await getCanonicalFeeJuice();
const canonicalFeeJuice = await getFeeJuice(this.senderWallet);
const selector = await FunctionSelector.fromNameAndParameters(
canonicalFeeJuice.artifact.functions.find(f => f.name === 'claim')!,
);
Expand All @@ -36,7 +36,7 @@ export class FeeJuicePaymentMethodWithClaim extends FeeJuicePaymentMethod {
selector,
isStatic: false,
args: [
this.sender.toField(),
this.senderWallet.getAddress().toField(),
new Fr(this.claim.claimAmount),
this.claim.claimSecret,
new Fr(this.claim.messageLeafIndex),
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/bot/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,16 @@ export class BotFactory {

const claim = await this.bridgeL1FeeJuice(address, 10n ** 22n);

const paymentMethod = new FeeJuicePaymentMethodWithClaim(address, claim);
const wallet = await account.getWallet();
const paymentMethod = new FeeJuicePaymentMethodWithClaim(wallet, claim);
const sentTx = account.deploy({ fee: { paymentMethod } });
const txHash = await sentTx.getTxHash();
this.log.info(`Sent tx with hash ${txHash.toString()}`);
await this.tryFlushTxs();
this.log.verbose('Waiting for account deployment to settle');
await sentTx.wait({ timeout: this.config.txMinedWaitSeconds });
this.log.info(`Account deployed at ${address}`);
return account.getWallet();
return wallet;
}
}

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/cli-wallet/src/utils/options/fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export function parsePaymentMethod(
}
log(`Using Fee Juice for fee payments with claim for ${claimAmount} tokens`);
const { FeeJuicePaymentMethodWithClaim } = await import('@aztec/aztec.js/fee');
return new FeeJuicePaymentMethodWithClaim(sender.getAddress(), {
return new FeeJuicePaymentMethodWithClaim(sender, {
claimAmount: (typeof claimAmount === 'string'
? Fr.fromHexString(claimAmount)
: new Fr(claimAmount)
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/devnet/e2e_smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe('End-to-end tests for devnet', () => {
const txReceipt = await l2Account
.deploy({
fee: {
paymentMethod: new FeeJuicePaymentMethodWithClaim(l2Account.getAddress(), {
paymentMethod: new FeeJuicePaymentMethodWithClaim(await l2Account.getWallet(), {
claimAmount: Fr.fromHexString(claimAmount).toBigInt(),
claimSecret: Fr.fromHexString(claimSecret.value),
messageLeafIndex: BigInt(messageLeafIndex),
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_fees/account_init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ describe('e2e_fees account_init', () => {

it('pays natively in the Fee Juice by bridging funds themselves', async () => {
const claim = await t.feeJuiceBridgeTestHarness.prepareTokensOnL1(FEE_FUNDING_FOR_TESTER_ACCOUNT, bobsAddress);
const paymentMethod = new FeeJuicePaymentMethodWithClaim(bobsAddress, claim);
const paymentMethod = new FeeJuicePaymentMethodWithClaim(bobsWallet, claim);
const tx = await bobsAccountManager.deploy({ fee: { paymentMethod } }).wait();
expect(tx.transactionFee!).toBeGreaterThan(0n);
await expect(t.getGasBalanceFn(bobsAddress)).resolves.toEqual([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('e2e_fees Fee Juice payments', () => {
it('claims bridged funds and pays with them on the same tx', async () => {
const claim = await t.feeJuiceBridgeTestHarness.prepareTokensOnL1(FEE_FUNDING_FOR_TESTER_ACCOUNT, bobAddress);
// docs:start:claim_and_pay
const paymentMethod = new FeeJuicePaymentMethodWithClaim(bobAddress, claim);
const paymentMethod = new FeeJuicePaymentMethodWithClaim(bobWallet, claim);
const receipt = await feeJuiceContract
.withWallet(bobWallet)
.methods.check_balance(0n)
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/end-to-end/src/spartan/setup_test_wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ export async function deployTestWalletWithTokens(

const wallets = await Promise.all(
fundedAccounts.map(async (a, i) => {
const paymentMethod = new FeeJuicePaymentMethodWithClaim(a.getAddress(), claims[i]);
const wallet = await a.getWallet();
const paymentMethod = new FeeJuicePaymentMethodWithClaim(wallet, claims[i]);
await a.deploy({ fee: { paymentMethod } }).wait();
logger.info(`Account deployed at ${a.getAddress()}`);
return a.getWallet();
return wallet;
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ function generateCircuitArtifactImportFunction() {
return [artifactName, simulatedArtifactName];
})
.map(artifactName => {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
return `case '${artifactName}': {
const { default: compiledCircuit } = await import(\"../artifacts/${artifactName}.json\");
return compiledCircuit as NoirCompiledCircuit;
Expand All @@ -69,6 +74,11 @@ function generateCircuitArtifactImportFunction() {

function generateVkImportFunction() {
const cases = Object.values(ClientCircuitArtifactNames).map(artifactName => {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
return `case '${artifactName}': {
const { default: keyData } = await import(\"../artifacts/keys/${artifactName}.vk.data.json\");
return keyJsonToVKData(keyData);
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/protocol-contracts/src/auth-registry/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getAuthRegistryArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: authRegistryJson } = await import('../../artifacts/AuthRegistry.json');
protocolContractArtifact = loadContractArtifact(authRegistryJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/protocol-contracts/src/class-registerer/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getContractClassRegistererArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: contractClassRegistererJson } = await import('../../artifacts/ContractClassRegisterer.json');
protocolContractArtifact = loadContractArtifact(contractClassRegistererJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/protocol-contracts/src/fee-juice/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getFeeJuiceArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: feeJuiceJson } = await import('../../artifacts/FeeJuice.json');
protocolContractArtifact = loadContractArtifact(feeJuiceJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/protocol-contracts/src/instance-deployer/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getContractInstanceDeployerArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: contractInstanceDeployerJson } = await import('../../artifacts/ContractInstanceDeployer.json');
protocolContractArtifact = loadContractArtifact(contractInstanceDeployerJson);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getMultiCallEntrypointArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: multiCallEntrypointJson } = await import('../../artifacts/MultiCallEntrypoint.json');
protocolContractArtifact = loadContractArtifact(multiCallEntrypointJson);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/protocol-contracts/src/router/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ let protocolContractArtifact: ContractArtifact;

export async function getRouterArtifact(): Promise<ContractArtifact> {
if (!protocolContractArtifact) {
// Cannot assert this import as it's incompatible with browsers
// https://caniuse.com/mdn-javascript_statements_import_import_assertions_type_json
// Use the new "with" syntax once supported by firefox
// https://caniuse.com/mdn-javascript_statements_import_import_attributes_type_json
// In the meantime, this lazy import is INCOMPATIBLE WITH NODEJS
const { default: routerJson } = await import('../../artifacts/Router.json');
protocolContractArtifact = loadContractArtifact(routerJson);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { type L1ContractsConfig, type L1ReaderConfig, createEthereumChain } from '@aztec/ethereum';
import type { ViemPublicClient } from '@aztec/ethereum';
import {
type L1ContractsConfig,
type L1ReaderConfig,
type ViemPublicClient,
createEthereumChain,
} from '@aztec/ethereum';
import type { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
import { createLogger } from '@aztec/foundation/log';
Expand Down

0 comments on commit 2c1fe48

Please sign in to comment.