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
| Type | When to use |
|---|---|
NativeFeePaymentMethod | Account already holds Fee Juice |
SponsoredFeePaymentMethod | A public sponsor contract will pay unconditionally |
FeeJuicePaymentMethodWithClaim | First-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(ð_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_gasto include a margin above the simulated value. - Sponsor refusal:
SponsoredFeePaymentMethodcan still be rejected by the sponsor contract at inclusion time; handle the revert. - Claim not ready: verify via
is_l1_to_l2_message_readybefore 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.