From ffa250a7fd19e81d01e11fb28d48c60047287659 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 16:58:16 +0000 Subject: [PATCH 01/18] cleanup and sponsoredfeepayment in aztecjs --- yarn-project/aztec.js/package.json | 3 +- .../src/account_manager/account_manager.ts | 61 ++++++++++--- .../account_manager/deploy_account_method.ts | 87 ------------------- .../aztec.js/src/account_manager/index.ts | 1 - yarn-project/aztec.js/src/api/fee_testing.ts | 1 + .../aztec.js/src/contract/batch_call.ts | 3 +- .../account_entrypoint_meta_payment_method.ts | 81 +++++++++++++++++ .../src/fee}/sponsored_fee_payment.ts | 4 + yarn-project/aztec/src/index.ts | 1 - yarn-project/aztec/src/sandbox/index.ts | 1 - yarn-project/aztec/src/sandbox/sandbox.ts | 6 +- .../sandbox/sponsored_fee_payment_method.ts | 51 ----------- .../aztec/src/sandbox/sponsored_fpc.ts | 22 +---- .../cli-wallet/src/cmds/create_account.ts | 5 +- .../cli-wallet/src/cmds/deploy_account.ts | 4 +- .../cli-wallet/src/utils/options/fees.ts | 3 +- .../cli/src/cmds/infrastructure/index.ts | 10 ++- .../cmds/infrastructure/setup_l2_contract.ts | 8 +- yarn-project/cli/src/utils/index.ts | 1 + .../{cmds/misc => utils}/setup_contracts.ts | 37 +++++++- yarn-project/constants/src/constants.gen.ts | 17 ++-- yarn-project/constants/src/constants.ts | 1 + .../src/composed/e2e_sandbox_example.test.ts | 2 +- .../end-to-end/src/e2e_fees/fees_test.ts | 40 +++++++-- .../src/e2e_fees/public_payments.test.ts | 2 +- .../src/e2e_fees/sponsored_payments.test.ts | 84 ++++++++++++++++++ .../src/fixtures/snapshot_manager.ts | 11 ++- yarn-project/end-to-end/src/fixtures/utils.ts | 43 ++++++++- yarn-project/entrypoints/package.json | 1 + .../src}/default_multi_call_entrypoint.ts | 23 +++-- yarn-project/entrypoints/src/index.ts | 1 + 31 files changed, 401 insertions(+), 214 deletions(-) delete mode 100644 yarn-project/aztec.js/src/account_manager/deploy_account_method.ts create mode 100644 yarn-project/aztec.js/src/api/fee_testing.ts create mode 100644 yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts rename yarn-project/{cli-wallet/src/utils => aztec.js/src/fee}/sponsored_fee_payment.ts (86%) delete mode 100644 yarn-project/aztec/src/sandbox/sponsored_fee_payment_method.ts rename yarn-project/cli/src/{cmds/misc => utils}/setup_contracts.ts (56%) create mode 100644 yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts rename yarn-project/{aztec.js/src/entrypoint => entrypoints/src}/default_multi_call_entrypoint.ts (82%) diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 2f5ebcf09ac5..de274bb0ee6e 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -23,7 +23,8 @@ "./tx_hash": "./dest/api/tx_hash.js", "./wallet": "./dest/api/wallet.js", "./utils": "./dest/api/utils.js", - "./testing": "./dest/api/testing.js" + "./testing": "./dest/api/testing.js", + "./fee/testing": "./dest/api/fee_testing.js" }, "typedocOptions": { "entryPoints": [ diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 33cfb0b7a805..89cabc276cc6 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -1,3 +1,4 @@ +import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multicall'; import { Fr } from '@aztec/foundation/fields'; import { CompleteAddress, type ContractInstanceWithAddress } from '@aztec/stdlib/contract'; import { getContractInstanceFromDeployParams } from '@aztec/stdlib/contract'; @@ -10,9 +11,9 @@ import type { AccountInterface } from '../account/interface.js'; import { Contract } from '../contract/contract.js'; import { DeployMethod, type DeployOptions } from '../contract/deploy_method.js'; import { DefaultWaitOpts, type WaitOpts } from '../contract/sent_tx.js'; -import { DefaultMultiCallEntrypoint } from '../entrypoint/default_multi_call_entrypoint.js'; +import { AccountEntrypointMetaPaymentMethod } from '../fee/account_entrypoint_meta_payment_method.js'; +import { DeploySentTx, FeeJuicePaymentMethod, type FeePaymentMethod } from '../index.js'; import { AccountWalletWithSecretKey, SignerlessWallet, type Wallet } from '../wallet/index.js'; -import { DeployAccountMethod } from './deploy_account_method.js'; import { DeployAccountSentTx } from './deploy_account_sent_tx.js'; /** @@ -179,14 +180,30 @@ export class AccountManager { // and it can't be used unless the contract is initialized. const wallet = new SignerlessWallet(this.pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion)); - return new DeployAccountMethod( - this.accountContract.getAuthWitnessProvider(completeAddress), + return new DeployMethod( this.getPublicKeys(), wallet, artifact, + address => Contract.at(address, artifact, wallet), constructorArgs, constructorName, + ); + } + + /** + * + * @param originalPaymentMethod + */ + public async getSelfPaymentMethod(originalPaymentMethod?: FeePaymentMethod) { + const artifact = await this.accountContract.getContractArtifact(); + const wallet = await this.getWallet(); + const address = wallet.getAddress(); + return new AccountEntrypointMetaPaymentMethod( + artifact, + wallet, 'entrypoint', + address, + originalPaymentMethod ?? new FeeJuicePaymentMethod(address), ); } @@ -200,15 +217,25 @@ export class AccountManager { */ public deploy(opts?: DeployAccountOptions): DeployAccountSentTx { const sentTx = this.getDeployMethod(opts?.deployWallet) - .then(deployMethod => - deployMethod.send({ - contractAddressSalt: new Fr(this.salt), - skipClassRegistration: opts?.skipClassRegistration ?? true, - skipPublicDeployment: opts?.skipPublicDeployment ?? true, - skipInitialization: opts?.skipInitialization ?? false, - universalDeploy: true, - fee: opts?.fee, - }), + .then( + deployMethod => + new Promise>(async resolve => { + const fee = + !opts?.deployWallet && opts?.fee + ? { ...opts?.fee, paymentMethod: await this.getSelfPaymentMethod(opts?.fee?.paymentMethod) } + : undefined; + + resolve( + deployMethod.send({ + contractAddressSalt: new Fr(this.salt), + skipClassRegistration: opts?.skipClassRegistration ?? true, + skipPublicDeployment: opts?.skipPublicDeployment ?? true, + skipInitialization: opts?.skipInitialization ?? false, + universalDeploy: true, + fee, + }), + ); + }), ) .then(tx => tx.getTxHash()); return new DeployAccountSentTx(this.pxe, sentTx, this.getWallet()); @@ -232,4 +259,12 @@ export class AccountManager { public async isDeployable() { return (await this.accountContract.getDeploymentFunctionAndArgs()) !== undefined; } + + /** + * Returns the contract artifact associated with this manager's account contract. + * @returns The contract artifact. + */ + public getArtifact() { + return this.accountContract.getContractArtifact(); + } } diff --git a/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts b/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts deleted file mode 100644 index 51571a979089..000000000000 --- a/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - EncodedAppEntrypointCalls, - EncodedCallsForEntrypoint, - computeCombinedPayloadHash, -} from '@aztec/entrypoints/encoding'; -import type { AuthWitnessProvider } from '@aztec/entrypoints/interfaces'; -import { ExecutionPayload, mergeExecutionPayloads } from '@aztec/entrypoints/payload'; -import { type ContractArtifact, type FunctionArtifact, getFunctionArtifactByName } from '@aztec/stdlib/abi'; -import type { PublicKeys } from '@aztec/stdlib/keys'; - -import { Contract } from '../contract/contract.js'; -import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; -import { DeployMethod, type DeployOptions } from '../contract/deploy_method.js'; -import type { Wallet } from '../wallet/wallet.js'; - -/** - * Contract interaction for deploying an account contract. Handles fee preparation and contract initialization. - */ -export class DeployAccountMethod extends DeployMethod { - #authWitnessProvider: AuthWitnessProvider; - #feePaymentArtifact: FunctionArtifact | undefined; - - constructor( - authWitnessProvider: AuthWitnessProvider, - publicKeys: PublicKeys, - wallet: Wallet, - artifact: ContractArtifact, - args: any[] = [], - constructorNameOrArtifact?: string | FunctionArtifact, - feePaymentNameOrArtifact?: string | FunctionArtifact, - ) { - super( - publicKeys, - wallet, - artifact, - (address, wallet) => Contract.at(address, artifact, wallet), - args, - constructorNameOrArtifact, - ); - - this.#authWitnessProvider = authWitnessProvider; - this.#feePaymentArtifact = - typeof feePaymentNameOrArtifact === 'string' - ? getFunctionArtifactByName(artifact, feePaymentNameOrArtifact) - : feePaymentNameOrArtifact; - } - - protected override async getInitializeExecutionPayload(options: DeployOptions): Promise { - let exec = await super.getInitializeExecutionPayload(options); - - if (options.fee && this.#feePaymentArtifact) { - const { address } = await this.getInstance(); - const emptyAppCalls = await EncodedAppEntrypointCalls.fromAppExecution([]); - const fee = await this.getDefaultFeeOptions(options.fee); - // Get the execution payload for the fee, it includes the calls and potentially authWitnesses - const { calls: feeCalls, authWitnesses: feeAuthwitnesses } = await fee.paymentMethod.getExecutionPayload( - fee.gasSettings, - ); - // Encode the calls for the fee - const feePayer = await fee.paymentMethod.getFeePayer(fee.gasSettings); - const isFeePayer = feePayer.equals(address); - const feeEncodedCalls = await EncodedCallsForEntrypoint.fromFeeCalls(feeCalls, isFeePayer); - - // Get the entrypoint args - const args = [emptyAppCalls, feeEncodedCalls, false]; - - // Compute the authwitness required to verify the combined payload - const combinedPayloadAuthWitness = await this.#authWitnessProvider.createAuthWit( - await computeCombinedPayloadHash(emptyAppCalls, feeEncodedCalls), - ); - - const call = new ContractFunctionInteraction( - this.wallet, - address, - this.#feePaymentArtifact, - args, - [combinedPayloadAuthWitness, ...feeAuthwitnesses], - [], - [...emptyAppCalls.hashedArguments, ...feeEncodedCalls.hashedArguments], - ); - - exec = mergeExecutionPayloads([exec, await call.request()]); - } - - return exec; - } -} diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index 07441ad79fc9..4a7ae7384a8a 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -1,3 +1,2 @@ export { AccountManager, type DeployAccountOptions } from './account_manager.js'; -export { DeployAccountMethod } from './deploy_account_method.js'; export { type DeployAccountTxReceipt, DeployAccountSentTx } from './deploy_account_sent_tx.js'; diff --git a/yarn-project/aztec.js/src/api/fee_testing.ts b/yarn-project/aztec.js/src/api/fee_testing.ts new file mode 100644 index 000000000000..dc7f930d9faf --- /dev/null +++ b/yarn-project/aztec.js/src/api/fee_testing.ts @@ -0,0 +1 @@ +export { SponsoredFeePaymentMethod } from '../fee/sponsored_fee_payment.js'; diff --git a/yarn-project/aztec.js/src/contract/batch_call.ts b/yarn-project/aztec.js/src/contract/batch_call.ts index 13b748a3baf2..a00de90544da 100644 --- a/yarn-project/aztec.js/src/contract/batch_call.ts +++ b/yarn-project/aztec.js/src/contract/batch_call.ts @@ -1,5 +1,4 @@ -import { ExecutionPayload } from '@aztec/entrypoints/payload'; -import { mergeExecutionPayloads } from '@aztec/entrypoints/payload'; +import { ExecutionPayload, mergeExecutionPayloads } from '@aztec/entrypoints/payload'; import { type FunctionCall, FunctionType, decodeFromAbi } from '@aztec/stdlib/abi'; import type { TxExecutionRequest } from '@aztec/stdlib/tx'; diff --git a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts new file mode 100644 index 000000000000..2318465605c4 --- /dev/null +++ b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts @@ -0,0 +1,81 @@ +import { + EncodedAppEntrypointCalls, + EncodedCallsForEntrypoint, + computeCombinedPayloadHash, +} from '@aztec/entrypoints/encoding'; +import type { AuthWitnessProvider, FeePaymentMethod } from '@aztec/entrypoints/interfaces'; +import { ExecutionPayload } from '@aztec/entrypoints/payload'; +import { + type ContractArtifact, + type FunctionArtifact, + FunctionCall, + FunctionSelector, + encodeArguments, + getFunctionArtifactByName, +} from '@aztec/stdlib/abi'; +import { AztecAddress } from '@aztec/stdlib/aztec-address'; +import type { GasSettings } from '@aztec/stdlib/gas'; + +/** + * Fee payment method that allows a contract to pay for its own deployment + * It works by rerouting the provided fee payment method through the account's entrypoint, + * which sets itself as fee payer. + */ +export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { + constructor( + private artifact: ContractArtifact, + private authWitnessProvider: AuthWitnessProvider, + private feePaymentNameOrArtifact: string | FunctionArtifact, + private address: AztecAddress, + private paymentMethod: FeePaymentMethod, + ) {} + + getAsset(): Promise { + return this.paymentMethod.getAsset(); + } + + async getExecutionPayload(gasSettings: GasSettings): Promise { + const emptyAppCalls = await EncodedAppEntrypointCalls.fromAppExecution([]); + // Get the execution payload for the fee, it includes the calls and potentially authWitnesses + const { calls: feeCalls, authWitnesses: feeAuthwitnesses } = await this.paymentMethod.getExecutionPayload( + gasSettings, + ); + // Encode the calls for the fee + const feePayer = await this.paymentMethod.getFeePayer(gasSettings); + const isFeePayer = feePayer.equals(this.address); + const feeEncodedCalls = await EncodedCallsForEntrypoint.fromFeeCalls(feeCalls, isFeePayer); + + // Get the entrypoint args + const args = [emptyAppCalls, feeEncodedCalls, false]; + const feePaymentArtifact = + typeof this.feePaymentNameOrArtifact === 'string' + ? getFunctionArtifactByName(this.artifact, this.feePaymentNameOrArtifact) + : this.feePaymentNameOrArtifact; + + const entrypointCall = new FunctionCall( + feePaymentArtifact.name, + this.address, + await FunctionSelector.fromNameAndParameters(feePaymentArtifact.name, feePaymentArtifact.parameters), + feePaymentArtifact.functionType, + feePaymentArtifact.isStatic, + encodeArguments(feePaymentArtifact, args), + feePaymentArtifact.returnTypes, + ); + + // Compute the authwitness required to verify the combined payload + const combinedPayloadAuthWitness = await this.authWitnessProvider.createAuthWit( + await computeCombinedPayloadHash(emptyAppCalls, feeEncodedCalls), + ); + + return new ExecutionPayload( + [entrypointCall], + [combinedPayloadAuthWitness, ...feeAuthwitnesses], + [], + [...emptyAppCalls.hashedArguments, ...feeEncodedCalls.hashedArguments], + ); + } + + getFeePayer(gasSettings: GasSettings): Promise { + return this.paymentMethod.getFeePayer(gasSettings); + } +} diff --git a/yarn-project/cli-wallet/src/utils/sponsored_fee_payment.ts b/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts similarity index 86% rename from yarn-project/cli-wallet/src/utils/sponsored_fee_payment.ts rename to yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts index f63f34a2d022..7e05323693bd 100644 --- a/yarn-project/cli-wallet/src/utils/sponsored_fee_payment.ts +++ b/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts @@ -3,6 +3,10 @@ import { ExecutionPayload } from '@aztec/entrypoints/payload'; import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; +/** + * A fee payment method that uses a contract that blidly sponsors transactions. + * This contract is expected to be prefunded in testing environments. + */ export class SponsoredFeePaymentMethod implements FeePaymentMethod { constructor(private paymentContract: AztecAddress) {} diff --git a/yarn-project/aztec/src/index.ts b/yarn-project/aztec/src/index.ts index c024e4167e2f..3718ea80ed4b 100644 --- a/yarn-project/aztec/src/index.ts +++ b/yarn-project/aztec/src/index.ts @@ -3,5 +3,4 @@ export { getDeployedBananaCoinAddress, getDeployedBananaFPCAddress, getDeployedSponsoredFPCAddress, - SponsoredFeePaymentMethod, } from './sandbox/index.js'; diff --git a/yarn-project/aztec/src/sandbox/index.ts b/yarn-project/aztec/src/sandbox/index.ts index 69d0b802a1b2..4f41efff8269 100644 --- a/yarn-project/aztec/src/sandbox/index.ts +++ b/yarn-project/aztec/src/sandbox/index.ts @@ -2,4 +2,3 @@ export * from './sandbox.js'; export { getDeployedBananaCoinAddress, getDeployedBananaFPCAddress } from './banana_fpc.js'; export { getDeployedSponsoredFPCAddress } from './sponsored_fpc.js'; -export { SponsoredFeePaymentMethod } from './sponsored_fee_payment_method.js'; diff --git a/yarn-project/aztec/src/sandbox/sandbox.ts b/yarn-project/aztec/src/sandbox/sandbox.ts index c0df368610c4..ee2dd8f88dc4 100644 --- a/yarn-project/aztec/src/sandbox/sandbox.ts +++ b/yarn-project/aztec/src/sandbox/sandbox.ts @@ -4,7 +4,7 @@ import { deployFundedSchnorrAccounts, getInitialTestAccounts } from '@aztec/acco import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node'; import { AnvilTestWatcher, EthCheatCodes } from '@aztec/aztec.js/testing'; import { type BlobSinkClientInterface, createBlobSinkClient } from '@aztec/blob-sink/client'; -import { setupCanonicalL2FeeJuice } from '@aztec/cli/setup-contracts'; +import { setupCanonicalL2FeeJuice, setupSponsoredFPC } from '@aztec/cli/cli-utils'; import { GENESIS_ARCHIVE_ROOT, GENESIS_BLOCK_HASH } from '@aztec/constants'; import { NULL_KEY, @@ -34,7 +34,7 @@ import { foundry } from 'viem/chains'; import { createAccountLogs } from '../cli/util.js'; import { DefaultMnemonic } from '../mnemonic.js'; import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js'; -import { getSponsoredFPCAddress, setupSponsoredFPC } from './sponsored_fpc.js'; +import { getSponsoredFPCAddress } from './sponsored_fpc.js'; const logger = createLogger('sandbox'); @@ -181,7 +181,7 @@ export async function createSandbox(config: Partial = {}, userLog const deployer = await getSchnorrWallet(pxe, initialAccounts[0].address, initialAccounts[0].signingKey); await setupBananaFPC(initialAccounts, deployer, userLog); - await setupSponsoredFPC(deployer, userLog); + await setupSponsoredFPC(pxe, userLog); } const stop = async () => { diff --git a/yarn-project/aztec/src/sandbox/sponsored_fee_payment_method.ts b/yarn-project/aztec/src/sandbox/sponsored_fee_payment_method.ts deleted file mode 100644 index 29485d326011..000000000000 --- a/yarn-project/aztec/src/sandbox/sponsored_fee_payment_method.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { FeePaymentMethod } from '@aztec/aztec.js'; -import { ExecutionPayload } from '@aztec/entrypoints/payload'; -import { ProtocolContractAddress } from '@aztec/protocol-contracts'; -import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi'; -import type { AztecAddress } from '@aztec/stdlib/aztec-address'; -import type { PXE } from '@aztec/stdlib/interfaces/client'; - -import { getDeployedSponsoredFPCAddress } from './sponsored_fpc.js'; - -/** - * A payment method that uses the SponsoredFPCContract to pay the fee unconditionally. - */ -export class SponsoredFeePaymentMethod implements FeePaymentMethod { - constructor( - /** - * Contract which will pay the fee. - */ - private paymentContract: AztecAddress, - ) {} - - static async new(pxe: PXE) { - const sponsoredFPC = await getDeployedSponsoredFPCAddress(pxe); - return new SponsoredFeePaymentMethod(sponsoredFPC); - } - - getAsset(): Promise { - return Promise.resolve(ProtocolContractAddress.FeeJuice); - } - - getFeePayer(): Promise { - return Promise.resolve(this.paymentContract); - } - - async getExecutionPayload(): Promise { - return new ExecutionPayload( - [ - { - name: 'sponsor_unconditionally', - to: this.paymentContract, - selector: await FunctionSelector.fromSignature('sponsor_unconditionally()'), - type: FunctionType.PRIVATE, - isStatic: false, - args: [], - returnTypes: [], - }, - ], - [], - [], - ); - } -} diff --git a/yarn-project/aztec/src/sandbox/sponsored_fpc.ts b/yarn-project/aztec/src/sandbox/sponsored_fpc.ts index 4c7d698dbe3e..17a44fd1ce97 100644 --- a/yarn-project/aztec/src/sandbox/sponsored_fpc.ts +++ b/yarn-project/aztec/src/sandbox/sponsored_fpc.ts @@ -1,18 +1,10 @@ -import { - type ContractInstanceWithAddress, - Fr, - type PXE, - type Wallet, - getContractInstanceFromDeployParams, -} from '@aztec/aztec.js'; -import type { LogFn } from '@aztec/foundation/log'; +import { type ContractInstanceWithAddress, Fr, type PXE, getContractInstanceFromDeployParams } from '@aztec/aztec.js'; +import { SPONSORED_FPC_SALT } from '@aztec/constants'; import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; -const SPONSORED_FPC_SALT = new Fr(0); - async function getSponsoredFPCInstance(): Promise { return await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { - salt: SPONSORED_FPC_SALT, + salt: new Fr(SPONSORED_FPC_SALT), }); } @@ -20,14 +12,6 @@ export async function getSponsoredFPCAddress() { return (await getSponsoredFPCInstance()).address; } -export async function setupSponsoredFPC(deployer: Wallet, log: LogFn) { - const deployed = await SponsoredFPCContract.deploy(deployer) - .send({ contractAddressSalt: SPONSORED_FPC_SALT, universalDeploy: true }) - .deployed(); - - log(`SponsoredFPC: ${deployed.address}`); -} - export async function getDeployedSponsoredFPCAddress(pxe: PXE) { const fpc = await getSponsoredFPCAddress(); const contracts = await pxe.getContracts(); diff --git a/yarn-project/cli-wallet/src/cmds/create_account.ts b/yarn-project/cli-wallet/src/cmds/create_account.ts index 902aafe0546b..b27200e9b9cc 100644 --- a/yarn-project/cli-wallet/src/cmds/create_account.ts +++ b/yarn-project/cli-wallet/src/cmds/create_account.ts @@ -32,7 +32,7 @@ export async function createAccount( Fr.ZERO, publicKey, ); - const salt = account.getInstance().salt; + const { salt } = account.getInstance(); const { address, publicKeys, partialAddress } = await account.getCompleteAddress(); const out: Record = {}; @@ -65,11 +65,12 @@ export async function createAccount( await account.register(); } else { const wallet = await account.getWallet(); + const feeOptions = await feeOpts.toDeployAccountOpts(wallet); const deployOpts: DeployAccountOptions = { skipClassRegistration: !publicDeploy, skipPublicDeployment: !publicDeploy, skipInitialization: skipInitialization, - ...(await feeOpts.toDeployAccountOpts(wallet)), + fee: { ...feeOptions, paymentMethod: await account.getSelfPaymentMethod(feeOptions.fee?.paymentMethod) }, }; if (feeOpts.estimateOnly) { const gas = await (await account.getDeployMethod(deployOpts.deployWallet)).estimateGas(deployOpts); diff --git a/yarn-project/cli-wallet/src/cmds/deploy_account.ts b/yarn-project/cli-wallet/src/cmds/deploy_account.ts index 910b2b19ca12..858779e34cc9 100644 --- a/yarn-project/cli-wallet/src/cmds/deploy_account.ts +++ b/yarn-project/cli-wallet/src/cmds/deploy_account.ts @@ -40,10 +40,12 @@ export async function deployAccount( let tx; let txReceipt; + const feeOptions = await feeOpts.toDeployAccountOpts(wallet); const deployOpts: DeployAccountOptions = { - ...(await feeOpts.toDeployAccountOpts(wallet)), skipInitialization: false, + fee: { ...feeOptions, paymentMethod: await account.getSelfPaymentMethod(feeOptions.fee?.paymentMethod) }, }; + if (feeOpts.estimateOnly) { const gas = await (await account.getDeployMethod(deployOpts.deployWallet)).estimateGas(deployOpts); if (json) { diff --git a/yarn-project/cli-wallet/src/utils/options/fees.ts b/yarn-project/cli-wallet/src/utils/options/fees.ts index 48d36d173049..6847beef500a 100644 --- a/yarn-project/cli-wallet/src/utils/options/fees.ts +++ b/yarn-project/cli-wallet/src/utils/options/fees.ts @@ -15,7 +15,6 @@ import { Option } from 'commander'; import type { WalletDB } from '../../storage/wallet_db.js'; import { createOrRetrieveAccount } from '../accounts.js'; -import { SponsoredFeePaymentMethod } from '../sponsored_fee_payment.js'; import { aliasedAddressParser } from './options.js'; export type CliFeeArgs = { @@ -325,6 +324,8 @@ export function parsePaymentMethod( } case 'fpc-sponsored': { const sponsor = getFpc(); + log(`Using sponsored fee payment with sponsor ${sponsor}`); + const { SponsoredFeePaymentMethod } = await import('@aztec/aztec.js/fee/testing'); return new SponsoredFeePaymentMethod(sponsor); } case undefined: diff --git a/yarn-project/cli/src/cmds/infrastructure/index.ts b/yarn-project/cli/src/cmds/infrastructure/index.ts index c2386a55fc60..10e5f79dfa20 100644 --- a/yarn-project/cli/src/cmds/infrastructure/index.ts +++ b/yarn-project/cli/src/cmds/infrastructure/index.ts @@ -10,11 +10,19 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger .description('Bootstrap the blockchain by initializing all the protocol contracts') .addOption(pxeOption) .option('--testAccounts', 'Deploy funded test accounts.') + .option('--sponsoredFPC', 'Deploy a sponsored FPC.') .option('--json', 'Output the contract addresses in JSON format') .option('--skipProofWait', "Don't wait for proofs to land.") .action(async options => { const { setupL2Contracts } = await import('./setup_l2_contract.js'); - await setupL2Contracts(options.rpcUrl, options.testAccounts, options.json, options.skipProofWait, log); + await setupL2Contracts( + options.rpcUrl, + options.testAccounts, + options.sponsoredFPC, + options.json, + options.skipProofWait, + log, + ); }); program diff --git a/yarn-project/cli/src/cmds/infrastructure/setup_l2_contract.ts b/yarn-project/cli/src/cmds/infrastructure/setup_l2_contract.ts index cd5d301535c0..a38f7714d09e 100644 --- a/yarn-project/cli/src/cmds/infrastructure/setup_l2_contract.ts +++ b/yarn-project/cli/src/cmds/infrastructure/setup_l2_contract.ts @@ -4,11 +4,12 @@ import { jsonStringify } from '@aztec/foundation/json-rpc'; import type { LogFn } from '@aztec/foundation/log'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; -import { setupCanonicalL2FeeJuice } from '../misc/setup_contracts.js'; +import { setupCanonicalL2FeeJuice, setupSponsoredFPC } from '../../utils/setup_contracts.js'; export async function setupL2Contracts( rpcUrl: string, testAccounts: boolean, + sponsoredFPC: boolean, json: boolean, skipProofWait: boolean, log: LogFn, @@ -42,6 +43,11 @@ export async function setupL2Contracts( await deployFundedSchnorrAccounts(pxe, deployedAccounts, waitOpts); } + if (sponsoredFPC) { + log('setupL2Contracts: Setting up sponsored FPC...'); + await setupSponsoredFPC(pxe, log, waitOpts, waitForProvenOptions); + } + if (json) { const toPrint: Record = { ...ProtocolContractAddress }; deployedAccounts.forEach((a, i) => { diff --git a/yarn-project/cli/src/utils/index.ts b/yarn-project/cli/src/utils/index.ts index 49b74224250b..973e79604592 100644 --- a/yarn-project/cli/src/utils/index.ts +++ b/yarn-project/cli/src/utils/index.ts @@ -2,3 +2,4 @@ export * from './commands.js'; export * from './aztec.js'; export * from './encoding.js'; export * from './github.js'; +export * from './setup_contracts.js'; diff --git a/yarn-project/cli/src/cmds/misc/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts similarity index 56% rename from yarn-project/cli/src/cmds/misc/setup_contracts.ts rename to yarn-project/cli/src/utils/setup_contracts.ts index d7eb7afb5007..df97ff73ec5c 100644 --- a/yarn-project/cli/src/cmds/misc/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -2,12 +2,15 @@ import { DefaultWaitOpts, type EthAddress, FeeJuicePaymentMethod, + Fr, type PXE, SignerlessWallet, type WaitForProvenOpts, + getContractInstanceFromDeployParams, waitForProven, } from '@aztec/aztec.js'; -import { FEE_JUICE_INITIAL_MINT } from '@aztec/constants'; +import { FEE_JUICE_INITIAL_MINT, SPONSORED_FPC_SALT } from '@aztec/constants'; +import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multicall'; import type { LogFn } from '@aztec/foundation/log'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { Gas } from '@aztec/stdlib/gas'; @@ -52,3 +55,35 @@ export async function setupCanonicalL2FeeJuice( ); } } + +export async function setupSponsoredFPC( + pxe: PXE, + log: LogFn, + waitOpts = DefaultWaitOpts, + waitForProvenOptions?: WaitForProvenOpts, +) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { SponsoredFPCContract } = await import('@aztec/noir-contracts.js/SponsoredFPCContract'); + + const { l1ChainId: chainId, protocolVersion } = await pxe.getNodeInfo(); + const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion)); + const sponsoredFPCInstance = await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { + salt: new Fr(SPONSORED_FPC_SALT), + }); + const paymentMethod = new FeeJuicePaymentMethod(sponsoredFPCInstance.address); + + const deployTx = await SponsoredFPCContract.deploy(deployer).send({ + contractAddressSalt: SPONSORED_FPC_SALT, + universalDeploy: true, + fee: { paymentMethod }, + }); + + const deployed = await deployTx.deployed(waitOpts); + + if (waitForProvenOptions !== undefined) { + await waitForProven(pxe, await deployTx.getReceipt(), waitForProvenOptions); + } + + log(`SponsoredFPC: ${deployed.address}`); +} diff --git a/yarn-project/constants/src/constants.gen.ts b/yarn-project/constants/src/constants.gen.ts index 8ee0172dfa83..d3ca12b891ce 100644 --- a/yarn-project/constants/src/constants.gen.ts +++ b/yarn-project/constants/src/constants.gen.ts @@ -92,11 +92,16 @@ export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 19; export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 12; -export const REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = 11121068431693264234253912047066709627593769337094408533543930778360n; -export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = 2889881020989534926461066592611988634597302675057895885580456197069n; -export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 24399338136397901754495080759185489776044879232766421623673792970137n; -export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 14061769416655647708490531650437236735160113654556896985372298487345n; -export const DEPLOYER_CONTRACT_INSTANCE_UPDATED_MAGIC_VALUE = 1534834688047131268740281708431107902615560100979874281215533519862n; +export const REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = + 11121068431693264234253912047066709627593769337094408533543930778360n; +export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = + 2889881020989534926461066592611988634597302675057895885580456197069n; +export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = + 24399338136397901754495080759185489776044879232766421623673792970137n; +export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = + 14061769416655647708490531650437236735160113654556896985372298487345n; +export const DEPLOYER_CONTRACT_INSTANCE_UPDATED_MAGIC_VALUE = + 1534834688047131268740281708431107902615560100979874281215533519862n; export const MAX_PROTOCOL_CONTRACTS = 7; export const CANONICAL_AUTH_REGISTRY_ADDRESS = 1; export const DEPLOYER_CONTRACT_ADDRESS = 2; @@ -412,4 +417,4 @@ export enum GeneratorIndex { SYMMETRIC_KEY_2 = 55, PUBLIC_TX_HASH = 56, PRIVATE_TX_HASH = 57, -} \ No newline at end of file +} diff --git a/yarn-project/constants/src/constants.ts b/yarn-project/constants/src/constants.ts index 8e2f8f06cafb..b5b485566674 100644 --- a/yarn-project/constants/src/constants.ts +++ b/yarn-project/constants/src/constants.ts @@ -1,5 +1,6 @@ // Typescript-land-only constants export const FEE_FUNDING_FOR_TESTER_ACCOUNT = BigInt(1_000e18); +export const SPONSORED_FPC_SALT = BigInt(0); // Autogenerated constants loaded from noir-land export * from './constants.gen.js'; diff --git a/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts b/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts index ff18470ea264..bda6b0551f6a 100644 --- a/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts +++ b/yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts @@ -55,7 +55,6 @@ end-to-end-1 | at Object. (composed/e2e_sandbox_example.test.t import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { getDeployedTestAccountsWallets } from '@aztec/accounts/testing'; import { - SponsoredFeePaymentMethod, getDeployedBananaCoinAddress, getDeployedBananaFPCAddress, getDeployedSponsoredFPCAddress, @@ -70,6 +69,7 @@ import { getFeeJuiceBalance, waitForPXE, } from '@aztec/aztec.js'; +import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee/testing'; import { timesParallel } from '@aztec/foundation/collection'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; diff --git a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts index db8b1daa631b..7e494b23f6b6 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts @@ -18,6 +18,7 @@ import { AppSubscriptionContract } from '@aztec/noir-contracts.js/AppSubscriptio import { CounterContract } from '@aztec/noir-contracts.js/Counter'; 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 } from '@aztec/noir-contracts.js/Token'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; @@ -39,6 +40,7 @@ import { ensureAccountsPubliclyDeployed, getBalancesFn, setupCanonicalFeeJuice, + setupSponsoredFPC, } from '../fixtures/utils.js'; import { FeeJuicePortalTestingHarnessFactory, type GasBridgingTestHarness } from '../shared/gas_portal_test_harness.js'; @@ -50,6 +52,7 @@ const { E2E_DATA_PATH: dataPath } = process.env; * PublicDeployAccounts: Deploys the accounts publicly. * DeployFeeJuice: Deploys the Fee Juice contract. * FPCSetup: Deploys BananaCoin and FPC contracts, and bridges gas from L1. + * SponsoredFPCSetup: Deploys Sponsored FPC contract, and bridges gas from L1. * FundAlice: Mints private and public bananas to Alice. * SetupSubscription: Deploys a counter contract and a subscription contract, and mints Fee Juice to the subscription contract. */ @@ -76,6 +79,7 @@ export class FeesTest { public feeJuiceContract!: FeeJuiceContract; public bananaCoin!: BananaCoin; public bananaFPC!: FPCContract; + public sponsoredFPC!: SponsoredFPCContract; public counterContract!: CounterContract; public subscriptionContract!: AppSubscriptionContract; public feeJuiceBridgeTestHarness!: GasBridgingTestHarness; @@ -240,6 +244,13 @@ export class FeesTest { }, async ({ bananaCoinAddress }) => { this.bananaCoin = await BananaCoin.at(bananaCoinAddress, this.aliceWallet); + const logger = this.logger; + this.getBananaPublicBalanceFn = getBalancesFn('🍌.public', this.bananaCoin.methods.balance_of_public, logger); + this.getBananaPrivateBalanceFn = getBalancesFn( + '🍌.private', + this.bananaCoin.methods.balance_of_private, + logger, + ); }, ); } @@ -271,14 +282,6 @@ export class FeesTest { const bananaFPC = await FPCContract.at(data.bananaFPCAddress, this.aliceWallet); this.bananaFPC = bananaFPC; - const logger = this.logger; - this.getBananaPublicBalanceFn = getBalancesFn('🍌.public', this.bananaCoin.methods.balance_of_public, logger); - this.getBananaPrivateBalanceFn = getBalancesFn( - '🍌.private', - this.bananaCoin.methods.balance_of_private, - logger, - ); - this.getCoinbaseBalance = async () => { const { walletClient } = createL1Clients(context.aztecNodeConfig.l1RpcUrls, MNEMONIC); const gasL1 = getContract({ @@ -315,6 +318,27 @@ export class FeesTest { ); } + public async applySponsoredFPCSetupSnapshot() { + await this.snapshotManager.snapshot( + 'sponsored_fpc_setup', + async context => { + const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; + expect((await context.pxe.getContractMetadata(feeJuiceContract.address)).isContractPubliclyDeployed).toBe(true); + + this.sponsoredFPC = await setupSponsoredFPC(context.pxe); + this.logger.info(`SponsoredFPC deployed at ${this.sponsoredFPC.address}`); + + return { + sponsoredFPCAddress: this.sponsoredFPC.address, + }; + }, + async data => { + const sponsoredFPC = await SponsoredFPCContract.at(data.sponsoredFPCAddress, this.aliceWallet); + this.sponsoredFPC = sponsoredFPC; + }, + ); + } + public async applyFundAliceWithBananas() { await this.snapshotManager.snapshot( 'fund_alice', diff --git a/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts index e83f8e17a810..ca5c9467fa6d 100644 --- a/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts @@ -15,7 +15,7 @@ describe('e2e_fees public_payment', () => { let bananaFPC: FPCContract; let gasSettings: GasSettings; - const t = new FeesTest('private_payment'); + const t = new FeesTest('public_payment'); beforeAll(async () => { await t.applyBaseSnapshots(); diff --git a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts new file mode 100644 index 000000000000..de2b1850824e --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts @@ -0,0 +1,84 @@ +import { type AccountWallet, type AztecAddress } from '@aztec/aztec.js'; +import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee/testing'; +import type { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; +import type { TokenContract } from '@aztec/noir-contracts.js/Token'; +import { GasSettings } from '@aztec/stdlib/gas'; + +import { expectMapping } from '../fixtures/utils.js'; +import { FeesTest } from './fees_test.js'; + +describe('e2e_fees sponsored_public_payment', () => { + let aliceWallet: AccountWallet; + let aliceAddress: AztecAddress; + let bobAddress: AztecAddress; + let sequencerAddress: AztecAddress; + let sponsoredFPC: SponsoredFPCContract; + let gasSettings: GasSettings; + let bananaCoin: TokenContract; + + const t = new FeesTest('sponsored_payment'); + + beforeAll(async () => { + await t.applyBaseSnapshots(); + await t.applySponsoredFPCSetupSnapshot(); + await t.applyFundAliceWithBananas(); + ({ aliceWallet, aliceAddress, bobAddress, sequencerAddress, sponsoredFPC, bananaCoin, gasSettings } = + await t.setup()); + }); + + afterAll(async () => { + await t.teardown(); + }); + + let initialAlicePublicBananas: bigint; + let initialAliceGas: bigint; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + let initialBobPublicBananas: bigint; + + let initialFPCGas: bigint; + + let initialSequencerGas: bigint; + + beforeEach(async () => { + gasSettings = GasSettings.from({ + ...gasSettings, + maxFeesPerGas: await aliceWallet.getCurrentBaseFees(), + }); + + [[initialAlicePublicBananas, initialBobPublicBananas], [initialAliceGas, initialFPCGas, initialSequencerGas]] = + await Promise.all([ + t.getBananaPublicBalanceFn(aliceAddress, bobAddress), + t.getGasBalanceFn(aliceAddress, sponsoredFPC.address, sequencerAddress), + ]); + }); + + it('pays fees for tx that make public transfer', async () => { + const bananasToSendToBob = 10n; + // docs:start:sponsored_fpc + const tx = await bananaCoin.methods + .transfer_in_public(aliceAddress, bobAddress, bananasToSendToBob, 0) + .send({ + fee: { + gasSettings, + paymentMethod: new SponsoredFeePaymentMethod(sponsoredFPC.address), + }, + }) + .wait(); + // docs:end:sponsored_fpc + + const feeAmount = tx.transactionFee!; + + await expectMapping( + t.getBananaPublicBalanceFn, + [aliceAddress, bobAddress], + [initialAlicePublicBananas - bananasToSendToBob, bananasToSendToBob], + ); + + await expectMapping( + t.getGasBalanceFn, + [aliceAddress, sponsoredFPC.address, sequencerAddress], + [initialAliceGas, initialFPCGas - feeAmount, initialSequencerGas], + ); + }); +}); diff --git a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts index 5d37c9505480..470f1c5cabf5 100644 --- a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts +++ b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts @@ -49,7 +49,13 @@ import { MNEMONIC, TEST_PEER_CHECK_INTERVAL_MS } from './fixtures.js'; import { getACVMConfig } from './get_acvm_config.js'; import { getBBConfig } from './get_bb_config.js'; import { setupL1Contracts } from './setup_l1_contracts.js'; -import { type SetupOptions, createAndSyncProverNode, getLogger, getPrivateKeyFromIndex } from './utils.js'; +import { + type SetupOptions, + createAndSyncProverNode, + getLogger, + getPrivateKeyFromIndex, + getSponsoredFPCAddress, +} from './utils.js'; import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js'; export type SubsystemsContext = { @@ -336,8 +342,9 @@ async function setupFromFresh( } const initialFundedAccounts = await generateSchnorrAccounts(numberOfInitialFundedAccounts); + const sponsoredFPCAddress = await getSponsoredFPCAddress(); const { genesisArchiveRoot, genesisBlockHash, prefilledPublicData } = await getGenesisValues( - initialFundedAccounts.map(a => a.address), + initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress), opts.initialAccountFeeJuice, ); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index f2cfacde9633..da57539c958b 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -26,11 +26,13 @@ import { waitForPXE, } from '@aztec/aztec.js'; import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; +import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee/testing'; import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec.js/testing'; import type { BBNativePrivateKernelProver } from '@aztec/bb-prover'; import { createBlobSinkClient } from '@aztec/blob-sink/client'; import { type BlobSinkServer, createBlobSinkServer } from '@aztec/blob-sink/server'; -import { FEE_JUICE_INITIAL_MINT, GENESIS_ARCHIVE_ROOT, GENESIS_BLOCK_HASH } from '@aztec/constants'; +import { FEE_JUICE_INITIAL_MINT, GENESIS_ARCHIVE_ROOT, GENESIS_BLOCK_HASH, SPONSORED_FPC_SALT } from '@aztec/constants'; +import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multicall'; import { type DeployL1ContractsArgs, type DeployL1ContractsReturnType, @@ -49,13 +51,14 @@ import { Fr } from '@aztec/foundation/fields'; import { retryUntil } from '@aztec/foundation/retry'; import { TestDateProvider } from '@aztec/foundation/timer'; import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice'; +import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { ProtocolContractAddress, protocolContractTreeRoot } from '@aztec/protocol-contracts'; import { type ProverNode, type ProverNodeConfig, createProverNode } from '@aztec/prover-node'; import { type PXEService, type PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe/server'; import type { SequencerClient } from '@aztec/sequencer-client'; import type { TestSequencerClient } from '@aztec/sequencer-client/test'; -import { getContractClassFromArtifact } from '@aztec/stdlib/contract'; +import { getContractClassFromArtifact, getContractInstanceFromDeployParams } from '@aztec/stdlib/contract'; import { Gas } from '@aztec/stdlib/gas'; import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client'; import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees'; @@ -720,7 +723,7 @@ export async function expectMappingDelta( } /** - * Deploy the protocol contracts to a running instance. + * Deploy the canonical Fee Juice contract to a running instance. */ export async function setupCanonicalFeeJuice(pxe: PXE) { // "deploy" the Fee Juice as it contains public functions @@ -740,6 +743,40 @@ export async function setupCanonicalFeeJuice(pxe: PXE) { } } +/** + * Computes the address of the "canonical" SponosoredFPCContract. This is not a protocol contract + * but by conventions its address is computed with a salt of 0. + * @returns The address of the sponsored FPC contract + */ +export async function getSponsoredFPCAddress() { + const sponsoredFPCInstance = await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { + salt: new Fr(SPONSORED_FPC_SALT), + }); + return sponsoredFPCInstance.address; +} + +/** + * Deploy a sponsored FPC contract to a running instance. + */ +export async function setupSponsoredFPC(pxe: PXE) { + const { l1ChainId: chainId, protocolVersion } = await pxe.getNodeInfo(); + const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion)); + + // Make the contract pay for the deployment fee itself + const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress()); + + const deployed = await SponsoredFPCContract.deploy(deployer) + .send({ + contractAddressSalt: new Fr(SPONSORED_FPC_SALT), + universalDeploy: true, + fee: { paymentMethod }, + }) + .deployed(); + + getLogger().info(`SponsoredFPC: ${deployed.address}`); + return deployed; +} + export async function waitForProvenChain(node: AztecNode, targetBlock?: number, timeoutSec = 60, intervalSec = 1) { targetBlock ??= await node.getBlockNumber(); diff --git a/yarn-project/entrypoints/package.json b/yarn-project/entrypoints/package.json index f9fbc81ca1a2..ce1740e7fbe2 100644 --- a/yarn-project/entrypoints/package.json +++ b/yarn-project/entrypoints/package.json @@ -8,6 +8,7 @@ "./dapp": "./dest/dapp_entrypoint.js", "./account": "./dest/account_entrypoint.js", "./default": "./dest/default_entrypoint.js", + "./multicall": "./dest/default_multi_call_entrypoint.js", "./interfaces": "./dest/interfaces.js", "./payload": "./dest/payload.js", "./encoding": "./dest/encoding.js" diff --git a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts b/yarn-project/entrypoints/src/default_multi_call_entrypoint.ts similarity index 82% rename from yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts rename to yarn-project/entrypoints/src/default_multi_call_entrypoint.ts index 785a06e8dc2d..50100d9becd9 100644 --- a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts +++ b/yarn-project/entrypoints/src/default_multi_call_entrypoint.ts @@ -1,11 +1,12 @@ -import { EncodedCallsForEntrypoint } from '@aztec/entrypoints/encoding'; -import type { EntrypointInterface, FeeOptions } from '@aztec/entrypoints/interfaces'; -import { ExecutionPayload } from '@aztec/entrypoints/payload'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { type FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { HashedValues, TxContext, TxExecutionRequest } from '@aztec/stdlib/tx'; +import { EncodedCallsForEntrypoint } from './encoding.js'; +import type { EntrypointInterface, FeeOptions } from './interfaces.js'; +import type { ExecutionPayload } from './payload.js'; + /** * Implementation for an entrypoint interface that can execute multiple function calls in a single transaction */ @@ -20,8 +21,16 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { // Initial request with calls, authWitnesses and capsules const { calls, authWitnesses, capsules, extraHashedArgs } = exec; - // Encode the calls - const encodedCalls = await EncodedCallsForEntrypoint.fromAppExecution(calls); + // Get the execution payload for the fee, it includes the calls and potentially authWitnesses + const { + calls: feeCalls, + authWitnesses: feeAuthwitnesses, + extraHashedArgs: feeExtraHashedArgs, + } = await fee.paymentMethod.getExecutionPayload(fee.gasSettings); + + // Encode the calls, including the fee calls + // (since this entrypoint does not distinguish between app and fee calls) + const encodedCalls = await EncodedCallsForEntrypoint.fromAppExecution(calls.concat(feeCalls)); // Obtain the entrypoint hashed args, built from the encoded calls const abi = this.getEntrypointAbi(); @@ -33,8 +42,8 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { origin: this.address, functionSelector: await FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), txContext: new TxContext(this.chainId, this.version, fee.gasSettings), - argsOfCalls: [...encodedCalls.hashedArguments, entrypointHashedArgs, ...extraHashedArgs], - authWitnesses, + argsOfCalls: [...encodedCalls.hashedArguments, entrypointHashedArgs, ...extraHashedArgs, ...feeExtraHashedArgs], + authWitnesses: [...feeAuthwitnesses, ...authWitnesses], capsules, }); diff --git a/yarn-project/entrypoints/src/index.ts b/yarn-project/entrypoints/src/index.ts index 2c31758ff989..8a7d8664b94f 100644 --- a/yarn-project/entrypoints/src/index.ts +++ b/yarn-project/entrypoints/src/index.ts @@ -11,3 +11,4 @@ export * from './dapp_entrypoint.js'; export * from './interfaces.js'; export * from './default_entrypoint.js'; export * from './encoding.js'; +export * from './default_multi_call_entrypoint.js'; From e995b96423544714a6351ef12377e272117bd742 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 17:00:19 +0000 Subject: [PATCH 02/18] fmt --- yarn-project/cli/package.json | 1 + yarn-project/cli/tsconfig.json | 3 +++ .../end-to-end/src/e2e_fees/sponsored_payments.test.ts | 2 +- yarn-project/yarn.lock | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index b8410bd1fe06..9456c2fb07d7 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -70,6 +70,7 @@ "@aztec/archiver": "workspace:^", "@aztec/aztec.js": "workspace:^", "@aztec/constants": "workspace:^", + "@aztec/entrypoints": "workspace:^", "@aztec/foundation": "workspace:^", "@aztec/l1-artifacts": "workspace:^", "@aztec/p2p": "workspace:^", diff --git a/yarn-project/cli/tsconfig.json b/yarn-project/cli/tsconfig.json index de0c9beda9b0..1676df9854eb 100644 --- a/yarn-project/cli/tsconfig.json +++ b/yarn-project/cli/tsconfig.json @@ -15,6 +15,9 @@ { "path": "../constants" }, + { + "path": "../entrypoints" + }, { "path": "../foundation" }, diff --git a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts index de2b1850824e..3894344d01e7 100644 --- a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts @@ -1,4 +1,4 @@ -import { type AccountWallet, type AztecAddress } from '@aztec/aztec.js'; +import type { AccountWallet, AztecAddress } from '@aztec/aztec.js'; import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee/testing'; import type { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; import type { TokenContract } from '@aztec/noir-contracts.js/Token'; diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index c95ddaf01a43..9e21721640c1 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -501,6 +501,7 @@ __metadata: "@aztec/archiver": "workspace:^" "@aztec/aztec.js": "workspace:^" "@aztec/constants": "workspace:^" + "@aztec/entrypoints": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" "@aztec/l1-artifacts": "workspace:^" From 1f11dd96498aad0cf4675f02478312fc14700c72 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 17:08:51 +0000 Subject: [PATCH 03/18] jsdoc --- .../aztec.js/src/account_manager/account_manager.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 89cabc276cc6..e22a9d5c767f 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -191,8 +191,10 @@ export class AccountManager { } /** - * - * @param originalPaymentMethod + * Returns a FeePaymentMethod that routes the original one provided as an argument + * through the account's entrypoint. This allows an account contract to pay + * for its own deployment and initialization. + * @param originalPaymentMethod The original payment method to be wrapped. */ public async getSelfPaymentMethod(originalPaymentMethod?: FeePaymentMethod) { const artifact = await this.accountContract.getContractArtifact(); From 7ae1dca49187f970d8594c4ea60374abea9a3b76 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 17:58:35 +0000 Subject: [PATCH 04/18] simplification --- .../src/account_manager/account_manager.ts | 94 +++++++++++-------- .../account_entrypoint_meta_payment_method.ts | 6 +- .../cli-wallet/src/cmds/create_account.ts | 4 +- .../cli-wallet/src/cmds/deploy_account.ts | 4 +- yarn-project/cli/src/utils/setup_contracts.ts | 2 +- 5 files changed, 65 insertions(+), 45 deletions(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index e22a9d5c767f..3b2a304f99bb 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -2,6 +2,7 @@ import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multicall'; import { Fr } from '@aztec/foundation/fields'; import { CompleteAddress, type ContractInstanceWithAddress } from '@aztec/stdlib/contract'; import { getContractInstanceFromDeployParams } from '@aztec/stdlib/contract'; +import type { GasSettings } from '@aztec/stdlib/gas'; import type { PXE } from '@aztec/stdlib/interfaces/client'; import { deriveKeys } from '@aztec/stdlib/keys'; @@ -12,7 +13,7 @@ import { Contract } from '../contract/contract.js'; import { DeployMethod, type DeployOptions } from '../contract/deploy_method.js'; import { DefaultWaitOpts, type WaitOpts } from '../contract/sent_tx.js'; import { AccountEntrypointMetaPaymentMethod } from '../fee/account_entrypoint_meta_payment_method.js'; -import { DeploySentTx, FeeJuicePaymentMethod, type FeePaymentMethod } from '../index.js'; +import { FeeJuicePaymentMethod, type FeePaymentMethod } from '../index.js'; import { AccountWalletWithSecretKey, SignerlessWallet, type Wallet } from '../wallet/index.js'; import { DeployAccountSentTx } from './deploy_account_sent_tx.js'; @@ -140,12 +141,11 @@ export class AccountManager { /** * Returns the pre-populated deployment method to deploy the account contract that backs this account. - * Typically you will not need this method and can call `deploy` directly. Use this for having finer - * grained control on when to create, simulate, and send the deployment tx. + * If no wallet is provided, it uses a signerless wallet with the multi call entrypoint * @param deployWallet - Wallet used for deploying the account contract. - * @returns A DeployMethod instance that deploys this account contract. + * @returns A DeployMethod instance that deploys this account contract */ - public async getDeployMethod(deployWallet?: Wallet) { + async #getDeployMethod(deployWallet?: Wallet): Promise { const artifact = await this.accountContract.getContractArtifact(); if (!(await this.isDeployable())) { @@ -164,7 +164,7 @@ export class AccountManager { if (deployWallet) { // If deploying using an existing wallet/account, treat it like regular contract deployment. const thisWallet = await this.getWallet(); - return new DeployMethod( + new DeployMethod( this.getPublicKeys(), deployWallet, artifact, @@ -194,9 +194,10 @@ export class AccountManager { * Returns a FeePaymentMethod that routes the original one provided as an argument * through the account's entrypoint. This allows an account contract to pay * for its own deployment and initialization. - * @param originalPaymentMethod The original payment method to be wrapped. + * @param originalPaymentMethod - originalPaymentMethod The original payment method to be wrapped. + * @returns A FeePaymentMethod that routes the original one through the account's entrypoint (AccountEntrypointMetaPaymentMethod) */ - public async getSelfPaymentMethod(originalPaymentMethod?: FeePaymentMethod) { + async #getSelfPaymentMethod(originalPaymentMethod?: FeePaymentMethod) { const artifact = await this.accountContract.getContractArtifact(); const wallet = await this.getWallet(); const address = wallet.getAddress(); @@ -218,31 +219,58 @@ export class AccountManager { * @returns A SentTx object that can be waited to get the associated Wallet. */ public deploy(opts?: DeployAccountOptions): DeployAccountSentTx { - const sentTx = this.getDeployMethod(opts?.deployWallet) - .then( - deployMethod => - new Promise>(async resolve => { - const fee = - !opts?.deployWallet && opts?.fee - ? { ...opts?.fee, paymentMethod: await this.getSelfPaymentMethod(opts?.fee?.paymentMethod) } - : undefined; - - resolve( - deployMethod.send({ - contractAddressSalt: new Fr(this.salt), - skipClassRegistration: opts?.skipClassRegistration ?? true, - skipPublicDeployment: opts?.skipPublicDeployment ?? true, - skipInitialization: opts?.skipInitialization ?? false, - universalDeploy: true, - fee, - }), - ); - }), - ) + let deployMethod: DeployMethod; + const sentTx = this.#getDeployMethod(opts?.deployWallet) + .then(method => { + deployMethod = method; + if (!opts?.deployWallet && opts?.fee) { + return this.#getSelfPaymentMethod(opts?.fee?.paymentMethod); + } + }) + .then(maybeWrappedPaymentMethod => { + let fee = opts?.fee; + if (maybeWrappedPaymentMethod) { + fee = { ...opts?.fee, paymentMethod: maybeWrappedPaymentMethod }; + } + return deployMethod.send({ + contractAddressSalt: new Fr(this.salt), + skipClassRegistration: opts?.skipClassRegistration ?? true, + skipPublicDeployment: opts?.skipPublicDeployment ?? true, + skipInitialization: opts?.skipInitialization ?? false, + universalDeploy: true, + fee, + }); + }) .then(tx => tx.getTxHash()); return new DeployAccountSentTx(this.pxe, sentTx, this.getWallet()); } + /** + * Deploys the account contract that backs this account. + * Does not register the associated class nor publicly deploy the instance by default. + * Uses the salt provided in the constructor or a randomly generated one. + * Registers the account in the PXE Service before deploying the contract. + * @param opts - Fee options to be used for the deployment. + * @returns A SentTx object that can be waited to get the associated Wallet. + */ + public async estimateDeploymentGas( + opts?: DeployAccountOptions, + ): Promise> { + const deployMethod = await this.#getDeployMethod(opts?.deployWallet); + const fee = + !opts?.deployWallet && opts?.fee + ? { ...opts.fee, paymentMethod: await this.#getSelfPaymentMethod(opts.fee.paymentMethod) } + : opts?.fee; + return deployMethod.estimateGas({ + contractAddressSalt: new Fr(this.salt), + skipClassRegistration: opts?.skipClassRegistration ?? true, + skipPublicDeployment: opts?.skipPublicDeployment ?? true, + skipInitialization: opts?.skipInitialization ?? false, + universalDeploy: true, + fee, + }); + } + /** * Deploys the account contract that backs this account if needed and awaits the tx to be mined. * Uses the salt provided in the constructor or a randomly generated one. If no initialization @@ -261,12 +289,4 @@ export class AccountManager { public async isDeployable() { return (await this.accountContract.getDeploymentFunctionAndArgs()) !== undefined; } - - /** - * Returns the contract artifact associated with this manager's account contract. - * @returns The contract artifact. - */ - public getArtifact() { - return this.accountContract.getContractArtifact(); - } } diff --git a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts index 2318465605c4..de7d10329cc7 100644 --- a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts @@ -26,7 +26,7 @@ export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { private artifact: ContractArtifact, private authWitnessProvider: AuthWitnessProvider, private feePaymentNameOrArtifact: string | FunctionArtifact, - private address: AztecAddress, + private accountAddress: AztecAddress, private paymentMethod: FeePaymentMethod, ) {} @@ -42,7 +42,7 @@ export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { ); // Encode the calls for the fee const feePayer = await this.paymentMethod.getFeePayer(gasSettings); - const isFeePayer = feePayer.equals(this.address); + const isFeePayer = feePayer.equals(this.accountAddress); const feeEncodedCalls = await EncodedCallsForEntrypoint.fromFeeCalls(feeCalls, isFeePayer); // Get the entrypoint args @@ -54,7 +54,7 @@ export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { const entrypointCall = new FunctionCall( feePaymentArtifact.name, - this.address, + this.accountAddress, await FunctionSelector.fromNameAndParameters(feePaymentArtifact.name, feePaymentArtifact.parameters), feePaymentArtifact.functionType, feePaymentArtifact.isStatic, diff --git a/yarn-project/cli-wallet/src/cmds/create_account.ts b/yarn-project/cli-wallet/src/cmds/create_account.ts index b27200e9b9cc..944a76f6d944 100644 --- a/yarn-project/cli-wallet/src/cmds/create_account.ts +++ b/yarn-project/cli-wallet/src/cmds/create_account.ts @@ -70,10 +70,10 @@ export async function createAccount( skipClassRegistration: !publicDeploy, skipPublicDeployment: !publicDeploy, skipInitialization: skipInitialization, - fee: { ...feeOptions, paymentMethod: await account.getSelfPaymentMethod(feeOptions.fee?.paymentMethod) }, + fee: feeOptions.fee, }; if (feeOpts.estimateOnly) { - const gas = await (await account.getDeployMethod(deployOpts.deployWallet)).estimateGas(deployOpts); + const gas = await account.estimateDeploymentGas(deployOpts); if (json) { out.fee = { gasLimits: { diff --git a/yarn-project/cli-wallet/src/cmds/deploy_account.ts b/yarn-project/cli-wallet/src/cmds/deploy_account.ts index 858779e34cc9..49028ee6304f 100644 --- a/yarn-project/cli-wallet/src/cmds/deploy_account.ts +++ b/yarn-project/cli-wallet/src/cmds/deploy_account.ts @@ -43,11 +43,11 @@ export async function deployAccount( const feeOptions = await feeOpts.toDeployAccountOpts(wallet); const deployOpts: DeployAccountOptions = { skipInitialization: false, - fee: { ...feeOptions, paymentMethod: await account.getSelfPaymentMethod(feeOptions.fee?.paymentMethod) }, + fee: feeOptions.fee, }; if (feeOpts.estimateOnly) { - const gas = await (await account.getDeployMethod(deployOpts.deployWallet)).estimateGas(deployOpts); + const gas = await account.estimateDeploymentGas(deployOpts); if (json) { out.fee = { gasLimits: { diff --git a/yarn-project/cli/src/utils/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts index df97ff73ec5c..0a6e62e206a1 100644 --- a/yarn-project/cli/src/utils/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -64,7 +64,7 @@ export async function setupSponsoredFPC( ) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment - const { SponsoredFPCContract } = await import('@aztec/noir-contracts.js/SponsoredFPCContract'); + const { SponsoredFPCContract } = await import('@aztec/noir-contracts.js/SponsoredFPC'); const { l1ChainId: chainId, protocolVersion } = await pxe.getNodeInfo(); const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion)); From 33fe140b81d9cdfeb9cc2dc97314ab2e16bc3658 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 17:59:07 +0000 Subject: [PATCH 05/18] typo --- yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts b/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts index 7e05323693bd..0ca0ef6da1a3 100644 --- a/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts +++ b/yarn-project/aztec.js/src/fee/sponsored_fee_payment.ts @@ -4,7 +4,7 @@ import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; /** - * A fee payment method that uses a contract that blidly sponsors transactions. + * A fee payment method that uses a contract that blindly sponsors transactions. * This contract is expected to be prefunded in testing environments. */ export class SponsoredFeePaymentMethod implements FeePaymentMethod { From 0b4590fbb9d37a38b0fba373d708173cc135405c Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 17:59:55 +0000 Subject: [PATCH 06/18] typo, gh let me commit suggestions dammit --- yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts index 3894344d01e7..26b2392e13d2 100644 --- a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts @@ -53,7 +53,7 @@ describe('e2e_fees sponsored_public_payment', () => { ]); }); - it('pays fees for tx that make public transfer', async () => { + it('pays fees for tx that makes a public transfer', async () => { const bananasToSendToBob = 10n; // docs:start:sponsored_fpc const tx = await bananaCoin.methods From 5aafd98a075317f871bad3a804c7d7e3f98d8f50 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 18:06:53 +0000 Subject: [PATCH 07/18] fmt --- yarn-project/cli/src/utils/setup_contracts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/cli/src/utils/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts index 0a6e62e206a1..c80f0f19c6e8 100644 --- a/yarn-project/cli/src/utils/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -74,7 +74,7 @@ export async function setupSponsoredFPC( const paymentMethod = new FeeJuicePaymentMethod(sponsoredFPCInstance.address); const deployTx = await SponsoredFPCContract.deploy(deployer).send({ - contractAddressSalt: SPONSORED_FPC_SALT, + contractAddressSalt: new Fr(SPONSORED_FPC_SALT), universalDeploy: true, fee: { paymentMethod }, }); From ec5d98c0c2dbde9975ce96c0edc7fe88015ce6d9 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 18:14:03 +0000 Subject: [PATCH 08/18] can't read --- yarn-project/cli/src/utils/setup_contracts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/cli/src/utils/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts index c80f0f19c6e8..8e2f2bc5560e 100644 --- a/yarn-project/cli/src/utils/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -73,7 +73,7 @@ export async function setupSponsoredFPC( }); const paymentMethod = new FeeJuicePaymentMethod(sponsoredFPCInstance.address); - const deployTx = await SponsoredFPCContract.deploy(deployer).send({ + const deployTx = SponsoredFPCContract.deploy(deployer).send({ contractAddressSalt: new Fr(SPONSORED_FPC_SALT), universalDeploy: true, fee: { paymentMethod }, From a1ee2d5b44268412663ef3bb1e3bee51d681f6ef Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 18:46:06 +0000 Subject: [PATCH 09/18] comment and return --- .../aztec.js/src/account_manager/account_manager.ts | 2 +- .../src/fee/account_entrypoint_meta_payment_method.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 3b2a304f99bb..575ecd152869 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -164,7 +164,7 @@ export class AccountManager { if (deployWallet) { // If deploying using an existing wallet/account, treat it like regular contract deployment. const thisWallet = await this.getWallet(); - new DeployMethod( + return new DeployMethod( this.getPublicKeys(), deployWallet, artifact, diff --git a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts index de7d10329cc7..236a0b894d06 100644 --- a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts @@ -20,6 +20,15 @@ import type { GasSettings } from '@aztec/stdlib/gas'; * Fee payment method that allows a contract to pay for its own deployment * It works by rerouting the provided fee payment method through the account's entrypoint, * which sets itself as fee payer. + * + * Usually, in order to pay fees it is necessary to obtain an ExecutionPayload that encodes the necessary information + * That is sent to the user's account entrypoint, that has plumbing to handle a fee payload. + * If there's no account contract yet (it's being deployed) a MultiCallContract is used, which doesn't have a concept of fees or + * how to handle this payload. + * HOWEVER,the account contract entrypoint does, so this method reshapes that fee payload into a call to the account contract entrypoint + * being deployed with the original fee payload. + * + * This class can be seen in action in AccountManager.ts -> #getSelfPaymentMethod */ export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { constructor( From 7fb2aeec1025b8e151b7d3d64f5ecf8c8f567e63 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 18:57:42 +0000 Subject: [PATCH 10/18] more fixes --- yarn-project/aztec.js/src/api/fee.ts | 1 + .../aztec.js/src/fee/account_entrypoint_meta_payment_method.ts | 2 +- yarn-project/cli/src/utils/setup_contracts.ts | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/yarn-project/aztec.js/src/api/fee.ts b/yarn-project/aztec.js/src/api/fee.ts index ec3e7762646a..832272f6a08f 100644 --- a/yarn-project/aztec.js/src/api/fee.ts +++ b/yarn-project/aztec.js/src/api/fee.ts @@ -3,3 +3,4 @@ export { FeeJuicePaymentMethod } from '../fee/fee_juice_payment_method.js'; export { PrivateFeePaymentMethod } from '../fee/private_fee_payment_method.js'; export { PublicFeePaymentMethod } from '../fee/public_fee_payment_method.js'; export { FeeJuicePaymentMethodWithClaim } from '../fee/fee_juice_payment_method_with_claim.js'; +export { SponsoredFeePaymentMethod } from '../fee/sponsored_fee_payment.js'; diff --git a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts index 236a0b894d06..64c0135f7604 100644 --- a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts @@ -28,7 +28,7 @@ import type { GasSettings } from '@aztec/stdlib/gas'; * HOWEVER,the account contract entrypoint does, so this method reshapes that fee payload into a call to the account contract entrypoint * being deployed with the original fee payload. * - * This class can be seen in action in AccountManager.ts -> #getSelfPaymentMethod + * This class can be seen in action in AccountManager.ts#getSelfPaymentMethod */ export class AccountEntrypointMetaPaymentMethod implements FeePaymentMethod { constructor( diff --git a/yarn-project/cli/src/utils/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts index 8e2f2bc5560e..9383c7fc94e2 100644 --- a/yarn-project/cli/src/utils/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -5,6 +5,7 @@ import { Fr, type PXE, SignerlessWallet, + SponsoredFeePaymentMethod, type WaitForProvenOpts, getContractInstanceFromDeployParams, waitForProven, @@ -71,7 +72,7 @@ export async function setupSponsoredFPC( const sponsoredFPCInstance = await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { salt: new Fr(SPONSORED_FPC_SALT), }); - const paymentMethod = new FeeJuicePaymentMethod(sponsoredFPCInstance.address); + const paymentMethod = new SponsoredFeePaymentMethod(sponsoredFPCInstance.address); const deployTx = SponsoredFPCContract.deploy(deployer).send({ contractAddressSalt: new Fr(SPONSORED_FPC_SALT), From 23a19dc9aadcb9d9b2829c9994301c50205f6bf2 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:01:56 +0000 Subject: [PATCH 11/18] outdated comment --- .../aztec.js/src/account_manager/account_manager.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 575ecd152869..5c361e18aa64 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -246,10 +246,9 @@ export class AccountManager { } /** - * Deploys the account contract that backs this account. - * Does not register the associated class nor publicly deploy the instance by default. - * Uses the salt provided in the constructor or a randomly generated one. - * Registers the account in the PXE Service before deploying the contract. + * Estimates the gas needed to deploy the account contract that backs this account. + * This method is here to ensure that the fee payment method is correctly set up in case + * the account contract needs to pay for its own deployment. * @param opts - Fee options to be used for the deployment. * @returns A SentTx object that can be waited to get the associated Wallet. */ From 7190085e402485f164643e0b8373b3b56b86850c Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:02:20 +0000 Subject: [PATCH 12/18] comment --- yarn-project/aztec.js/src/account_manager/account_manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 5c361e18aa64..79208fdb9c79 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -250,7 +250,7 @@ export class AccountManager { * This method is here to ensure that the fee payment method is correctly set up in case * the account contract needs to pay for its own deployment. * @param opts - Fee options to be used for the deployment. - * @returns A SentTx object that can be waited to get the associated Wallet. + * @returns The gas estimations for the account contract deployment and initialization. */ public async estimateDeploymentGas( opts?: DeployAccountOptions, From 332f2b0a7d9d58897a280cf75065e2e4a7430568 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:14:31 +0000 Subject: [PATCH 13/18] fix cli-wallet --- yarn-project/cli-wallet/src/cmds/deploy.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn-project/cli-wallet/src/cmds/deploy.ts b/yarn-project/cli-wallet/src/cmds/deploy.ts index 930e146eefa9..257c8a416f53 100644 --- a/yarn-project/cli-wallet/src/cmds/deploy.ts +++ b/yarn-project/cli-wallet/src/cmds/deploy.ts @@ -1,4 +1,4 @@ -import { type AccountWalletWithSecretKey, ContractDeployer, type DeployMethod, Fr, type PXE } from '@aztec/aztec.js'; +import { type AccountWalletWithSecretKey, ContractDeployer, type DeployOptions, Fr, type PXE } from '@aztec/aztec.js'; import { encodeArgs, getContractArtifact } from '@aztec/cli/utils'; import type { LogFn, Logger } from '@aztec/foundation/log'; import { getInitializer } from '@aztec/stdlib/abi'; @@ -44,8 +44,8 @@ export async function deploy( } const deploy = deployer.deploy(...args); - const deployOpts: Parameters[0] = { - ...(await feeOpts.toSendOpts(wallet)), + const deployOpts: DeployOptions = { + ...(await feeOpts.toDeployAccountOpts(wallet)), contractAddressSalt: salt, universalDeploy, skipClassRegistration, From da138a3560ea0027e6c68b97e6977d4394b4e39a Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Fri, 21 Mar 2025 20:16:16 +0100 Subject: [PATCH 14/18] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Beneő --- yarn-project/aztec.js/src/account_manager/account_manager.ts | 3 +++ .../src/fee/account_entrypoint_meta_payment_method.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/yarn-project/aztec.js/src/account_manager/account_manager.ts b/yarn-project/aztec.js/src/account_manager/account_manager.ts index 79208fdb9c79..ca7783947643 100644 --- a/yarn-project/aztec.js/src/account_manager/account_manager.ts +++ b/yarn-project/aztec.js/src/account_manager/account_manager.ts @@ -194,6 +194,9 @@ export class AccountManager { * Returns a FeePaymentMethod that routes the original one provided as an argument * through the account's entrypoint. This allows an account contract to pay * for its own deployment and initialization. + * + * For more details on how the fee payment routing works see documentation of AccountEntrypointMetaPaymentMethod class. + * * @param originalPaymentMethod - originalPaymentMethod The original payment method to be wrapped. * @returns A FeePaymentMethod that routes the original one through the account's entrypoint (AccountEntrypointMetaPaymentMethod) */ diff --git a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts index 64c0135f7604..3916776c84c1 100644 --- a/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/account_entrypoint_meta_payment_method.ts @@ -22,10 +22,10 @@ import type { GasSettings } from '@aztec/stdlib/gas'; * which sets itself as fee payer. * * Usually, in order to pay fees it is necessary to obtain an ExecutionPayload that encodes the necessary information - * That is sent to the user's account entrypoint, that has plumbing to handle a fee payload. + * that is sent to the user's account entrypoint, that has plumbing to handle a fee payload. * If there's no account contract yet (it's being deployed) a MultiCallContract is used, which doesn't have a concept of fees or * how to handle this payload. - * HOWEVER,the account contract entrypoint does, so this method reshapes that fee payload into a call to the account contract entrypoint + * HOWEVER, the account contract's entrypoint does, so this method reshapes that fee payload into a call to the account contract entrypoint * being deployed with the original fee payload. * * This class can be seen in action in AccountManager.ts#getSelfPaymentMethod From c72de254456f1e8237aba315d69d1e089be88bae Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:20:08 +0000 Subject: [PATCH 15/18] actual fix --- yarn-project/cli-wallet/src/cmds/create_account.ts | 3 +-- yarn-project/cli-wallet/src/cmds/deploy_account.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/yarn-project/cli-wallet/src/cmds/create_account.ts b/yarn-project/cli-wallet/src/cmds/create_account.ts index 944a76f6d944..ecd9996b0b10 100644 --- a/yarn-project/cli-wallet/src/cmds/create_account.ts +++ b/yarn-project/cli-wallet/src/cmds/create_account.ts @@ -65,12 +65,11 @@ export async function createAccount( await account.register(); } else { const wallet = await account.getWallet(); - const feeOptions = await feeOpts.toDeployAccountOpts(wallet); const deployOpts: DeployAccountOptions = { skipClassRegistration: !publicDeploy, skipPublicDeployment: !publicDeploy, skipInitialization: skipInitialization, - fee: feeOptions.fee, + ...(await feeOpts.toDeployAccountOpts(wallet)), }; if (feeOpts.estimateOnly) { const gas = await account.estimateDeploymentGas(deployOpts); diff --git a/yarn-project/cli-wallet/src/cmds/deploy_account.ts b/yarn-project/cli-wallet/src/cmds/deploy_account.ts index 49028ee6304f..48b43cc53870 100644 --- a/yarn-project/cli-wallet/src/cmds/deploy_account.ts +++ b/yarn-project/cli-wallet/src/cmds/deploy_account.ts @@ -40,10 +40,9 @@ export async function deployAccount( let tx; let txReceipt; - const feeOptions = await feeOpts.toDeployAccountOpts(wallet); const deployOpts: DeployAccountOptions = { skipInitialization: false, - fee: feeOptions.fee, + ...(await feeOpts.toDeployAccountOpts(wallet)), }; if (feeOpts.estimateOnly) { From 71ea6abb1b314b071d1275cd08e85b01726d0ad9 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:47:09 +0000 Subject: [PATCH 16/18] fix full_prover --- yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts b/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts index 6a1df6a9c4fd..57b66f9a7bd5 100644 --- a/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts @@ -39,7 +39,7 @@ import { deployAccounts, publicDeployAccounts, } from '../fixtures/snapshot_manager.js'; -import { getPrivateKeyFromIndex, setupPXEService } from '../fixtures/utils.js'; +import { getPrivateKeyFromIndex, getSponsoredFPCAddress, setupPXEService } from '../fixtures/utils.js'; import { TokenSimulator } from '../simulators/token_simulator.js'; const { E2E_DATA_PATH: dataPath } = process.env; @@ -295,7 +295,10 @@ export class FullProverTest { txGatheringIntervalMs: 1000, txGatheringMaxParallelRequests: 100, }; - const { prefilledPublicData } = await getGenesisValues(this.context.initialFundedAccounts.map(a => a.address)); + const sponsoredFPCAddress = await getSponsoredFPCAddress(); + const { prefilledPublicData } = await getGenesisValues( + this.context.initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress), + ); this.proverNode = await createProverNode( proverConfig, { From 58618771fdf8c88d58b6d3ad91ca8bb48ad33b1c Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:55:21 +0000 Subject: [PATCH 17/18] added to deploy_l1_contracts --- .../cli/src/cmds/l1/deploy_l1_contracts.ts | 7 ++++- yarn-project/cli/src/utils/setup_contracts.ts | 27 +++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts index 2e9b3a5f3231..9f96d5877e36 100644 --- a/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts +++ b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts @@ -5,6 +5,7 @@ import type { LogFn, Logger } from '@aztec/foundation/log'; import { getGenesisValues } from '@aztec/world-state/testing'; import { deployAztecContracts } from '../../utils/aztec.js'; +import { getSponsoredFPCAddress } from '../../utils/setup_contracts.js'; export async function deployL1Contracts( rpcUrls: string[], @@ -14,6 +15,7 @@ export async function deployL1Contracts( mnemonicIndex: number, salt: number | undefined, testAccounts: boolean, + sponsoredFPC: boolean, acceleratedTestDeployments: boolean, json: boolean, initialValidators: EthAddress[], @@ -23,7 +25,10 @@ export async function deployL1Contracts( const config = getL1ContractsConfigEnvVars(); const initialFundedAccounts = testAccounts ? await getInitialTestAccounts() : []; - const { genesisBlockHash, genesisArchiveRoot } = await getGenesisValues(initialFundedAccounts.map(a => a.address)); + const sponsoredFPCAddress = sponsoredFPC ? await getSponsoredFPCAddress() : []; + const { genesisBlockHash, genesisArchiveRoot } = await getGenesisValues( + initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress), + ); const { l1ContractAddresses } = await deployAztecContracts( rpcUrls, diff --git a/yarn-project/cli/src/utils/setup_contracts.ts b/yarn-project/cli/src/utils/setup_contracts.ts index 9383c7fc94e2..26becf2d9fb1 100644 --- a/yarn-project/cli/src/utils/setup_contracts.ts +++ b/yarn-project/cli/src/utils/setup_contracts.ts @@ -57,22 +57,33 @@ export async function setupCanonicalL2FeeJuice( } } +async function getSponsoredFPCContract() { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { SponsoredFPCContract } = await import('@aztec/noir-contracts.js/SponsoredFPC'); + return SponsoredFPCContract; +} + +export async function getSponsoredFPCAddress() { + const SponsoredFPCContract = await getSponsoredFPCContract(); + const sponsoredFPCInstance = await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { + salt: new Fr(SPONSORED_FPC_SALT), + }); + return sponsoredFPCInstance.address; +} + export async function setupSponsoredFPC( pxe: PXE, log: LogFn, waitOpts = DefaultWaitOpts, waitForProvenOptions?: WaitForProvenOpts, ) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment - const { SponsoredFPCContract } = await import('@aztec/noir-contracts.js/SponsoredFPC'); - + const SponsoredFPCContract = await getSponsoredFPCContract(); + const address = await getSponsoredFPCAddress(); + const paymentMethod = new SponsoredFeePaymentMethod(address); const { l1ChainId: chainId, protocolVersion } = await pxe.getNodeInfo(); + const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion)); - const sponsoredFPCInstance = await getContractInstanceFromDeployParams(SponsoredFPCContract.artifact, { - salt: new Fr(SPONSORED_FPC_SALT), - }); - const paymentMethod = new SponsoredFeePaymentMethod(sponsoredFPCInstance.address); const deployTx = SponsoredFPCContract.deploy(deployer).send({ contractAddressSalt: new Fr(SPONSORED_FPC_SALT), From 42544e09aa8a291983bcd52c21495687ab606955 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 21 Mar 2025 19:56:29 +0000 Subject: [PATCH 18/18] fix --- yarn-project/cli/src/cmds/l1/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts index 6d7fb2073e05..6aae5d1fcca3 100644 --- a/yarn-project/cli/src/cmds/l1/index.ts +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -42,6 +42,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger .option('--salt ', 'The optional salt to use in deployment', arg => parseInt(arg)) .option('--json', 'Output the contract addresses in JSON format') .option('--test-accounts', 'Populate genesis state with initial fee juice for test accounts') + .option('--sponsored-fpc', 'Populate genesis state with a testing sponsored FPC contract') .option('--accelerated-test-deployments', 'Fire and forget deployment transactions, use in testing only', false) .action(async options => { const { deployL1Contracts } = await import('./deploy_l1_contracts.js'); @@ -56,6 +57,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger options.mnemonicIndex, options.salt, options.testAccounts, + options.sponsoredFPC, options.acceleratedTestDeployments, options.json, initialValidators,