Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 2 additions & 37 deletions yarn-project/aztec/src/local-network/local-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,11 @@ import { SecretValue } from '@aztec/foundation/config';
import { EthAddress } from '@aztec/foundation/eth-address';
import type { LogFn } from '@aztec/foundation/log';
import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
import { protocolContractsHash } from '@aztec/protocol-contracts';
import { SequencerState } from '@aztec/sequencer-client';
import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi';
import type { FunctionAbi } from '@aztec/stdlib/abi';
import { AztecAddress } from '@aztec/stdlib/aztec-address';
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
import type { AllowedElement, ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
import {
type TelemetryClient,
Expand All @@ -43,43 +39,12 @@ import { createAccountLogs } from '../cli/util.js';
import { DefaultMnemonic } from '../mnemonic.js';
import { AnvilTestWatcher } from '../testing/anvil_test_watcher.js';
import { EpochTestSettler } from '../testing/epoch_test_settler.js';
import { getTokenAllowedSetupFunctions } from '../testing/token_allowed_setup.js';
import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js';
import { getSponsoredFPCAddress } from './sponsored_fpc.js';

const logger = createLogger('local-network');

/**
* Returns Token-specific allowlist entries for FPC-based fee payments.
* The local network deploys a banana FPC and Token contracts, so the node must allow Token setup functions.
*/
async function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]> {
const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat(
TokenContractArtifact.nonDispatchPublicFunctions || [],
);
const getCalldataLength = (name: string) => {
const fn = allFunctions.find(f => f.name === name)!;
return 1 + countArgumentsSize(fn);
};
const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
const transferInPublicSelector = await FunctionSelector.fromSignature(
'transfer_in_public((Field),(Field),u128,Field)',
);
return [
{
classId: tokenClassId,
selector: increaseBalanceSelector,
calldataLength: getCalldataLength('_increase_public_balance'),
onlySelf: true,
},
{
classId: tokenClassId,
selector: transferInPublicSelector,
calldataLength: getCalldataLength('transfer_in_public'),
},
];
}

const localAnvil = foundry;

/**
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec/src/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { AnvilTestWatcher } from './anvil_test_watcher.js';
export { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test';
export { CheatCodes } from './cheat_codes.js';
export { EpochTestSettler } from './epoch_test_settler.js';
export { getTokenAllowedSetupFunctions } from './token_allowed_setup.js';
19 changes: 19 additions & 0 deletions yarn-project/aztec/src/testing/token_allowed_setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
import { buildAllowedElement } from '@aztec/p2p/msg_validators';
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';

/**
* Returns Token-specific allowlist entries needed for FPC-based fee payments.
* These are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha.
*/
export async function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]> {
const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
const target = { classId: tokenClassId };
return Promise.all([
// Token: needed for private transfers via FPC (transfer_to_public enqueues this)
buildAllowedElement(TokenContractArtifact, target, '_increase_public_balance', { onlySelf: true }),
// Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
buildAllowedElement(TokenContractArtifact, target, 'transfer_in_public'),
]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type FeePaymentMethod, PrivateFeePaymentMethod, SponsoredFeePaymentMeth
import { type Logger, createLogger } from '@aztec/aztec.js/log';
import type { AztecNode } from '@aztec/aztec.js/node';
import type { Wallet } from '@aztec/aztec.js/wallet';
import { CheatCodes } from '@aztec/aztec/testing';
import { CheatCodes, getTokenAllowedSetupFunctions } from '@aztec/aztec/testing';
import { createExtendedL1Client } from '@aztec/ethereum/client';
import { RollupContract } from '@aztec/ethereum/contracts';
import type { DeployAztecL1ContractsArgs } from '@aztec/ethereum/deploy-aztec-l1-contracts';
Expand All @@ -19,16 +19,12 @@ import { AMMContract } from '@aztec/noir-contracts.js/AMM';
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
import { TokenContract as BananaCoin, TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
import { TokenContract as BananaCoin, TokenContract } from '@aztec/noir-contracts.js/Token';
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi';
import type { FunctionAbi } from '@aztec/stdlib/abi';
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
import { GasSettings } from '@aztec/stdlib/gas';
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
import { deriveSigningKey } from '@aztec/stdlib/keys';

import { MNEMONIC } from '../../fixtures/fixtures.js';
Expand All @@ -46,35 +42,6 @@ import { type ClientFlowsConfig, FULL_FLOWS_CONFIG, KEY_FLOWS_CONFIG } from './c

const { BENCHMARK_CONFIG } = process.env;

/** Returns Token-specific allowlist entries for FPC-based fee payments (test-only). */
async function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]> {
const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat(
TokenContractArtifact.nonDispatchPublicFunctions || [],
);
const getCalldataLength = (name: string) => {
const fn = allFunctions.find(f => f.name === name)!;
return 1 + countArgumentsSize(fn);
};
const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
const transferInPublicSelector = await FunctionSelector.fromSignature(
'transfer_in_public((Field),(Field),u128,Field)',
);
return [
{
classId: tokenClassId,
selector: increaseBalanceSelector,
calldataLength: getCalldataLength('_increase_public_balance'),
onlySelf: true,
},
{
classId: tokenClassId,
selector: transferInPublicSelector,
calldataLength: getCalldataLength('transfer_in_public'),
},
];
}

export type AccountType = 'ecdsar1' | 'schnorr';
export type FeePaymentMethodGetter = (wallet: Wallet, sender: AztecAddress) => Promise<FeePaymentMethod | undefined>;
export type BenchmarkingFeePaymentMethod = 'bridged_fee_juice' | 'private_fpc' | 'sponsored_fpc' | 'fee_juice';
Expand Down
48 changes: 2 additions & 46 deletions yarn-project/end-to-end/src/e2e_fees/fees_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AztecAddress } from '@aztec/aztec.js/addresses';
import { type Logger, createLogger } from '@aztec/aztec.js/log';
import type { AztecNode } from '@aztec/aztec.js/node';
import { CheatCodes } from '@aztec/aztec/testing';
import { CheatCodes, getTokenAllowedSetupFunctions } from '@aztec/aztec/testing';
import { createExtendedL1Client } from '@aztec/ethereum/client';
import { RollupContract } from '@aztec/ethereum/contracts';
import type { DeployAztecL1ContractsArgs } from '@aztec/ethereum/deploy-aztec-l1-contracts';
Expand All @@ -14,16 +14,12 @@ import { AppSubscriptionContract } from '@aztec/noir-contracts.js/AppSubscriptio
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
import { TokenContract as BananaCoin, TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
import { TokenContract as BananaCoin } from '@aztec/noir-contracts.js/Token';
import { CounterContract } from '@aztec/noir-test-contracts.js/Counter';
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi';
import type { FunctionAbi } from '@aztec/stdlib/abi';
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
import { GasSettings } from '@aztec/stdlib/gas';
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';

import { getContract } from 'viem';

Expand All @@ -41,46 +37,6 @@ import { type BalancesFn, getBalancesFn, setupSponsoredFPC } from '../fixtures/u
import { FeeJuicePortalTestingHarnessFactory, type GasBridgingTestHarness } from '../shared/gas_portal_test_harness.js';
import { TestWallet } from '../test-wallet/test_wallet.js';

/** Returns the calldata length for a function: 1 (selector) + arguments size. */
function getCalldataLength(functionName: string): number {
const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat(
TokenContractArtifact.nonDispatchPublicFunctions || [],
);
const fn = allFunctions.find(f => f.name === functionName);
if (!fn) {
throw new Error(`Unknown function ${functionName} in Token artifact`);
}
return 1 + countArgumentsSize(fn);
}

/**
* Returns Token-specific allowlist entries needed for FPC-based fee payments.
* These are test-only — FPC-based fee payment with custom tokens won't work on mainnet alpha.
*/
async function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]> {
const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
const transferInPublicSelector = await FunctionSelector.fromSignature(
'transfer_in_public((Field),(Field),u128,Field)',
);

return [
// Token: needed for private transfers via FPC (transfer_to_public enqueues this)
{
classId: tokenClassId,
selector: increaseBalanceSelector,
calldataLength: getCalldataLength('_increase_public_balance'),
onlySelf: true,
},
// Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
{
classId: tokenClassId,
selector: transferInPublicSelector,
calldataLength: getCalldataLength('transfer_in_public'),
},
];
}

/**
* Test fixture for testing fees. Provides the following setup steps:
* InitialAccounts: Initializes 3 Schnorr account contracts.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,30 @@
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
import { AuthRegistryArtifact } from '@aztec/protocol-contracts/auth-registry';
import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi';
import type { ContractArtifact, FunctionAbi } from '@aztec/stdlib/abi';
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';

/** Returns the expected calldata length for a function: 1 (selector) + arguments size. */
function getCalldataLength(artifact: ContractArtifact, functionName: string): number {
const allFunctions: FunctionAbi[] = (artifact.functions as FunctionAbi[]).concat(
artifact.nonDispatchPublicFunctions || [],
);
const fn = allFunctions.find(f => f.name === functionName);
if (!fn) {
throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`);
}
return 1 + countArgumentsSize(fn);
}
import { buildAllowedElement } from './allowed_setup_helpers.js';

let defaultAllowedSetupFunctions: AllowedElement[] | undefined;

/** Returns the default list of functions allowed to run in the setup phase of a transaction. */
export async function getDefaultAllowedSetupFunctions(): Promise<AllowedElement[]> {
if (defaultAllowedSetupFunctions === undefined) {
const setAuthorizedInternalSelector = await FunctionSelector.fromSignature('_set_authorized((Field),Field,bool)');
const setAuthorizedSelector = await FunctionSelector.fromSignature('set_authorized(Field,bool)');
const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');

defaultAllowedSetupFunctions = [
defaultAllowedSetupFunctions = await Promise.all([
// AuthRegistry: needed for authwit support via private path (set_authorized_private enqueues _set_authorized)
{
address: ProtocolContractAddress.AuthRegistry,
selector: setAuthorizedInternalSelector,
calldataLength: getCalldataLength(AuthRegistryArtifact, '_set_authorized'),
buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, '_set_authorized', {
onlySelf: true,
rejectNullMsgSender: true,
},
}),
// AuthRegistry: needed for authwit support via public path (PublicFeePaymentMethod calls set_authorized directly)
{
address: ProtocolContractAddress.AuthRegistry,
selector: setAuthorizedSelector,
calldataLength: getCalldataLength(AuthRegistryArtifact, 'set_authorized'),
buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, 'set_authorized', {
rejectNullMsgSender: true,
},
}),
// FeeJuice: needed for claiming on the same tx as a spend (claim_and_end_setup enqueues this)
{
address: ProtocolContractAddress.FeeJuice,
selector: increaseBalanceSelector,
calldataLength: getCalldataLength(FeeJuiceArtifact, '_increase_public_balance'),
buildAllowedElement(FeeJuiceArtifact, { address: ProtocolContractAddress.FeeJuice }, '_increase_public_balance', {
onlySelf: true,
},
];
}),
]);
}
return defaultAllowedSetupFunctions;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Fr } from '@aztec/foundation/curves/bn254';
import { FunctionSelector, countArgumentsSize, getAllFunctionAbis } from '@aztec/stdlib/abi';
import type { ContractArtifact } from '@aztec/stdlib/abi';
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';

/**
* Builds an AllowedElement from a contract artifact, deriving both the function selector
* and calldata length from the artifact instead of hardcoding signature strings.
*/
export async function buildAllowedElement(
artifact: ContractArtifact,
target: { address: AztecAddress } | { classId: Fr },
functionName: string,
opts?: { onlySelf?: boolean; rejectNullMsgSender?: boolean },
): Promise<AllowedElement> {
const allFunctions = getAllFunctionAbis(artifact);
const fn = allFunctions.find(f => f.name === functionName);
if (!fn) {
throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`);
}
const selector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
const calldataLength = 1 + countArgumentsSize(fn);
return {
...target,
selector,
calldataLength,
...(opts?.onlySelf ? { onlySelf: true } : {}),
...(opts?.rejectNullMsgSender ? { rejectNullMsgSender: true } : {}),
} as AllowedElement;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
import { FunctionSelector } from '@aztec/stdlib/abi';
import { FunctionSelector, getAllFunctionAbis } from '@aztec/stdlib/abi';
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
import { type Tx, TxExecutionPhase } from '@aztec/stdlib/tx';

Expand All @@ -8,7 +9,10 @@ export type FeePayerBalanceDelta = {
claimAmount: bigint;
};

const increasePublicBalanceSelectorPromise = FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
const increasePublicBalanceSelectorPromise = (() => {
const fn = getAllFunctionAbis(FeeJuiceArtifact).find(f => f.name === '_increase_public_balance')!;
return FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
})();

export function getTxFeeLimit(tx: Tx): bigint {
return tx.data.constants.txContext.gasSettings.getFeeLimit().toBigInt();
Expand Down
1 change: 1 addition & 0 deletions yarn-project/p2p/src/msg_validators/tx_validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './gas_validator.js';
export * from './phases_validator.js';
export * from './test_utils.js';
export * from './allowed_public_setup.js';
export * from './allowed_setup_helpers.js';
export * from './archive_cache.js';
export * from './tx_permitted_validator.js';
export * from './timestamp_validator.js';
Expand Down
Loading