Skip to content
Merged
1 change: 1 addition & 0 deletions .test_patterns.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ tests:

# boxes
- regex: "boxes/scripts/run_test.sh vite"
error_regex: "Test timeout of 90000ms exceeded."
owners:
- *grego

Expand Down
3 changes: 2 additions & 1 deletion playground/src/components/contract/contract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ export function ContractComponent() {
setIsWorking(true);
let result;
try {
const call = currentContract.methods[fnName](...parameters[fnName]);
const fnParameters = parameters[fnName] ?? [];
const call = currentContract.methods[fnName](...fnParameters);

result = await call.simulate();
setSimulationResults({
Expand Down
38 changes: 24 additions & 14 deletions yarn-project/aztec.js/src/account_manager/deploy_account_method.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { AuthWitnessProvider } from '@aztec/entrypoints/interfaces';
import {
EncodedAppEntrypointPayload,
EncodedFeeEntrypointPayload,
ExecutionPayload,
EncodedAppEntrypointCalls,
EncodedCallsForEntrypoint,
computeCombinedPayloadHash,
} from '@aztec/entrypoints/payload';
import { mergeExecutionPayloads } from '@aztec/entrypoints/utils';
} 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';

Expand Down Expand Up @@ -51,22 +50,33 @@ export class DeployAccountMethod extends DeployMethod {

if (options.fee && this.#feePaymentArtifact) {
const { address } = await this.getInstance();
const emptyAppPayload = await EncodedAppEntrypointPayload.fromAppExecution([]);
const emptyAppCalls = await EncodedAppEntrypointCalls.fromAppExecution([]);
const fee = await this.getDefaultFeeOptions(options.fee);
const feePayload = await EncodedFeeEntrypointPayload.fromFeeOptions(address, fee);
const args = [emptyAppPayload, feePayload, false];
// 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,
[
await this.#authWitnessProvider.createAuthWit(await computeCombinedPayloadHash(emptyAppPayload, feePayload)),
...feePayload.authWitnesses,
],
[combinedPayloadAuthWitness, ...feeAuthwitnesses],
[],
[...emptyAppPayload.hashedArguments, ...feePayload.hashedArguments],
[...emptyAppCalls.hashedArguments, ...feeEncodedCalls.hashedArguments],
);

exec = mergeExecutionPayloads([exec, await call.request()]);
Expand Down
50 changes: 17 additions & 33 deletions yarn-project/aztec.js/src/contract/base_contract_interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@ import type { Fr } from '@aztec/foundation/fields';
import { createLogger } from '@aztec/foundation/log';
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
import { GasSettings } from '@aztec/stdlib/gas';
import type { Capsule, HashedValues, TxExecutionRequest, TxProvingResult } from '@aztec/stdlib/tx';
import type { Capsule, TxExecutionRequest, TxProvingResult } from '@aztec/stdlib/tx';

import { FeeJuicePaymentMethod } from '../fee/fee_juice_payment_method.js';
import type { Wallet } from '../wallet/wallet.js';
import { getGasLimits } from './get_gas_limits.js';
import { ProvenTx } from './proven_tx.js';
import { SentTx } from './sent_tx.js';

/**
* Represents the options to configure a request from a contract interaction.
* Allows specifying additional auth witnesses and capsules to use during execution
*/
export type RequestMethodOptions = {
/** Extra authwits to use during execution */
authWitnesses?: AuthWitness[];
/** Extra capsules to use during execution */
capsules?: Capsule[];
};

/**
* Represents options for calling a (constrained) function in a contract.
* Allows the user to specify the sender address and nonce for a transaction.
*/
export type SendMethodOptions = {
export type SendMethodOptions = RequestMethodOptions & {
/** Wether to skip the simulation of the public part of the transaction. */
skipPublicSimulation?: boolean;
/** The fee options for the transaction. */
Expand All @@ -25,10 +35,6 @@ export type SendMethodOptions = {
nonce?: Fr;
/** Whether the transaction can be cancelled. If true, an extra nullifier will be emitted: H(nonce, GENERATOR_INDEX__TX_NULLIFIER) */
cancellable?: boolean;
/** Authwits to use in the simulation */
authWitnesses?: AuthWitness[];
/** Capsules to use in the simulation */
capsules?: Capsule[];
};

/**
Expand All @@ -42,7 +48,6 @@ export abstract class BaseContractInteraction {
protected wallet: Wallet,
protected authWitnesses: AuthWitness[] = [],
protected capsules: Capsule[] = [],
protected extraHashedValues: HashedValues[] = [],
) {}

/**
Expand All @@ -58,7 +63,7 @@ export abstract class BaseContractInteraction {
* @param options - An optional object containing additional configuration for the transaction.
* @returns An execution request wrapped in promise.
*/
public abstract request(options?: SendMethodOptions): Promise<ExecutionPayload>;
public abstract request(options?: RequestMethodOptions): Promise<ExecutionPayload>;

/**
* Creates a transaction execution request, simulates and proves it. Differs from .prove in
Expand Down Expand Up @@ -153,8 +158,8 @@ export abstract class BaseContractInteraction {
*/
protected async getFeeOptions(
executionPayload: ExecutionPayload,
fee?: UserFeeOptions,
options?: TxExecutionOptions,
fee: UserFeeOptions = {},
options: TxExecutionOptions,
): Promise<FeeOptions> {
// docs:end:getFeeOptions
const defaultFeeOptions = await this.getDefaultFeeOptions(fee);
Expand All @@ -165,7 +170,7 @@ export abstract class BaseContractInteraction {
let gasSettings = defaultFeeOptions.gasSettings;
if (fee?.estimateGas) {
const feeForEstimation: FeeOptions = { paymentMethod, gasSettings };
const txRequest = await this.wallet.createTxExecutionRequest(executionPayload, feeForEstimation, options ?? {});
const txRequest = await this.wallet.createTxExecutionRequest(executionPayload, feeForEstimation, options);
const simulationResult = await this.wallet.simulateTx(
txRequest,
true /*simulatePublic*/,
Expand All @@ -185,25 +190,4 @@ export abstract class BaseContractInteraction {

return { gasSettings, paymentMethod };
}

/**
* Return all authWitnesses added for this interaction.
*/
public getAuthWitnesses() {
return this.authWitnesses;
}

/**
* Return all capsules added for this contract interaction.
*/
public getCapsules() {
return this.capsules;
}

/**
* Return all extra hashed values added for this contract interaction.
*/
public getExtraHashedValues() {
return this.extraHashedValues;
}
}
42 changes: 16 additions & 26 deletions yarn-project/aztec.js/src/contract/batch_call.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { ExecutionPayload } from '@aztec/entrypoints/payload';
import { mergeExecutionPayloads } from '@aztec/entrypoints/utils';
import { mergeExecutionPayloads } from '@aztec/entrypoints/payload';
import { type FunctionCall, FunctionType, decodeFromAbi } from '@aztec/stdlib/abi';
import type { TxExecutionRequest } from '@aztec/stdlib/tx';

import type { Wallet } from '../wallet/wallet.js';
import { BaseContractInteraction, type SendMethodOptions } from './base_contract_interaction.js';
import {
BaseContractInteraction,
type RequestMethodOptions,
type SendMethodOptions,
} from './base_contract_interaction.js';
import type { SimulateMethodOptions } from './contract_function_interaction.js';

/** A batch of function calls to be sent as a single transaction through a wallet. */
Expand All @@ -30,11 +34,11 @@ export class BatchCall extends BaseContractInteraction {

/**
* Returns an execution request that represents this operation.
* @param _options - (ignored) An optional object containing additional configuration for the transaction.
* @returns An execution request wrapped in promise.
* @param options - An optional object containing additional configuration for the request generation.
* @returns An execution payload wrapped in promise.
*/
public async request(_options: SendMethodOptions = {}): Promise<ExecutionPayload> {
const requests = await this.getRequests();
public async request(options: RequestMethodOptions = {}): Promise<ExecutionPayload> {
const requests = await this.getRequests(options);
return mergeExecutionPayloads(requests);
}

Expand All @@ -48,7 +52,7 @@ export class BatchCall extends BaseContractInteraction {
* @returns The result of the transaction as returned by the contract function.
*/
public async simulate(options: SimulateMethodOptions = {}): Promise<any> {
const { indexedExecutionPayloads, unconstrained } = (await this.getRequests()).reduce<{
const { indexedExecutionPayloads, unconstrained } = (await this.getRequests(options)).reduce<{
/** Keep track of the number of private calls to retrieve the return values */
privateIndex: 0;
/** Keep track of the number of public calls to retrieve the return values */
Expand Down Expand Up @@ -76,9 +80,9 @@ export class BatchCall extends BaseContractInteraction {

const payloads = indexedExecutionPayloads.map(([request]) => request);
const requestWithoutFee = mergeExecutionPayloads(payloads);
const { fee: userFee } = options;
const fee = await this.getFeeOptions(requestWithoutFee, userFee);
const txRequest = await this.wallet.createTxExecutionRequest(requestWithoutFee, fee, {});
const { fee: userFee, nonce, cancellable } = options;
const fee = await this.getFeeOptions(requestWithoutFee, userFee, {});
const txRequest = await this.wallet.createTxExecutionRequest(requestWithoutFee, fee, { nonce, cancellable });

const unconstrainedCalls = unconstrained.map(
async ([call, index]) =>
Expand Down Expand Up @@ -113,21 +117,7 @@ export class BatchCall extends BaseContractInteraction {
return results;
}

/**
* Return all authWitnesses added for this interaction.
*/
public override getAuthWitnesses() {
return [this.authWitnesses, ...this.calls.map(c => c.getAuthWitnesses())].flat();
}

/**
* Return all capsules added for this interaction.
*/
public override getCapsules() {
return [this.capsules, ...this.calls.map(c => c.getCapsules())].flat();
}

private async getRequests() {
return await Promise.all(this.calls.map(c => c.request()));
private async getRequests(options: RequestMethodOptions = {}) {
return await Promise.all(this.calls.map(c => c.request(options)));
}
}
Loading