Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Fee Payments

Choose and apply a fee payment strategy via aztec-fee.

Runnable Examples

  • examples/fee_native.rs — sender holds Fee Juice.
  • examples/fee_sponsored.rs — public sponsor pays unconditionally.
  • examples/fee_juice_claim.rs — claim Fee Juice bridged from L1 and pay in the same tx.

Strategies

TypeWhen to use
NativeFeePaymentMethodAccount already holds Fee Juice
SponsoredFeePaymentMethodA public sponsor contract will pay unconditionally
FeeJuicePaymentMethodWithClaimFirst-time user claiming Fee Juice from an L1 deposit

Private Fee Payment Contract (FPC) support is planned but is not currently shipped; consumers needing that flow must implement FeePaymentMethod themselves.

Typical Flow

use aztec_rs::fee::{FeePaymentMethod, NativeFeePaymentMethod};
use aztec_rs::wallet::SendOptions;

let fee_payload = NativeFeePaymentMethod::new(alice)
    .get_fee_execution_payload()
    .await?;

wallet.send_tx(
    execution_payload,
    SendOptions {
        from: alice,
        fee_execution_payload: Some(fee_payload),
        gas_settings: Some(aztec_rs::fee::GasSettings::default()),
        ..Default::default()
    },
).await?;

The wallet merges the fee payload with execution_payload before handing the combined request to the account provider.

Claim-Based Flow (Bridge from L1)

use aztec_rs::l1_client::{EthClient, prepare_fee_juice_on_l1};
use aztec_rs::fee::FeeJuicePaymentMethodWithClaim;

let bridge = prepare_fee_juice_on_l1(&eth_client, &l1_addresses, alice, amount).await?;
// Wait for L2-side readiness first (see cross-chain guide).
let fee   = FeeJuicePaymentMethodWithClaim::new(alice, bridge.claim);
let payload = fee.get_fee_execution_payload().await?;

Edge Cases

  • Estimate drift: adjust GasSettings::max_fee_per_gas to include a margin above the simulated value.
  • Sponsor refusal: SponsoredFeePaymentMethod can still be rejected by the sponsor contract at inclusion time; handle the revert.
  • Claim not ready: verify via is_l1_to_l2_message_ready before invoking the claim-based strategy.

Full Runnable Example

Source: examples/fee_native.rs.

//! Send a transaction with an explicit native fee payload.

#![allow(clippy::print_stdout, clippy::wildcard_imports)]

mod common;

use common::*;

#[tokio::main]
async fn main() -> Result<(), aztec_rs::Error> {
    let Some((wallet, alice)) = setup_wallet(TEST_ACCOUNT_0).await else {
        return Err(aztec_rs::Error::InvalidData(format!(
            "node not reachable at {}",
            node_url()
        )));
    };
    let bob = imported_complete_address(TEST_ACCOUNT_1).address;

    let (token_address, token_artifact, _) = deploy_token(&wallet, alice, 0).await?;
    send_token_method(
        &wallet,
        &token_artifact,
        token_address,
        "mint_to_public",
        vec![AbiValue::Field(Fr::from(alice)), AbiValue::Integer(1_000)],
        alice,
    )
    .await?;

    let fee_payload = NativeFeePaymentMethod::new(alice)
        .get_fee_execution_payload()
        .await?;
    let tx_hash = wallet
        .send_tx(
            ExecutionPayload {
                calls: vec![build_call(
                    &token_artifact,
                    token_address,
                    "transfer_in_public",
                    vec![
                        AbiValue::Field(Fr::from(alice)),
                        AbiValue::Field(Fr::from(bob)),
                        AbiValue::Integer(10),
                        AbiValue::Integer(0),
                    ],
                )],
                ..Default::default()
            },
            SendOptions {
                from: alice,
                fee_execution_payload: Some(fee_payload),
                gas_settings: Some(GasSettings::default()),
                ..Default::default()
            },
        )
        .await?
        .tx_hash;

    println!("Token address:      {token_address}");
    println!("Alice:              {alice}");
    println!("Bob:                {bob}");
    println!("Tx hash:            {tx_hash}");
    println!(
        "Bob public balance: {}",
        public_balance(&wallet, token_address, &bob).await?
    );

    Ok(())
}

For sponsored and claim-based variants, see examples/fee_sponsored.rs and examples/fee_juice_claim.rs in the repository.

References