Skip to content

Latest commit

 

History

History
163 lines (108 loc) · 10.9 KB

File metadata and controls

163 lines (108 loc) · 10.9 KB

Aztec FPC

TLDR

FPC (Fee Payment Contract) is an Aztec primitive: a smart contract that pays Fee Juice on a user's behalf. The protocol supports three FPC designs (sponsored, private, third-party-token) and doesn't dictate what the operator receives in return.

Nethermind's aztec-fpc is one such implementation: a private, multi-asset, quote-based FPC deployed on testnet. Users pay the operator in any accepted token, at a rate locked by an operator-signed Schnorr quote. One contract instance serves any number of tokens; new tokens are added via the attestation service without redeploying.

Components

Component Role
FPC Contract (FPCMultiAsset) On-chain fee payer. Verifies operator-signed quotes, transfers tokens from user to operator, pays Fee Juice to the protocol.
Attestation Service REST API that signs per-user fee quotes with the operator's Schnorr key. Serves wallet discovery metadata at /.well-known/fpc.json.
Top-up Service Monitors the FPC's Fee Juice balance on L2 and bridges more from L1 when it drops below a threshold.
SDK (@nethermindeth/aztec-fpc-sdk) TypeScript client that handles quote fetching, auth-witness construction, and transaction submission.
Tokens accepted Any operator-accepted token (added via the admin API, no redeployment)
Cold-start 1 tx from L1 bridge to active L2 account
On-chain allowlist None required (quote-binding enforces asset selection)
SDK surface 2 methods

GitHub | SDK Getting Started | Testnet Deployment


What is FPC?

Every Aztec transaction requires Fee Juice, the protocol's native fee token. Fee Juice is non-transferable on L2 and must be bridged from L1 or paid on a user's behalf by another contract.

FPC is the Aztec pattern for the second option: a smart contract that holds Fee Juice and pays it for the user. The protocol doesn't prescribe what (if anything) the operator receives back. Existing FPC designs include:

  • Sponsored FPC: pays unconditionally for free transactions (testnet, devnet, local networks only)
  • Private FPC: routes fee payments through private notes so fee activity stays off the public state
  • Third-party token FPCs: accept a specific token in exchange for covering the Fee Juice cost

What aztec-fpc is

