Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 1 addition & 25 deletions docs/docs-developers/docs/aztec-js/aztec_js_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This is an auto-generated reference. For tutorials and guides, see the [Aztec.js

*Package: @aztec/aztec.js*

*Generated: 2026-08-19T09:19:51.719Z*
*Generated: 2026-08-24T07:31:17.032Z*

This document provides a comprehensive reference for all public APIs in the Aztec.js library.

Expand Down Expand Up @@ -94,7 +94,6 @@ Each section is organized by module, with classes, interfaces, types, and functi
- [L2Claim](#l2claim)
- [L2AmountClaim](#l2amountclaim)
- [L2AmountClaimWithRecipient](#l2amountclaimwithrecipient)
- [generateClaimSecret](#generateclaimsecret)
- [L1TokenManager](#l1tokenmanager)
- [L1FeeJuicePortalManager](#l1feejuiceportalmanager)
- [L1ToL2TokenPortalManager](#l1tol2tokenportalmanager)
Expand Down Expand Up @@ -3332,29 +3331,6 @@ Address that will receive the newly minted notes.
**Type:** `AztecAddress`


#### generateClaimSecret

**Type:** Function

Generates a pair secret and secret hash

**Signature:**

```typescript
export async generateClaimSecret(logger?: Logger): Promise<[
Fr,
Fr
]>
```

**Parameters:**

- `logger` (optional): `Logger`

**Returns:**

`Promise<[Fr, Fr]>`

#### L1TokenManager

**Type:** Class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ This section describes the design pattern using the `private-fee-juice` package'
Two different salt values show up in this flow; it's worth naming them up front so they don't get confused:

- **Deployment salt.** Used to derive the FPC's contract address. Once a community agrees on the bytecode and this salt, everyone can derive the same address locally without an onchain deployment tx. The convention for the `private-fee-juice` `PrivateFPC` is `Fr.ZERO` (see [Recommended salt](#recommended-salt-0)).
- **Bridge salt.** A random value the user chooses per L1 deposit. Combined with the user's Aztec address, it derives the _bridge secret_ (`secret = poseidon2([salt, claimer], DOM_SEP__FPC_BRIDGE_SECRET)`), whose hash is passed as the `secretHash` on the L1 deposit. Only the user knows the preimage, so only the user can later produce the `secret` that `FeeJuice.claim` requires to consume the L1-to-L2 message.
- **Bridge salt.** A random value the user chooses per L1 deposit. Combined with the user's Aztec address, it derives the _bridge secret_ (`secret = poseidon2([salt, claimer], DOM_SEP__FPC_BRIDGE_SECRET)`), whose hash is passed as the `privateContentHash` on the L1 deposit. Only the user knows the preimage, so only the user can later produce the `secret` that `FeeJuice.claim` requires to consume the L1-to-L2 message.

`PrivateFPC.mint(amount, salt, leaf_index)` and `PrivateFPC.mint_and_pay_fee(amount, salt, leaf_index)` take the **bridge** salt (along with the leaf index and the user's claimer address, which is `msg_sender`) to reconstruct the Fee Juice claim nullifier and verify the bridge was consumed.

### Two flows

1. **Bridge + mint + pay** (run once to seed the user's private Fee Juice balance inside the FPC, and run again each time that balance runs low and the user wants to add more by bridging another deposit from L1):
1. **L1 deposit.** Call `FeeJuicePortal.depositToAztecPublic(_to = fpcAddress, _amount = amount, _secretHash = computeSecretHash(bridgeSecret))` where `bridgeSecret = poseidon2([bridgeSalt, claimer], DOM_SEP__FPC_BRIDGE_SECRET)`. The FPC is the _recipient_ of the deposit, the user is the _claimer_.
1. **L1 deposit.** Call `FeeJuicePortal.depositToAztecPublic(_to = fpcAddress, _amount = amount, _privateContentHash = computePrivateContentHash(bridgeSecret))` where `bridgeSecret = poseidon2([bridgeSalt, claimer], DOM_SEP__FPC_BRIDGE_SECRET)`. The FPC is the _recipient_ of the deposit, the user is the _claimer_.
2. **L2 claim.** In a normal L2 transaction, call `FeeJuice.claim(fpcAddress, amount, bridgeSecret, leafIndex)` directly. This consumes the L1-to-L2 message, credits Fee Juice to the FPC's **public** Fee Juice balance, and emits the claim nullifier. The fee for this transaction is paid by whatever mechanism the user normally uses (their own Fee Juice, `FeeJuicePaymentMethodWithClaim` on a _separate_ bridge they control, the Sponsored FPC on devnet/testnet, and so on). The `PrivateFPC` does _not_ sponsor this call, because at this point the user has no balance with it yet.
3. **Mint.** In a follow-up L2 transaction, call `PrivateFPC.mint(amount, bridgeSalt, leafIndex)` (again paid by whatever mechanism the user normally uses). `mint` does **not** call `FeeJuice.claim` again, because the claim already happened in step 1.2. The contract recomputes the same nullifier value that the earlier `claim` emitted (possible because the user supplies the `bridgeSalt` that originally produced it), asserts that nullifier exists in the nullifier tree as proof the L1 deposit was consumed, emits its own FPC-scoped nullifier to prevent double-minting the same bridge credit, and credits `amount` to the claimer's private balance inside the FPC.
4. **Pay.** From that point on, the user can pass `new FPCFeePaymentMethod(fpcAddress)` as the payment method on any transaction. Under the hood, the method calls `PrivateFPC.pay_fee()` in setup, which deducts `max_gas_cost` from the user's private balance and makes the FPC the fee payer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Use the `Inbox` contract's `sendL2Message` function:
| Parameter | Type | Description |
| ------------- | --------- | ------------------------------------------------------- |
| `_recipient` | `L2Actor` | L2 contract address and rollup version |
| `_content` | `bytes32` | Hash of message content (use `Hash.sha256ToField`) |
| `_secretHash` | `bytes32` | Hash of secret for message consumption |
| `_publicContentHash` | `bytes32` | Hash of the public message content (use `Hash.sha256ToField`) |
| `_privateContentHash` | `bytes32` | Hash of the private message content. |

#include_code deposit_public l1-contracts/test/portals/TokenPortal.sol solidity

Expand All @@ -36,7 +36,7 @@ L1 to L2 messages are not available immediately. The proposer batches messages f

### Consume the message on L2

Call `consume_l1_to_l2_message` on the context. The `content` must match the hash sent from L1, and the `secret` must be the pre-image of the `secretHash`. Consuming a message emits a nullifier to prevent double-spending.
Call `consume_l1_to_l2_message` on the context. The `public_content_hash` must match the hash sent from L1, and the `private_content` must be the preimage of the `private_content_hash` (in the common claim-secret scheme, the secret the depositor generated on L1). Consuming a message emits a nullifier to prevent double-spending.

The content hash must be computed identically on both L1 and L2. Create a shared library for your content hash functions—see [`token_portal_content_hash_lib`](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/labs/noir-contracts/contracts/libs/token_portal_content_hash_lib) for an example.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ An entity on L2, specifying the Aztec address and the protocol version. Used whe

## `L1ToL2Msg`

A message sent from L1 to L2. The `secretHash` field contains the hash of a secret pre-image that must be known to consume the message on L2. Use [`computeSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/stdlib/src/hash/hash.ts) to compute it from a secret.
A message sent from L1 to L2. The `publicContentHash` field is the hash of the application-specific public content of the message. The `privateContentHash` field is the hash of the private content, whose preimage is typically used to consume the message. Use [`computePrivateContentHash`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/stdlib/src/hash/hash.ts) to compute it from the private content.

#include_code l1_to_l2_msg l1-contracts/src/core/libraries/DataStructures.sol solidity

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ Sends a message from L1 to L2.
| Name | Type | Description |
| ----------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Recipient | [`L2Actor`](./data_structures.md#l2actor) | The recipient of the message. The recipient's version **MUST** match the inbox version and the actor must be an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. |
| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to a single field for rollup purposes. If the content is small enough it can be passed directly, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/l1-contracts/src/core/libraries/crypto/Hash.sol) utilities with `sha256ToField` functions). |
| Secret Hash | `field` (~254 bits) | A hash of a secret used when consuming the message on L2. Keep this preimage secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed). Use [`computeSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/stdlib/src/hash/hash.ts) to compute it from a secret. |
| Public Content Hash | `field` (~254 bits) | Hash of the public content of the message. |
| Private Content Hash | `field` (~254 bits) | Hash of the private content of the message. The private content is application-defined: most commonly a random claim secret generated by the depositor, but it could also be, for example, the L2 recipient plus a blinding salt. The private content is typically needed to be known to consume the message (the value that was hashed). Use [`computePrivateContentHash`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/stdlib/src/hash/hash.ts) to compute its hash. |
| ReturnValue | `(bytes32, uint256)` | The message hash (used as an identifier) and the leaf index in the tree. |

#### Edge cases

- Will revert with `Inbox__ActorTooLarge(bytes32 actor)` if the recipient actor is larger than the field size (~254 bits).
- Will revert with `Inbox__VersionMismatch(uint256 expected, uint256 actual)` if the recipient version doesn't match the inbox version.
- Will revert with `Inbox__ContentTooLarge(bytes32 content)` if the content is larger than the field size (~254 bits).
- Will revert with `Inbox__SecretHashTooLarge(bytes32 secretHash)` if the secret hash is larger than the field size (~254 bits).
- Will revert with `Inbox__PublicContentHashTooLarge(bytes32 publicContentHash)` if the public content hash is larger than the field size (~254 bits).
- Will revert with `Inbox__PrivateContentHashTooLarge(bytes32 privateContentHash)` if the private content hash is larger than the field size (~254 bits).

## View functions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,18 @@ For cross-chain messages, this means inserting and nullifying L1 → L2 messages
While a message could theoretically be arbitrarily long, we want to limit the cost of the insertion on L1 as much as possible. Therefore, we allow the users to send 32 bytes of "content" between L1 and L2. If 32 suffices, no packing required. If the 32 is too "small" for the message directly, the sender should simply pass along a `sha256(content)` instead of the content directly (note that this hash should fit in a field element which is ~254 bits. More info on this below). The content can then either be emitted as an event on L2 or kept by the sender, who should then be the only entity that can "unpack" the message.
In this manner, there is some way to "unpack" the content on the receiving domain.

The message that is passed along requires the `sender/recipient` pair to be communicated as well (we need to know who should receive the message and be able to check). By having the pending messages be a contract on L1, we can ensure that the `sender = msg.sender` and let only `content` and `recipient` be provided by the caller. We only store the commitment (`sha256(LxToLyMsg)`) on chain or in the trees, so we only need to update a single storage slot per message.
The message that is passed along requires the `sender/recipient` pair to be communicated as well (we need to know who should receive the message and be able to check). By having the pending messages be a contract on L1, we can ensure that the `sender = msg.sender` and let only `publicContentHash`, `privateContentHash` and `recipient` be provided by the caller. We only store the commitment (`sha256(LxToLyMsg)`) on chain or in the trees, so we only need to update a single storage slot per message.

See the [Data Structures](./data_structures.md) page for the full message structure definitions (`L1Actor`, `L2Actor`, `L1ToL2Msg`, `L2ToL1Msg`).

:::info
The `bytes32` elements for `content` and `secretHash` hold values that must fit in a field element (~ 254 bits).
The `bytes32` elements for `publicContentHash` and `privateContentHash` hold values that must fit in a field element (~ 254 bits).
:::

:::info
The nullifier computation should include the index of the message in the message tree to ensure that it is possible to send duplicate messages (e.g., 2 x deposit of 500 dai to the same account).

To make it possible to hide when a specific message is consumed, the `L1ToL2Msg` is extended with a `secretHash` field, where the `secretPreimage` is used as part of the nullifier computation. This way, it is not possible for someone just seeing the `L1ToL2Msg` on L1 to know when it is consumed on L2.
To make it possible to hide when a specific message is consumed, the `L1ToL2Msg` carries a `privateContentHash` field, where the private content (its preimage) is used as part of the nullifier computation. The private content is application-defined: most commonly a random claim secret generated by the depositor, but it could also be, for example, the L2 recipient plus a blinding salt. This way, it is not possible for someone just seeing the `L1ToL2Msg` on L1 to know when it is consumed on L2.
:::

## Combined Architecture
Expand Down
2 changes: 1 addition & 1 deletion docs/docs-developers/docs/foundational-topics/fees.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Fee Juice originates on Ethereum as an ERC-20 token. Bridging means depositing t
Bridging happens in two steps:

1. **Deposit on L1.** The depositor generates a random claim secret, approves the `FeeJuicePortal` to spend their tokens, and calls its deposit function with the recipient's Aztec address, the amount, and the hash of the claim secret. The portal locks the tokens and sends an L1-to-L2 message addressed to the `FeeJuice` protocol contract on Aztec.
2. **Claim on L2.** After the message becomes available on Aztec (about two L2 blocks after the deposit), the claimant presents the claim secret to the `FeeJuice` contract. It consumes the message, emitting a nullifier so the same deposit cannot be claimed twice, and credits the recipient's public Fee Juice balance.
2. **Claim on L2.** After the message becomes available on Aztec (about two L2 blocks after the deposit), the claimant presents the claim secret (the message's private content) to the `FeeJuice` contract. It consumes the message, emitting a nullifier so the same deposit cannot be claimed twice, and credits the recipient's public Fee Juice balance.

Only the hash of the claim secret appears on L1, and the recipient address is fixed at deposit time, so revealing the secret on L2 releases the funds only to the intended recipient.

Expand Down
Loading
Loading