Skip to content

Commit f19f635

Browse files
authored
chore: accumulated backports to v4 next (#22569)
.
2 parents f8c89cf + 3ebcd75 commit f19f635

27 files changed

Lines changed: 511 additions & 189 deletions

File tree

docs/docs-developers/docs/aztec-js/how_to_create_account.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ New accounts must be deployed before they can send transactions. Deployment requ
3636

3737
### Using the Sponsored FPC
3838

39-
If your account doesn't have Fee Juice, use the [Sponsored Fee Payment Contract](./how_to_pay_fees.md#sponsored-fee-payment-contracts):
39+
If your account doesn't have Fee Juice, use the [Sponsored FPC](./how_to_pay_fees.md#sponsored-fpc-devnet-and-local-only):
4040

4141
#include_code deploy_account_sponsored_fpc /docs/examples/ts/aztecjs_connection/index.ts typescript
4242

4343
:::info
44-
See the [guide on fees](./how_to_pay_fees.md#sponsored-fee-payment-contracts) for setting up the Sponsored FPC.
44+
See the [guide on fees](./how_to_pay_fees.md#sponsored-fpc-devnet-and-local-only) for setting up the Sponsored FPC.
4545
:::
4646

4747
### Using Fee Juice

docs/docs-developers/docs/aztec-js/how_to_pay_fees.md

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ This guide walks you through paying transaction fees on Aztec using various paym
2020

2121
## Payment methods overview
2222

23-
| Method | Use Case | Privacy | Requirements |
24-
| ------------------- | ----------------------------- | ------- | -------------------------- |
25-
| Fee Juice (default) | Account already has Fee Juice | Public | Funded account |
23+
| Method | Use Case | Privacy | Requirements |
24+
| ------------------- | ---------------------------------------------- | --------------- | ---------------------------- |
25+
| Fee Juice (default) | Account already has Fee Juice | Public | Funded account |
2626
#if(devnet)
27-
| Sponsored FPC | Testing, free transactions | Public | None |
27+
| Sponsored FPC | Testing, free transactions | Public | None |
2828
#else
29-
| Sponsored FPC | Testing, free transactions | Public | None (devnet and local only) |
29+
| Sponsored FPC | Testing, free transactions | Public | None (devnet and local only) |
3030
#endif
31-
| Bridge + Claim | Bootstrap from L1 | Public | L1 ETH for gas |
31+
| Private FPC | Privacy-preserving fees | Private | Bridged Fee Juice via FPC |
32+
| Third-party FPC | Pay in other tokens on testnet/mainnet | Varies by FPC | FPC provider's SDK |
33+
| Bridge + Claim | Bootstrap from L1 | Public | L1 ETH for gas |
3234

3335
## Mana and Fee Juice
3436

@@ -81,9 +83,13 @@ If your account has Fee Juice (for example, from a faucet), is [deployed](./how_
8183

8284
## Use Fee Payment Contracts
8385

84-
Fee Payment Contracts (FPCs) pay Fee Juice on your behalf. FPCs must use Fee Juice exclusively on L2 during the setup phase; custom token contract functions cannot be called during setup on public networks. An FPC that accepts other tokens on L1 and bridges Fee Juice works on any network.
86+
Fee Payment Contracts (FPCs) pay Fee Juice on your behalf. An FPC holds its own Fee Juice balance to pay the protocol and can accept other tokens from users in exchange. Some FPCs operate privately by design, routing fee payments through private notes rather than public function calls.
8587

86-
### Sponsored Fee Payment Contracts
88+
:::note
89+
The SDK includes `PrivateFeePaymentMethod` and `PublicFeePaymentMethod` classes for the built-in reference FPC, but these are **deprecated** and do not work on mainnet alpha. For custom-token fee payment, use a third-party FPC with its own SDK (see [below](#third-party-fpcs-on-testnet-and-mainnet)).
90+
:::
91+
92+
### Sponsored FPC (devnet and local only)
8793

8894
#if(testnet)
8995
:::note
@@ -105,6 +111,61 @@ Here's a simpler example from the test suite:
105111

106112
#include_code sponsored_fpc_simple yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts typescript
107113

114+
### Private Fee Payment
115+
116+
For transactions where the fee payment itself should be private, you can use a fully private FPC — one that holds Fee Juice claimed from L1 as an internal private balance, works on every network, and never needs an onchain deployment. See [Pay Fees Privately](./how_to_use_private_fee_juice.md) for how this pattern works and a walkthrough using a community-built example.
117+
118+
:::tip Shared salt for privacy
119+
When multiple apps derive the same private FPC address (using the same artifact and salt), every private fee payment joins a single, larger privacy set. See [Recommended salt](./how_to_use_private_fee_juice.md#recommended-salt-0) for details.
120+
:::
121+
122+
### Third-party FPCs on testnet and mainnet
123+
124+
On networks where the Sponsored FPC is unavailable, third-party FPCs deployed by ecosystem teams let you pay fees in tokens other than Fee Juice. Each FPC provider typically offers an SDK or API that handles payment method construction on the client side — this may include quote fetching and authwit creation, though the exact flow depends on the FPC design. For background on how FPCs work at the protocol level, see [How FPCs work](../foundational-topics/fees.md#how-fpcs-work).
125+
126+
#### Example: Nethermind Private Multi Asset FPC
127+
128+
To illustrate how a third-party FPC integration works, the following walkthrough uses Nethermind's [Private Multi Asset FPC](https://github.com/NethermindEth/aztec-fpc) as a reference. This is one implementation — other FPCs may differ in design and API.
129+
130+
This FPC is quote-based and operates privately:
131+
132+
- A single deployment accepts many tokens — the asset is selected per quote rather than hard-coded at deploy time.
133+
- Fee payments are transferred as private notes, so fee activity is not visible onchain.
134+
- An operator-run attestation service signs per-user quotes binding the FPC address, accepted asset, amounts, expiry, and user.
135+
- A cold-start entrypoint allows a brand-new account to bridge tokens from L1, claim on L2, and pay the fee in a single transaction. Note that the cold-start path calls `Token::mint_to_private`, which enqueues a public call to update the token's total supply — so the minted amount is visible onchain even though the user's identity and balances remain private.
136+
137+
:::warning Third-party software
138+
This FPC is developed and maintained by Nethermind, not by Aztec Labs. The SDK (`@nethermindeth/aztec-fpc-sdk`) may not yet be published to npm — check the [repository README](https://github.com/NethermindEth/aztec-fpc/blob/main/sdk/README.md) for current install instructions. Review the [protocol spec](https://github.com/NethermindEth/aztec-fpc/blob/main/docs/spec/protocol-spec.md) and evaluate independently before integrating.
139+
:::
140+
141+
The SDK wraps the quote-and-pay flow into a single call. The snippet below shows the general shape of the integration (illustrative — verify against the current SDK API before using):
142+
143+
```ts
144+
import { FpcClient } from "@nethermindeth/aztec-fpc-sdk";
145+
146+
// Point the client at the FPC's attestation service
147+
const fpcClient = new FpcClient({
148+
fpcAddress, // the deployed FPC contract address
149+
operator, // operator's Aztec address
150+
node, // PXE or node connection
151+
attestationBaseUrl: "https://...", // attestation service URL from the FPC provider
152+
});
153+
154+
// Estimate gas, fetch a signed quote, and build the payment method
155+
const payment = await fpcClient.createPaymentMethod({
156+
wallet,
157+
user: wallet.getAddress(),
158+
tokenAddress, // the token you want to pay in
159+
estimatedGas, // from a prior estimateGas call
160+
});
161+
162+
// Use it like any other payment method
163+
const tx = await myContract.methods.myMethod(args).send({ fee: payment.fee });
164+
await tx.wait();
165+
```
166+
167+
For the cold-start flow, deployment addresses, and the full API, see the [`aztec-fpc` repository](https://github.com/NethermindEth/aztec-fpc).
168+
108169
## Bridge Fee Juice from L1
109170

110171
Fee Juice is non-transferable on L2, but you can bridge it from L1, claim it on L2, and use it. This involves a few components that are part of a running network's infrastructure:
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
title: Pay Fees Privately
3+
tags: [fees, privacy, fpc]
4+
sidebar_position: 8
5+
description: Learn how private fee payment works on Aztec and walk through an example using a community-built fully private Fee Payment Contract.
6+
---
7+
8+
import { General, Fees } from '@site/src/components/Snippets/general_snippets';
9+
10+
This guide explains how private fee payment works on Aztec and walks through a concrete example. A fully private FPC can pay transaction fees without revealing the payer — it has no public functions, no owner, and no offchain agent. Because the contract is fully private, **no onchain deployment transaction is required**. Every app just derives the address deterministically from the class hash and a shared salt, and users interact with it privately.
11+
12+
To illustrate the pattern, this guide uses [`PrivateFPC`](https://github.com/defi-wonderland/aztec-fee-payment) — a community-built implementation by [DeFi Wonderland](https://github.com/defi-wonderland). You could write your own private FPC following the same design principles.
13+
14+
## Prerequisites
15+
16+
- <General.AztecJSPrerequisites />
17+
- Familiarity with [fee concepts](../foundational-topics/fees.md) and [Paying Fees](./how_to_pay_fees.md)
18+
19+
:::info
20+
<Fees.FeeAsset_NonTransferrable />
21+
:::
22+
23+
## Why a fully private FPC?
24+
25+
The `PrivateFeePaymentMethod` shipped in `@aztec/aztec.js/fee` (now deprecated) targets the reference [`FPC` contract](https://github.com/AztecProtocol/aztec-packages/blob/next/noir-projects/noir-contracts/contracts/fees/fpc_contract/src/main.nr), which accepts an arbitrary asset and calls custom token functions (like `transfer_to_public`) during the setup phase of a transaction. Since Aztec v4.2.0, token functions are no longer in the default public setup allowlist, so that flow is rejected on public networks. See the [migration note](../resources/migration_notes.md#custom-token-fpcs-removed-from-default-public-setup-allowlist) for details.
26+
27+
A fully private FPC avoids the problem entirely by holding Fee Juice claimed from L1 as an internal private balance and never making cross-contract calls during setup — it only verifies a Fee Juice nullifier exists and deducts from its own private balance, so it passes the allowlist on every network.
28+
29+
## How a private FPC works
30+
31+
This section describes the design pattern using Wonderland's `PrivateFPC` as an example. The contract stores an internal, note-based `BalanceSet` of Fee Juice per user. There is no constructor, no admin, and no public surface.
32+
33+
Two flows are supported:
34+
35+
1. **Bridge + mint + pay** (recommended steady state):
36+
1. On L1, deposit Fee Juice to the `FeeJuicePortal`, targeting the FPC's Aztec address as the recipient and using a claimer-bound secret hash.
37+
2. On L2, call `FeeJuice.claim(...)` to emit the Fee Juice nullifier.
38+
3. Call `PrivateFPC.mint(amount, salt, leaf_index)` to convert the bridge claim into private Fee Juice balance inside the FPC, credited to the claimer.
39+
4. From that point on, every transaction can call `PrivateFPC.pay_fee()` to deduct `max_gas_cost` from the internal balance and have the FPC set itself as the transaction's fee payer.
40+
2. **Cold-start:** First call `FeeJuice.claim(...)` so the Fee Juice nullifier lands onchain, then in a follow-up transaction call `PrivateFPC.mint_and_pay_fee(amount, salt, leaf_index)`. The contract verifies the nullifier exists, credits `amount - max_gas_cost` to the claimer, and pays the fee — useful when the user has no prior balance with the FPC.
41+
42+
Because `pay_fee` never makes cross-contract calls — it only deducts from the FPC's internal private balance and calls `set_as_fee_payer` — no custom token calls ever happen during the setup phase.
43+
44+
:::note No refund
45+
`PrivateFPC.pay_fee()` deducts the full `max_gas_cost` and does not refund unused gas. Use `estimateGas` (see [Estimate mana costs](./how_to_pay_fees.md#estimate-mana-costs)) to right-size your limits.
46+
:::
47+
48+
## Share one FPC address across the ecosystem
49+
50+
Privacy on Aztec comes from indistinguishability. When two transactions call the *same* contract with the *same* function selector and argument shape, they are indistinguishable to an outside observer. If your app derives its own copy of a private FPC with a unique salt, that copy has its own (tiny) anonymity set. If every app derives the *same* FPC address and routes fees through it, every private fee payment in the ecosystem looks the same, and they all share a single, much larger privacy set.
51+
52+
This is the whole point of a fully private FPC: because you don't have to deploy it on L2, there is no race to "be the deployer" — the only thing that matters is that everyone agrees on the address.
53+
54+
## Recommended salt: `0`
55+
56+
Two parties derive the same contract address if and only if they use the same compiled artifact and the same deployment salt. For any fully private FPC, using a common salt maximizes the shared privacy set. The community convention for Wonderland's `PrivateFPC` is `Fr.ZERO`.
57+
58+
This is a convention, not a protocol-enforced default. It is up to each developer to pass the salt when registering the contract with their PXE, just as they choose any other deployment parameter. Following the convention means your users' private fee payments join the same privacy set as every other app that follows it.
59+
60+
:::danger Version-specific addresses
61+
The `PrivateFPC` address depends on the compiled contract bytecode. A different Aztec version produces different bytecode and therefore a **different address**. Sending Fee Juice to the wrong address means **unrecoverable loss**. Before using a derived address on a given network, verify the network runs the same Aztec version as the Wonderland SDK version you have installed.
62+
:::
63+
64+
## Example: pay fees with Wonderland's `PrivateFPC`
65+
66+
The SDK exports two payment methods (`FPCFeePaymentMethod` for users who already have a private balance, and `PrivateMintAndPayFeePaymentMethod` for cold-start) plus a `registerPrivateContract` helper that registers the FPC with your PXE using the shared salt — no deployment transaction needed.
67+
68+
For installation, the complete bridge-claim-mint-pay flow, required `send()` options (including `additionalScopes` and `gasSettings`), and a runnable end-to-end example, see the [SDK README](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/src/ts/README.md) and the [integration test](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/src/ts/test/private.test.ts).
69+
70+
:::note Transaction behavior
71+
| Scenario | Status | Execution result | Fee paid? |
72+
| --- | --- | --- | --- |
73+
| Private revert | `DROPPED` (not included in block) || No |
74+
| Public revert | `PROPOSED` | `REVERTED` | Yes (FPC pays) |
75+
| Success | `PROPOSED` | `SUCCESS` | Yes (FPC pays) |
76+
:::
77+
78+
## Reference implementation
79+
80+
Wonderland's repository ships detailed documentation for this design and its security properties:
81+
82+
- [Private FPC Product Requirements](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/docs/private-product-requirements.md) — problem statement, requirements matrix, cryptographic design (secret derivation, nullifier reconstruction, double-spend prevention), and security properties
83+
- [`PrivateFPC` Noir source](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/src/nr/private_contract/src/main.nr) — the contract itself, annotated with the full bridge-to-mint-to-pay flow
84+
- [`src/ts/README.md`](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/src/ts/README.md) — SDK reference with every exported class and utility
85+
- [Integration test `private.test.ts`](https://github.com/defi-wonderland/aztec-fee-payment/blob/dev/src/ts/test/private.test.ts) — canonical end-to-end example of the bridge → claim → mint → sponsor flow
86+
87+
## Next steps
88+
89+
- Learn about [fee concepts](../foundational-topics/fees.md) in detail
90+
- Review the other [fee payment methods](./how_to_pay_fees.md) available in `aztec.js`
91+
- Browse Wonderland's [`aztec-fee-payment`](https://github.com/defi-wonderland/aztec-fee-payment) repository for the Noir source, TypeScript SDK, and integration examples

0 commit comments

Comments
 (0)