Nethermind's aztec-fpc is a private, multi-asset, quote-based FPC deployed on testnet. Three properties define it:

  • Multi-asset: one contract instance serves any number of accepted tokens. The asset is selected per-quote, not hard-coded at deploy time. New tokens are added through the attestation service's admin API without redeploying.
  • Private: fee payments move as private notes via transfer_private_to_private. Fee activity is not visible in public state. (Exception: the cold-start path calls mint_to_private, which enqueues a public increase_total_supply_internal call, so the minted amount is visible even though the user's identity and balances remain private.)
  • Quote-based: an operator-run attestation service signs per-user quotes binding the FPC address, accepted asset, payment amount, Fee Juice amount, expiry, and user address. The on-chain contract verifies the Schnorr signature before executing the transfer.

A cold-start entrypoint lets a brand-new account bridge tokens from L1, claim on L2, and pay the fee in one transaction.

The operator holds Fee Juice (auto-topped-up from L1 by the top-up service), sets pricing via a configurable fee_bips spread in the attestation service, and keeps the margin.

How a standard transaction works

FPC transaction flow: User requests a signed quote from the Attestation Service, submits a transaction to the FPC Contract which verifies the quote, transfers the user's token to the operator, and pays fees.

The wallet requests a quote from the attestation service, which prices the Fee Juice cost in the user's token and signs it with the operator's Schnorr key. The user includes the operator's quote signature in their transaction alongside a transfer authorization witness (authwit). The authwit authorizes the token transfer and is carried as an execution payload component, not a function argument to fee_entrypoint.

The FPC contract then:

  1. Reconstructs the quote hash via compute_inner_authwit_hash over the 7-field preimage (domain separator, FPC address, accepted asset, Fee Juice amount, payment amount, expiry, user address)
  2. Verifies the Schnorr signature against the stored operator public key
  3. Pushes a nullifier to prevent replay
  4. Calls transfer_private_to_private to move the payment from user to operator
  5. Calls set_as_fee_payer() and end_setup(), committing the fee before the user's app logic runs

All of this executes in the setup phase.

What aztec-fpc does not do

It does not eliminate fee costs. It shifts who pays them and in what token. The operator takes on the operational cost of keeping the FPC funded with Fee Juice and recoups it through a configurable spread per token. The spread is set as fee_bips in the attestation service configuration and is applied off-chain when pricing quotes. The on-chain contract has no knowledge of fee_bips. It verifies and settles whatever signed amounts the attestation service produced.

Quote signatures are user-specific and single-use. A quote issued to one user cannot be used by another, and a consumed quote cannot be replayed. The operator is not exposed to a free-rider problem, but they are exposed to market rate risk if the token value moves between quote issuance and settlement.

There is no on-chain asset allowlist. The contract does not enforce which tokens are accepted. Protection comes entirely from the quote signature: accepted_asset is part of the signed compute_inner_authwit_hash preimage, so substituting a different token at call time invalidates the signature.

Operator key rotation requires deploying a new contract. The public key is stored in PublicImmutable and cannot be updated.

Comparison with Aztec's Sponsored FPC

Aztec Labs ships a Sponsored FPC for development and testing only. It is available on testnet, devnet, and local networks, not on mainnet. It is a pure subsidy run by Aztec Labs with no payment mechanism, no operator revenue, no cold-start, and no off-chain services.

Nethermind's aztec-fpc is the production-oriented variant. The operator runs it, accepts payment in any operator-accepted token via Schnorr-signed single-use quotes, earns a configurable fee_bips spread, and supports cold-start onboarding from L1 via cold_start_entrypoint.


Quick Example

import { FpcClient } from "@nethermindeth/aztec-fpc-sdk";

// Standard flow: user already holds an operator-accepted token on L2
const { fee } = await fpcClient.createPaymentMethod({
  wallet,
  user: userAddress,
  tokenAddress,
  estimatedGas,
});
await contract.methods.transfer(recipient, amount).send({ fee });

// Cold-start: user just bridged an operator-accepted token from L1 to L2
const result = await fpcClient.executeColdStart({
  wallet,
  userAddress,
  tokenAddress,
  bridgeAddress,
  bridgeClaim,
});

Start Here

You are... Goal Start here
dApp developer Use an existing FPC operator or run your own SDK Getting Started
Wallet team / operator Deploy the contract, configure attestation, surface FPC in your wallet Testnet Deployment
Bridge / onboarding UX Claim bridged tokens, pay fees, deliver the remainder in one atomic tx SDK Getting Started
Auditor Quote binding, setup-phase irreversibility, replay protection, operator key custody Security

Tip

Wallet teams running their own FPC combine the operator and integrator roles. Start with the SDK Getting Started, then follow the Run an Operator guide to deploy and fund your own instance.


Documentation

Section Pages
Overview Architecture, Quote System, Security, Quick Start
SDK Getting Started, API Reference
Contracts Overview, FPCMultiAsset, Faucet, Token Bridge
Services Attestation, Top-up
How-to Run an Operator, Integrate Wallet, Add Supported Asset, Cold-Start Flow
Operations Configuration, Deployment, Docker, Testing
Reference Metrics, E2E Test Matrix, Testnet Deployment, Wallet Discovery, Asset Model ADR

Contributing to Docs

After editing any .md file in docs/, regenerate the LLM index:

bash scripts/generate-llms-full.sh

Commit the updated docs/public/llms-full.txt alongside your changes. The docs-freshness CI check will fail if it's stale.

When adding a new page: create the .md file, add it to the FILES=() array in scripts/generate-llms-full.sh, add it to the documentation table above, and add it to docs/public/llms.txt.

Testnet addresses live in one place: docs/reference/testnet-deployment.md. All other pages reference it.

Get Help

For Aztec protocol questions (not specific to this FPC implementation), see the Aztec docs and Aztec Discord.


Aztec FPC, Nethermind, Apache-2.0