diff --git a/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md b/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md index ec559fa2546..a9437be61e5 100644 --- a/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md +++ b/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md @@ -8,7 +8,7 @@ You will learn: - How to write a custom account contract in Aztec.nr - The entrypoint function for transaction authentication and call execution -- The AccountActions module and EntrypointPayload struct, necessary inclusions for any account contract +- The AccountActions module and entrypoint payload structs, necessary inclusions for any account contract - Customizing authorization validation within the `is_valid` function (using Schnorr signatures as an example) - Typescript glue code to format and authenticate transactions - Deploying and testing the account contract @@ -43,14 +43,16 @@ Public Key: 0x0ede151adaef1cfcc1b3e152ea39f00c5cda3f3857cef00decb049d283672dc71 ::: -The important part of this contract is the `entrypoint` function, which will be the first function executed in any transaction originated from this account. This function has two main responsibilities: authenticating the transaction and executing calls. It receives a `payload` with the list of function calls to execute, and requests a corresponding auth witness from an oracle to validate it. You will find this logic implemented in the `AccountActions` module, which uses the `EntrypointPayload` struct: +The important part of this contract is the `entrypoint` function, which will be the first function executed in any transaction originated from this account. This function has two main responsibilities: authenticating the transaction and executing calls. It receives a `payload` with the list of function calls to execute, and requests a corresponding auth witness from an oracle to validate it. You will find this logic implemented in the `AccountActions` module, which use the `AppPayload` and `FeePayload` structs: #include_code entrypoint yarn-project/aztec-nr/authwit/src/account.nr rust -#include_code entrypoint-struct yarn-project/aztec-nr/authwit/src/entrypoint.nr rust +#include_code app-payload-struct yarn-project/aztec-nr/authwit/src/entrypoint/app.nr rust + +#include_code fee-payload-struct yarn-project/aztec-nr/authwit/src/entrypoint/fee.nr rust :::info -Using the `AccountActions` module and the `EntrypointPayload` struct is not mandatory. You can package the instructions to be carried out by your account contract however you want. However, using these modules can save you a lot of time when writing a new account contract, both in Noir and in Typescript. +Using the `AccountActions` module and the payload structs is not mandatory. You can package the instructions to be carried out by your account contract however you want. However, using these modules can save you a lot of time when writing a new account contract, both in Noir and in Typescript. ::: The `AccountActions` module provides default implementations for most of the account contract methods needed, but it requires a function for validating an auth witness. In this function you will customize how your account validates an action: whether it is using a specific signature scheme, a multi-party approval, a password, etc. @@ -100,5 +102,3 @@ To make sure that we are actually validating the provided signature in our accou #include_code account-contract-fails yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript Lo and behold, we get `Error: Assertion failed: 'verification == true'` when running the snippet above, pointing to the line in our account contract where we verify the Schnorr signature. - - diff --git a/yarn-project/accounts/src/defaults/account_entrypoint.ts b/yarn-project/accounts/src/defaults/account_entrypoint.ts index 782d5c4119a..67b62181dfd 100644 --- a/yarn-project/accounts/src/defaults/account_entrypoint.ts +++ b/yarn-project/accounts/src/defaults/account_entrypoint.ts @@ -1,14 +1,14 @@ -import { AuthWitnessProvider, EntrypointInterface } from '@aztec/aztec.js/account'; +import { AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account'; import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; -import { AztecAddress, Fr, FunctionData, TxContext } from '@aztec/circuits.js'; +import { AztecAddress, Fr, FunctionData, GeneratorIndex, TxContext } from '@aztec/circuits.js'; import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from './constants.js'; -import { buildPayload, hashPayload } from './entrypoint_payload.js'; +import { buildAppPayload, buildFeePayload, hashPayload } from './entrypoint_payload.js'; /** * Implementation for an entrypoint interface that follows the default entrypoint signature - * for an account, which accepts an EntrypointPayload as defined in noir-libs/aztec-noir/src/entrypoint.nr. + * for an account, which accepts an AppPayload and a FeePayload as defined in noir-libs/aztec-noir/src/entrypoint module */ export class DefaultAccountEntrypoint implements EntrypointInterface { constructor( @@ -18,19 +18,27 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { private version: number = DEFAULT_VERSION, ) {} - async createTxExecutionRequest(executions: FunctionCall[]): Promise { - const { payload, packedArguments: callsPackedArguments } = buildPayload(executions); + async createTxExecutionRequest(executions: FunctionCall[], feeOpts?: FeeOptions): Promise { + const { payload: appPayload, packedArguments: appPackedArguments } = buildAppPayload(executions); + const { payload: feePayload, packedArguments: feePackedArguments } = buildFeePayload(feeOpts); + const abi = this.getEntrypointAbi(); - const packedArgs = PackedArguments.fromArgs(encodeArguments(abi, [payload])); - const message = Fr.fromBuffer(hashPayload(payload)); - const authWitness = await this.auth.createAuthWitness(message); + const entrypointPackedArgs = PackedArguments.fromArgs(encodeArguments(abi, [appPayload, feePayload])); + + const appAuthWitness = await this.auth.createAuthWitness( + Fr.fromBuffer(hashPayload(appPayload, GeneratorIndex.SIGNATURE_PAYLOAD)), + ); + const feeAuthWitness = await this.auth.createAuthWitness( + Fr.fromBuffer(hashPayload(feePayload, GeneratorIndex.FEE_PAYLOAD)), + ); + const txRequest = TxExecutionRequest.from({ - argsHash: packedArgs.hash, + argsHash: entrypointPackedArgs.hash, origin: this.address, functionData: FunctionData.fromAbi(abi), txContext: TxContext.empty(this.chainId, this.version), - packedArguments: [...callsPackedArguments, packedArgs], - authWitnesses: [authWitness], + packedArguments: [...appPackedArguments, ...feePackedArguments, entrypointPackedArgs], + authWitnesses: [appAuthWitness, feeAuthWitness], }); return txRequest; @@ -43,10 +51,10 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { isInternal: false, parameters: [ { - name: 'payload', + name: 'app_payload', type: { kind: 'struct', - path: 'authwit::entrypoint::EntrypointPayload', + path: 'authwit::entrypoint::app::AppPayload', fields: [ { name: 'function_calls', @@ -55,62 +63,73 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { length: 4, type: { kind: 'struct', - path: 'authwit::entrypoint::FunctionCall', + path: 'authwit::entrypoint::function_call::FunctionCall', fields: [ + { name: 'args_hash', type: { kind: 'field' } }, { - name: 'args_hash', + name: 'function_selector', type: { - kind: 'field', + kind: 'struct', + path: 'authwit::aztec::protocol_types::abis::function_selector::FunctionSelector', + fields: [{ name: 'inner', type: { kind: 'integer', sign: 'unsigned', width: 32 } }], }, }, { - name: 'function_selector', + name: 'target_address', type: { kind: 'struct', - path: 'aztec::protocol_types::abis::function_selector::FunctionSelector', - fields: [ - { - name: 'inner', - type: { - kind: 'integer', - sign: 'unsigned', - width: 32, - }, - }, - ], + path: 'authwit::aztec::protocol_types::address::AztecAddress', + fields: [{ name: 'inner', type: { kind: 'field' } }], }, }, + { name: 'is_public', type: { kind: 'boolean' } }, + ], + }, + }, + }, + { name: 'nonce', type: { kind: 'field' } }, + ], + }, + visibility: 'public', + }, + { + name: 'fee_payload', + type: { + kind: 'struct', + path: 'authwit::entrypoint::fee::FeePayload', + fields: [ + { + name: 'function_calls', + type: { + kind: 'array', + length: 2, + type: { + kind: 'struct', + path: 'authwit::entrypoint::function_call::FunctionCall', + fields: [ + { name: 'args_hash', type: { kind: 'field' } }, { - name: 'target_address', + name: 'function_selector', type: { kind: 'struct', - path: 'aztec::protocol_types::address::AztecAddress', - fields: [ - { - name: 'inner', - type: { - kind: 'field', - }, - }, - ], + path: 'authwit::aztec::protocol_types::abis::function_selector::FunctionSelector', + fields: [{ name: 'inner', type: { kind: 'integer', sign: 'unsigned', width: 32 } }], }, }, { - name: 'is_public', + name: 'target_address', type: { - kind: 'boolean', + kind: 'struct', + path: 'authwit::aztec::protocol_types::address::AztecAddress', + fields: [{ name: 'inner', type: { kind: 'field' } }], }, }, + { name: 'is_public', type: { kind: 'boolean' } }, ], }, }, }, - { - name: 'nonce', - type: { - kind: 'field', - }, - }, + { name: 'nonce', type: { kind: 'field' } }, ], }, visibility: 'public', diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index d04ab0630e0..f2718003552 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -1,4 +1,4 @@ -import { AccountInterface, AuthWitnessProvider, EntrypointInterface } from '@aztec/aztec.js/account'; +import { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account'; import { AuthWitness, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; import { CompleteAddress, Fr } from '@aztec/circuits.js'; import { NodeInfo } from '@aztec/types/interfaces'; @@ -7,7 +7,7 @@ import { DefaultAccountEntrypoint } from './account_entrypoint.js'; /** * Default implementation for an account interface. Requires that the account uses the default - * entrypoint signature, which accepts an EntrypointPayload as defined in noir-libs/aztec-noir/src/entrypoint.nr. + * entrypoint signature, which accept an AppPayload and a FeePayload as defined in noir-libs/aztec-noir/src/entrypoint module */ export class DefaultAccountInterface implements AccountInterface { private entrypoint: EntrypointInterface; @@ -25,8 +25,8 @@ export class DefaultAccountInterface implements AccountInterface { ); } - createTxExecutionRequest(executions: FunctionCall[]): Promise { - return this.entrypoint.createTxExecutionRequest(executions); + createTxExecutionRequest(executions: FunctionCall[], fee?: FeeOptions): Promise { + return this.entrypoint.createTxExecutionRequest(executions, fee); } createAuthWitness(message: Fr): Promise { diff --git a/yarn-project/accounts/src/defaults/entrypoint_payload.ts b/yarn-project/accounts/src/defaults/entrypoint_payload.ts index 96461519bfb..9841d8bb398 100644 --- a/yarn-project/accounts/src/defaults/entrypoint_payload.ts +++ b/yarn-project/accounts/src/defaults/entrypoint_payload.ts @@ -1,10 +1,14 @@ +import { FeeOptions } from '@aztec/aztec.js/account'; +import { Fr } from '@aztec/aztec.js/fields'; import { FunctionCall, PackedArguments, emptyFunctionCall } from '@aztec/circuit-types'; -import { Fr, GeneratorIndex } from '@aztec/circuits.js'; import { padArrayEnd } from '@aztec/foundation/collection'; import { pedersenHash } from '@aztec/foundation/crypto'; -// These must match the values defined in yarn-project/aztec-nr/aztec/src/entrypoint.nr +// These must match the values defined in: +// - yarn-project/aztec-nr/aztec/src/entrypoint/app.nr const ACCOUNT_MAX_CALLS = 4; +// - and yarn-project/aztec-nr/aztec/src/entrypoint/fee.nr +const FEE_MAX_CALLS = 2; /** Encoded function call for account contract entrypoint */ type EntrypointFunctionCall = { @@ -23,7 +27,7 @@ type EntrypointFunctionCall = { }; /** Encoded payload for the account contract entrypoint */ -export type EntrypointPayload = { +type EntrypointPayload = { // eslint-disable-next-line camelcase /** Encoded function calls to execute */ function_calls: EntrypointFunctionCall[]; @@ -31,16 +35,24 @@ export type EntrypointPayload = { nonce: Fr; }; -/** Assembles an entrypoint payload from a set of private and public function calls */ -export function buildPayload(calls: FunctionCall[]): { - /** The payload for the entrypoint function */ +/** Represents a generic payload to be executed in the context of an account contract */ +export type PayloadWithArguments = { + /** The payload to be run */ payload: EntrypointPayload; - /** The packed arguments of functions called */ + /** The packed arguments for the function calls */ packedArguments: PackedArguments[]; -} { +}; + +/** + * Builds a payload to be sent to the account contract + * @param calls - The function calls to run + * @param maxCalls - The maximum number of call expected to be run. Used for padding + * @returns A payload object and packed arguments + */ +function buildPayload(calls: FunctionCall[], maxCalls: number): PayloadWithArguments { const nonce = Fr.random(); - const paddedCalls = padArrayEnd(calls, emptyFunctionCall(), ACCOUNT_MAX_CALLS); + const paddedCalls = padArrayEnd(calls, emptyFunctionCall(), maxCalls); const packedArguments: PackedArguments[] = []; for (const call of paddedCalls) { packedArguments.push(PackedArguments.fromArgs(call.args)); @@ -67,15 +79,26 @@ export function buildPayload(calls: FunctionCall[]): { }; } -/** Hashes an entrypoint payload to a 32-byte buffer (useful for signing) */ -export function hashPayload(payload: EntrypointPayload) { +/** Assembles an entrypoint app payload from a set of private and public function calls */ +export function buildAppPayload(calls: FunctionCall[]): PayloadWithArguments { + return buildPayload(calls, ACCOUNT_MAX_CALLS); +} + +/** Creates the payload for paying the fee for a transaction */ +export function buildFeePayload(feeOpts?: FeeOptions): PayloadWithArguments { + const calls = feeOpts?.paymentMethod.getFunctionCalls(new Fr(feeOpts.maxFee)) ?? []; + return buildPayload(calls, FEE_MAX_CALLS); +} + +/** Hashes a payload to a 32-byte buffer */ +export function hashPayload(payload: EntrypointPayload, generatorIndex: number) { return pedersenHash( flattenPayload(payload).map(fr => fr.toBuffer()), - GeneratorIndex.SIGNATURE_PAYLOAD, + generatorIndex, ); } -/** Flattens an entrypoint payload */ +/** Flattens an payload */ function flattenPayload(payload: EntrypointPayload) { return [ ...payload.function_calls.flatMap(call => [ diff --git a/yarn-project/aztec-nr/authwit/src/account.nr b/yarn-project/aztec-nr/authwit/src/account.nr index 8823b14c5ec..dc343eace0c 100644 --- a/yarn-project/aztec-nr/authwit/src/account.nr +++ b/yarn-project/aztec-nr/authwit/src/account.nr @@ -1,7 +1,7 @@ use dep::aztec::context::{PrivateContext, PublicContext, Context}; use dep::aztec::state_vars::{map::Map, public_state::PublicState}; -use crate::entrypoint::EntrypointPayload; +use crate::entrypoint::{app::AppPayload, fee::FeePayload}; use crate::auth::IS_VALID_SELECTOR; struct AccountActions { @@ -54,12 +54,18 @@ impl AccountActions { } // docs:start:entrypoint - pub fn entrypoint(self, payload: EntrypointPayload) { - let message_hash = payload.hash(); + pub fn entrypoint(self, app_payload: AppPayload, fee_payload: FeePayload) { let valid_fn = self.is_valid_impl; - let private_context = self.context.private.unwrap(); - assert(valid_fn(private_context, message_hash)); - payload.execute_calls(private_context); + let mut private_context = self.context.private.unwrap(); + + let fee_hash = fee_payload.hash(); + assert(valid_fn(private_context, fee_hash)); + fee_payload.execute_calls(private_context); + private_context.capture_max_non_revertible_side_effect_counter(); + + let app_hash = app_payload.hash(); + assert(valid_fn(private_context, app_hash)); + app_payload.execute_calls(private_context); } // docs:end:entrypoint diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint.nr b/yarn-project/aztec-nr/authwit/src/entrypoint.nr index 4113c42533c..d52c28066ae 100644 --- a/yarn-project/aztec-nr/authwit/src/entrypoint.nr +++ b/yarn-project/aztec-nr/authwit/src/entrypoint.nr @@ -1,115 +1,3 @@ -use dep::aztec::context::PrivateContext; -use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, address::AztecAddress, - constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize} -}; - -global ACCOUNT_MAX_CALLS: Field = 4; -// 1 (ARGS_HASH) + 1 (FUNCTION_SELECTOR) + 1 (TARGET_ADDRESS) + 1 (IS_PUBLIC) -global FUNCTION_CALL_SIZE: Field = 4; -// 3 * 32 + 1 -global FUNCTION_CALL_SIZE_IN_BYTES: Field = 97; - -struct FunctionCall { - args_hash: Field, - function_selector: FunctionSelector, - target_address: AztecAddress, - is_public: bool, -} - -impl Serialize for FunctionCall { - fn serialize(self) -> [Field; FUNCTION_CALL_SIZE] { - [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field] - } -} - -impl FunctionCall { - fn to_be_bytes(self) -> [u8; FUNCTION_CALL_SIZE_IN_BYTES] { - let mut bytes: [u8; FUNCTION_CALL_SIZE_IN_BYTES] = [0; FUNCTION_CALL_SIZE_IN_BYTES]; - let args_hash_bytes = self.args_hash.to_be_bytes(32); - for i in 0..32 { - bytes[i] = args_hash_bytes[i]; - } - let function_selector_bytes = self.function_selector.to_field().to_be_bytes(32); - for i in 0..32 { - bytes[i + 32] = function_selector_bytes[i]; - } - let target_address_bytes = self.target_address.to_field().to_be_bytes(32); - for i in 0..32 { - bytes[i + 64] = target_address_bytes[i]; - } - bytes[96] = self.is_public as u8; - bytes - } -} - -// FUNCTION_CALL_SIZE * ACCOUNT_MAX_CALLS + 1 -global ENTRYPOINT_PAYLOAD_SIZE: Field = 17; -// FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS + 32 -global ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES: Field = 420; - -// Note: If you change the following struct you have to update default_entrypoint.ts -// docs:start:entrypoint-struct -struct EntrypointPayload { - function_calls: [FunctionCall; ACCOUNT_MAX_CALLS], - nonce: Field, -} -// docs:end:entrypoint-struct - -impl Serialize for EntrypointPayload { - // Serializes the entrypoint struct - fn serialize(self) -> [Field; ENTRYPOINT_PAYLOAD_SIZE] { - let mut fields: BoundedVec = BoundedVec::new(0); - for call in self.function_calls { - fields.extend_from_array(call.serialize()); - } - fields.push(self.nonce); - fields.storage - } -} - -impl Hash for EntrypointPayload { - fn hash(self) -> Field { - pedersen_hash( - self.serialize(), - GENERATOR_INDEX__SIGNATURE_PAYLOAD - ) - } -} - -impl EntrypointPayload { - // Serializes the payload as an array of bytes. Useful for hashing with sha256. - fn to_be_bytes(self) -> [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] { - let mut bytes: [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] = [0; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES]; - - for i in 0..ACCOUNT_MAX_CALLS { - let item_bytes = self.function_calls[i].to_be_bytes(); - for j in 0..FUNCTION_CALL_SIZE_IN_BYTES { - bytes[i * FUNCTION_CALL_SIZE_IN_BYTES + j] = item_bytes[j]; - } - } - - let nonce_bytes = self.nonce.to_be_bytes(32); - let nonce_offset = FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS; - for j in 0..32 { - bytes[nonce_offset + j] = nonce_bytes[j]; - } - - bytes - } - - // Executes all private and public calls - // docs:start:entrypoint-execute-calls - fn execute_calls(self, context: &mut PrivateContext) { - for call in self.function_calls { - if !call.target_address.is_zero() { - if call.is_public { - context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); - } else { - let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); - } - } - } - } - // docs:end:entrypoint-execute-calls -} +mod fee; +mod app; +mod function_call; diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint/app.nr b/yarn-project/aztec-nr/authwit/src/entrypoint/app.nr new file mode 100644 index 00000000000..49a22da9279 --- /dev/null +++ b/yarn-project/aztec-nr/authwit/src/entrypoint/app.nr @@ -0,0 +1,69 @@ +use dep::aztec::context::PrivateContext; +use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}}; + +use crate::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; + +// FUNCTION_CALL_SIZE * ACCOUNT_MAX_CALLS + 1 +global APP_PAYLOAD_SIZE: Field = 17; +// FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS + 32 +global APP_PAYLOAD_SIZE_IN_BYTES: Field = 420; + +global ACCOUNT_MAX_CALLS: Field = 4; + +// Note: If you change the following struct you have to update default_entrypoint.ts +// docs:start:app-payload-struct +struct AppPayload { + function_calls: [FunctionCall; ACCOUNT_MAX_CALLS], + nonce: Field, +} +// docs:end:app-payload-struct + +impl Serialize for AppPayload { + // Serializes the entrypoint struct + fn serialize(self) -> [Field; APP_PAYLOAD_SIZE] { + let mut fields: BoundedVec = BoundedVec::new(0); + for call in self.function_calls { + fields.extend_from_array(call.serialize()); + } + fields.push(self.nonce); + fields.storage + } +} + +impl Hash for AppPayload { + fn hash(self) -> Field { + pedersen_hash( + self.serialize(), + GENERATOR_INDEX__SIGNATURE_PAYLOAD + ) + } +} + +impl AppPayload { + // Serializes the payload as an array of bytes. Useful for hashing with sha256. + fn to_be_bytes(self) -> [u8; APP_PAYLOAD_SIZE_IN_BYTES] { + let mut bytes: BoundedVec = BoundedVec::new(0); + + for i in 0..ACCOUNT_MAX_CALLS { + bytes.extend_from_array(self.function_calls[i].to_be_bytes()); + } + bytes.extend_from_array(self.nonce.to_be_bytes(32)); + + bytes.storage + } + + // Executes all private and public calls + // docs:start:entrypoint-execute-calls + fn execute_calls(self, context: &mut PrivateContext) { + for call in self.function_calls { + if !call.target_address.is_zero() { + if call.is_public { + context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } else { + let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } + } + } + } + // docs:end:entrypoint-execute-calls +} diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint/fee.nr b/yarn-project/aztec-nr/authwit/src/entrypoint/fee.nr new file mode 100644 index 00000000000..6858e4fdd7a --- /dev/null +++ b/yarn-project/aztec-nr/authwit/src/entrypoint/fee.nr @@ -0,0 +1,65 @@ +use dep::aztec::context::PrivateContext; +use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__FEE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}}; +use crate::entrypoint::function_call::{FunctionCall}; + +// 2 * 4 (function call) + 1 +global FEE_PAYLOAD_SIZE: Field = 9; + +// 2*97 + 32 +global FEE_PAYLOAD_SIZE_IN_BYTES: Field = 226; + +global MAX_FEE_FUNCTION_CALLS = 2; + +// docs:start:fee-payload-struct +struct FeePayload { + function_calls: [FunctionCall; MAX_FEE_FUNCTION_CALLS], + nonce: Field, +} +// docs:end:fee-payload-struct + +impl Serialize for FeePayload { + // Serializes the entrypoint struct + fn serialize(self) -> [Field; FEE_PAYLOAD_SIZE] { + let mut fields: BoundedVec = BoundedVec::new(0); + for i in 0..MAX_FEE_FUNCTION_CALLS { + fields.extend_from_array(self.function_calls[i].serialize()); + } + fields.push(self.nonce); + fields.storage + } +} + +impl Hash for FeePayload { + fn hash(self) -> Field { + pedersen_hash( + self.serialize(), + GENERATOR_INDEX__FEE_PAYLOAD + ) + } +} + +impl FeePayload { + fn to_be_bytes(self) -> [u8; FEE_PAYLOAD_SIZE_IN_BYTES] { + let mut bytes: BoundedVec = BoundedVec::new(0); + + for i in 0..MAX_FEE_FUNCTION_CALLS { + bytes.extend_from_array(self.function_calls[i].to_be_bytes()); + } + bytes.extend_from_array(self.nonce.to_be_bytes(32)); + + bytes.storage + } + + fn execute_calls(self, context: &mut PrivateContext) { + for call in self.function_calls { + if !call.target_address.is_zero() { + if call.is_public { + context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } else { + let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } + } + } + } +} + diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint/function_call.nr b/yarn-project/aztec-nr/authwit/src/entrypoint/function_call.nr new file mode 100644 index 00000000000..0b1f2ba0363 --- /dev/null +++ b/yarn-project/aztec-nr/authwit/src/entrypoint/function_call.nr @@ -0,0 +1,39 @@ +use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::Serialize}; + +// 1 (ARGS_HASH) + 1 (FUNCTION_SELECTOR) + 1 (TARGET_ADDRESS) + 1 (IS_PUBLIC) +global FUNCTION_CALL_SIZE: Field = 4; +// 3 * 32 + 1 +global FUNCTION_CALL_SIZE_IN_BYTES: Field = 97; + +struct FunctionCall { + args_hash: Field, + function_selector: FunctionSelector, + target_address: AztecAddress, + is_public: bool, +} + +impl Serialize for FunctionCall { + fn serialize(self) -> [Field; FUNCTION_CALL_SIZE] { + [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field] + } +} + +impl FunctionCall { + fn to_be_bytes(self) -> [u8; FUNCTION_CALL_SIZE_IN_BYTES] { + let mut bytes: [u8; FUNCTION_CALL_SIZE_IN_BYTES] = [0; FUNCTION_CALL_SIZE_IN_BYTES]; + let args_hash_bytes = self.args_hash.to_be_bytes(32); + for i in 0..32 { + bytes[i] = args_hash_bytes[i]; + } + let function_selector_bytes = self.function_selector.to_field().to_be_bytes(32); + for i in 0..32 { + bytes[i + 32] = function_selector_bytes[i]; + } + let target_address_bytes = self.target_address.to_field().to_be_bytes(32); + for i in 0..32 { + bytes[i + 64] = target_address_bytes[i]; + } + bytes[96] = self.is_public as u8; + bytes + } +} diff --git a/yarn-project/aztec-nr/aztec/src/context/private_context.nr b/yarn-project/aztec-nr/aztec/src/context/private_context.nr index 1bb45553eb0..0e3d7fab979 100644 --- a/yarn-project/aztec-nr/aztec/src/context/private_context.nr +++ b/yarn-project/aztec-nr/aztec/src/context/private_context.nr @@ -156,6 +156,13 @@ impl PrivateContext { priv_circuit_pub_inputs } + pub fn capture_max_non_revertible_side_effect_counter(&mut self) { + assert( + self.max_non_revertible_side_effect_counter == 0, "Already captured the non-revertible side effect counter" + ); + self.max_non_revertible_side_effect_counter = self.side_effect_counter; + } + pub fn push_read_request(&mut self, read_request: Field) { let side_effect = SideEffect { value: read_request, counter: self.side_effect_counter }; self.read_requests.push(side_effect); @@ -196,7 +203,7 @@ impl PrivateContext { // docs:start:context_message_portal pub fn message_portal(&mut self, content: Field) { - // docs:end:context_message_portal + // docs:end:context_message_portal self.new_l2_to_l1_msgs.push(content); } diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 7af38fa4dc6..3bb05214e85 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -12,6 +12,7 @@ "./deployment": "./dest/api/deployment.js", "./eth_address": "./dest/api/eth_address.js", "./ethereum": "./dest/api/ethereum.js", + "./fee": "./dest/api/fee.js", "./fields": "./dest/api/fields.js", "./init": "./dest/api/init.js", "./log_id": "./dest/api/log_id.js", diff --git a/yarn-project/aztec.js/src/account/index.ts b/yarn-project/aztec.js/src/account/index.ts index 9458fb467a5..c3c7ca32743 100644 --- a/yarn-project/aztec.js/src/account/index.ts +++ b/yarn-project/aztec.js/src/account/index.ts @@ -9,7 +9,7 @@ import { Fr } from '@aztec/circuits.js'; export { AccountContract } from './contract.js'; -export { AccountInterface, AuthWitnessProvider, EntrypointInterface } from './interface.js'; +export { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from './interface.js'; export * from './wallet.js'; /** A contract deployment salt. */ diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index a2eadd90489..32ecce8425e 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -1,6 +1,18 @@ import { AuthWitness, CompleteAddress, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; import { Fr } from '@aztec/foundation/fields'; +import { FeePaymentMethod } from '../fee/fee_payment_method.js'; + +/** + * Fee payment options for a transaction. + */ +export type FeeOptions = { + /** The fee payment method to use */ + paymentMethod: FeePaymentMethod; + /** The fee limit to pay */ + maxFee: bigint | number | Fr; +}; + // docs:start:account-interface /** Creates authorization witnesses. */ export interface AuthWitnessProvider { @@ -16,10 +28,10 @@ export interface EntrypointInterface { /** * Generates an authenticated request out of set of function calls. * @param executions - The execution intents to be run. - * @param opts - Options. + * @param feeOpts - The fee to be paid for the transaction. * @returns The authenticated transaction execution request. */ - createTxExecutionRequest(executions: FunctionCall[]): Promise; + createTxExecutionRequest(executions: FunctionCall[], feeOpts?: FeeOptions): Promise; } /** diff --git a/yarn-project/aztec.js/src/api/account.ts b/yarn-project/aztec.js/src/api/account.ts index bb3fece73da..6449edc6334 100644 --- a/yarn-project/aztec.js/src/api/account.ts +++ b/yarn-project/aztec.js/src/api/account.ts @@ -5,6 +5,7 @@ export { EntrypointInterface, Salt, Wallet, + FeeOptions, } from '../account/index.js'; export { AccountManager } from '../account_manager/index.js'; diff --git a/yarn-project/aztec.js/src/api/fee.ts b/yarn-project/aztec.js/src/api/fee.ts new file mode 100644 index 00000000000..96b440f3672 --- /dev/null +++ b/yarn-project/aztec.js/src/api/fee.ts @@ -0,0 +1,3 @@ +export type { FeePaymentMethod } from '../fee/fee_payment_method.js'; +export { GenericFeePaymentMethod } from '../fee/generic_fee_payment_method.js'; +export { NativeFeePaymentMethod } from '../fee/native_fee_payment_method.js'; diff --git a/yarn-project/aztec.js/src/fee/fee_payment_method.ts b/yarn-project/aztec.js/src/fee/fee_payment_method.ts new file mode 100644 index 00000000000..25b58f6ab94 --- /dev/null +++ b/yarn-project/aztec.js/src/fee/fee_payment_method.ts @@ -0,0 +1,30 @@ +import { FunctionCall } from '@aztec/circuit-types'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; + +/** + * Holds information about how the fee for a transaction is to be paid. + */ +export interface FeePaymentMethod { + /** + * The asset used to pay the fee. + */ + getAsset(): AztecAddress; + /** + * Address which will hold the fee payment. + */ + getPaymentContract(): AztecAddress; + + /** + * Whether the fee payment is private or not + */ + isPrivateFeePayment(): boolean; + + /** + * Creates a function call to pay the fee in the given asset. + * TODO(fees) replace maxFee with gas limits + * @param maxFee - The maximum fee to be paid in the given asset. + * @returns The function call to pay the fee. + */ + getFunctionCalls(maxFee: Fr): FunctionCall[]; +} diff --git a/yarn-project/aztec.js/src/fee/generic_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/generic_fee_payment_method.ts new file mode 100644 index 00000000000..a0cc7dff9e9 --- /dev/null +++ b/yarn-project/aztec.js/src/fee/generic_fee_payment_method.ts @@ -0,0 +1,81 @@ +import { FunctionCall } from '@aztec/circuit-types'; +import { FunctionData } from '@aztec/circuits.js'; +import { FunctionSelector } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { FeePaymentMethod } from './fee_payment_method.js'; + +/** + * Holds information about how the fee for a transaction is to be paid. + */ +export class GenericFeePaymentMethod implements FeePaymentMethod { + constructor( + /** + * The asset used to pay the fee. + */ + private asset: AztecAddress, + /** + * Address which will hold the fee payment. + */ + private paymentContract: AztecAddress, + /** + * Whether the fee payment is private + */ + private privatePayment: boolean, + ) {} + + /** + * The asset used to pay the fee. + * @returns The asset used to pay the fee. + */ + getAsset() { + return this.asset; + } + + /** + * The address which will facilitate the fee payment. + * @returns The contract address responsible for holding the fee payment. + */ + getPaymentContract() { + return this.paymentContract; + } + + /** + * The fee payment function selector on the fee payment contract. + * @returns The fee payment function selector on the fee payment contract. + */ + #getFeePaymentEntrypoint() { + return this.privatePayment + ? FunctionSelector.fromSignature('prepare_fee_private(Field, (Field))') + : FunctionSelector.fromSignature('prepare_fee_public(Field, (Field))'); + } + + /** + * Whether the fee payment is private or not + * @returns Whether the fee payment is private or not + */ + isPrivateFeePayment(): boolean { + return this.privatePayment; + } + + /** + * Creates a function call to pay the fee in the given asset. + * @param maxFee - The maximum fee to be paid in the given asset. + * @returns The function call to pay the fee. + */ + getFunctionCalls(maxFee: Fr): FunctionCall[] { + return [ + // TODO(fees) set up auth witnesses + { + to: this.getPaymentContract(), + functionData: new FunctionData(this.#getFeePaymentEntrypoint(), false, true, false), + args: [maxFee, this.asset], + }, + ]; + } + + static empty(): GenericFeePaymentMethod { + return new GenericFeePaymentMethod(AztecAddress.ZERO, AztecAddress.ZERO, false); + } +} diff --git a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts new file mode 100644 index 00000000000..1e81c3024ef --- /dev/null +++ b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts @@ -0,0 +1,61 @@ +import { FunctionCall } from '@aztec/circuit-types'; +import { FunctionData } from '@aztec/circuits.js'; +import { FunctionSelector } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { FeePaymentMethod } from './fee_payment_method.js'; + +/** + * Pay fee directly in the native gas token. + */ +export class NativeFeePaymentMethod implements FeePaymentMethod { + // TODO(fees) replace this with the address of the gas token when that's deployed. + static #GAS_TOKEN = AztecAddress.ZERO; + + constructor() {} + + /** + * Gets the native gas asset used to pay the fee. + * @returns The asset used to pay the fee. + */ + getAsset() { + return NativeFeePaymentMethod.#GAS_TOKEN; + } + + /** + * The contract responsible for fee payment. This will be the same as the asset. + * @returns The contract address responsible for holding the fee payment. + */ + getPaymentContract() { + return NativeFeePaymentMethod.#GAS_TOKEN; + } + + /** + * Fee payments in the native gas token are always public. + * @returns false + */ + isPrivateFeePayment(): boolean { + return false; + } + + /** + * Creates a function call to pay the fee in gas token.. + * @param feeLimit - The maximum fee to be paid in gas token. + * @returns A function call + */ + getFunctionCalls(feeLimit: Fr): FunctionCall[] { + return [ + { + to: NativeFeePaymentMethod.#GAS_TOKEN, + functionData: new FunctionData(FunctionSelector.fromSignature('check_balance(Field)'), false, false, false), + args: [feeLimit], + }, + { + to: NativeFeePaymentMethod.#GAS_TOKEN, + functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false, false, false), + args: [feeLimit], + }, + ]; + } +} diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 14f6c88ee6e..855e5f96802 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -141,3 +141,4 @@ export { // This entire index file will be deprecated at some point after we're satisfied. export * from './api/init.js'; export * from './api/abi.js'; +export * from './api/fee.js'; diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index c9c1a983489..428d4b46fd0 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -2,7 +2,7 @@ import { AuthWitness, FunctionCall, PXE, TxExecutionRequest } from '@aztec/circu import { Fr } from '@aztec/circuits.js'; import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; -import { AccountInterface } from '../account/interface.js'; +import { AccountInterface, FeeOptions } from '../account/interface.js'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; import { BaseWallet } from './base_wallet.js'; @@ -14,8 +14,8 @@ export class AccountWallet extends BaseWallet { super(pxe); } - createTxExecutionRequest(execs: FunctionCall[]): Promise { - return this.account.createTxExecutionRequest(execs); + createTxExecutionRequest(execs: FunctionCall[], fee?: FeeOptions): Promise { + return this.account.createTxExecutionRequest(execs, fee); } async createAuthWitness(message: Fr | Buffer): Promise { diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 4a5f49f9c74..8f6519bc0fe 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -21,6 +21,7 @@ import { AztecAddress, CompleteAddress, Fr, GrumpkinPrivateKey, PartialAddress } import { ContractInstanceWithAddress } from '@aztec/types/contracts'; import { NodeInfo } from '@aztec/types/interfaces'; +import { FeeOptions } from '../account/interface.js'; import { Wallet } from '../account/wallet.js'; /** @@ -31,7 +32,7 @@ export abstract class BaseWallet implements Wallet { abstract getCompleteAddress(): CompleteAddress; - abstract createTxExecutionRequest(execs: FunctionCall[]): Promise; + abstract createTxExecutionRequest(execs: FunctionCall[], fee?: FeeOptions): Promise; abstract createAuthWitness(message: Fr): Promise; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 27647730b03..98505879b61 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -120,6 +120,7 @@ export enum GeneratorIndex { PARTIAL_ADDRESS = 27, BLOCK_HASH = 28, SIDE_EFFECT = 29, + FEE_PAYLOAD = 30, TX_REQUEST = 33, SIGNATURE_PAYLOAD = 34, VK = 41, diff --git a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index 97042d3f7d6..dfe804c0fa3 100644 --- a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -12,7 +12,7 @@ contract EcdsaAccount { state_vars::immutable_singleton::ImmutableSingleton }; use dep::authwit::{ - entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness }; @@ -34,9 +34,9 @@ contract EcdsaAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] - fn entrypoint(payload: pub EntrypointPayload) { + fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); - actions.entrypoint(payload); + actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] diff --git a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 166c3279c75..9eb15c3f691 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -13,7 +13,7 @@ contract SchnorrAccount { oracle::get_public_key::get_public_key, state_vars::immutable_singleton::ImmutableSingleton }; use dep::authwit::{ - entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness }; @@ -39,9 +39,9 @@ contract SchnorrAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file #[aztec(private)] - fn entrypoint(payload: pub EntrypointPayload) { + fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); - actions.entrypoint(payload); + actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] diff --git a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index 955ab197d08..c5293bac24c 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -5,7 +5,7 @@ contract SchnorrHardcodedAccount { use dep::aztec::context::PrivateContext; use dep::authwit::{ - entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness }; @@ -19,9 +19,9 @@ contract SchnorrHardcodedAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] - fn entrypoint(payload: pub EntrypointPayload) { + fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); - actions.entrypoint(payload); + actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] @@ -64,4 +64,4 @@ contract SchnorrHardcodedAccount { } // docs:end:is-valid } -// docs:end:contract \ No newline at end of file +// docs:end:contract diff --git a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index 30aac8146ba..f01b3237bfe 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -5,7 +5,7 @@ contract SchnorrSingleKeyAccount { use dep::std::{option::Option}; use dep::aztec::context::{PrivateContext, PublicContext, Context}; - use dep::authwit::{entrypoint::EntrypointPayload, account::AccountActions}; + use dep::authwit::{entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions}; use crate::{util::recover_address, auth_oracle::get_auth_witness}; @@ -16,9 +16,9 @@ contract SchnorrSingleKeyAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] - fn entrypoint(payload: pub EntrypointPayload) { + fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); - actions.entrypoint(payload); + actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr index 52d787e528c..b56ccb8d79e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr @@ -88,7 +88,7 @@ global ARGS_HASH_CHUNK_LENGTH: u32 = 32; global ARGS_HASH_CHUNK_COUNT: u32 = 32; // CONTRACT CLASS CONSTANTS -// This should be around 8192 (assuming 2**15 instructions packed at 8 bytes each), +// This should be around 8192 (assuming 2**15 instructions packed at 8 bytes each), // but it's reduced to speed up build times, otherwise the ClassRegisterer takes over 5 mins to compile. // We are not using 1024 so we can squeeze in a few more args to methods that consume packed public bytecode, // such as the ClassRegisterer.register, and still land below the 32 * 32 max args limit for hashing. @@ -129,7 +129,7 @@ global CALL_CONTEXT_LENGTH: Field = 8; global GLOBAL_VARIABLES_LENGTH: Field = 6; global PARTIAL_STATE_REFERENCE_LENGTH: Field = 8; global STATE_REFERENCE_LENGTH: Field = 10; // 2 for snap + 8 for partial -global HEADER_LENGTH: Field = 20; // 2 for last_archive, 2 for body hash, 10 for state reference, 6 for global vars +global HEADER_LENGTH: Field = 20; // 2 for last_archive, 2 for body hash, 10 for state reference, 6 for global vars global FUNCTION_DATA_LENGTH: Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6; // Change this ONLY if you have changed the PrivateCircuitPublicInputs structure. @@ -196,6 +196,7 @@ global GENERATOR_INDEX__GLOBAL_VARIABLES = 26; global GENERATOR_INDEX__PARTIAL_ADDRESS = 27; global GENERATOR_INDEX__BLOCK_HASH = 28; global GENERATOR_INDEX__SIDE_EFFECT = 29; +global GENERATOR_INDEX__FEE_PAYLOAD = 30; // Indices with size ≤ 16 global GENERATOR_INDEX__TX_REQUEST = 33; global GENERATOR_INDEX__SIGNATURE_PAYLOAD = 34;