Skip to content

feat(docs): add uniswap tut#20233

Merged
sklppy88 merged 1 commit intonextfrom
ek/feat/uniswap-tutorial
Mar 12, 2026
Merged

feat(docs): add uniswap tut#20233
sklppy88 merged 1 commit intonextfrom
ek/feat/uniswap-tutorial

Conversation

@sklppy88
Copy link
Contributor

@sklppy88 sklppy88 commented Feb 6, 2026

adds uniswap tut and sample code

@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from 6673509 to 13c5831 Compare February 11, 2026 17:42
@sklppy88 sklppy88 requested a review from critesjosh February 11, 2026 17:42
Copy link
Contributor

@critesjosh critesjosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdyt about adding tests?

Also, It seems like there are some missing steps (e.g. compiling contracts, both solidity and aztec)


Before starting, make sure you have the Aztec local network running at version #include_aztec_version. Check out [the local network guide](../../../getting_started_on_local_network.md) for setup instructions.

## What You'll Build
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a prerequisites section somewhere near the top.

This quickly gets into a bit of Aztec jargon (l2-l1 messages, portals, governance concepts) and it would be nice for readers to know where to go to learn more about these topics. Maybe just add links in-line as these concepts are introduced

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the intention is to have readers write the code as they go along, I think it should be more clear. There should be a "project setup" section that helps readers set up their project so they know what tools they will be using and where to put the files as they encounter them.


Both messages must be consumed on L1 before the swap executes. This two-message pattern prevents anyone from stealing funds or changing swap parameters.

### Why Two Messages?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this section is redundant with the lines just above. consider consolidating them

The public swap transfers tokens from the sender to the contract, exits them to L1 via the bridge, and sends a swap intent message:

:::note Authorization Witnesses
Aztec uses **authorization witnesses** (authwit) instead of the ERC20 approve/transferFrom pattern. The contract computes the hash of the exact action it wants to perform, sets that hash as authorized, then immediately performs the action. This gives fine-grained control - the authorization is for a specific action, not a blanket approval. Since we authorize and spend in the same transaction, replay attacks are impossible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add a link to the authwit page

IInbox public inbox;
uint256 public rollupVersion;

function initialize(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a comment that there is no access control on this, but there should be for a real prod contract?

uint256[2] calldata _leafIndices,
bytes32[][2] calldata _paths
) external returns (bytes32, uint256) {
IERC20 inputAsset = ExampleTokenPortal(_inputTokenPortal).underlying();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inputAsset is unused

));

// Approve bridge to burn this contract's funds and exit to L1 Uniswap Portal
let _ = self.call_self._approve_bridge_and_exit_input_asset_to_L1(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe worth adding a note about the let _ syntax and why its used. wdyt?

console.log(`Deposit message leaf index: ${depositLeafIndex}\n`);
// docs:end:deposit_to_l2

// docs:start:mine_blocks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont think this is used in the tutorial or explained why mining 2 blocks in necessary

@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from b3f871b to de017ec Compare March 3, 2026 11:25
@sklppy88 sklppy88 requested a review from critesjosh March 3, 2026 11:28
@sklppy88 sklppy88 marked this pull request as ready for review March 3, 2026 12:07
@sklppy88 sklppy88 requested a review from a team as a code owner March 3, 2026 12:07
@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch 2 times, most recently from 11fcbb0 to 3b13191 Compare March 3, 2026 17:35
Copy link
Contributor

@critesjosh critesjosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the build is broken. also can you merge next into this branch once the TS execution PR (#20113) get merged in, and make sure that the TS in this PR runs

@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from 02d739d to 5527846 Compare March 4, 2026 17:10
@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch 7 times, most recently from 65d2eb1 to 6d6f329 Compare March 6, 2026 11:47
@AztecBot AztecBot requested a review from a team March 6, 2026 12:01
@AztecBot AztecBot force-pushed the ek/feat/uniswap-tutorial branch from 6d6f329 to f24e354 Compare March 6, 2026 12:03
@AztecBot AztecBot enabled auto-merge March 6, 2026 12:03
@sklppy88 sklppy88 disabled auto-merge March 6, 2026 12:05
@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from f24e354 to e78ecf7 Compare March 6, 2026 12:20
@sklppy88 sklppy88 requested a review from critesjosh March 6, 2026 12:38
Copy link
Contributor

@critesjosh critesjosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main components of the tutorial are all here, we just need to stitch them together properly and polish it so new folks can get through this with minimal friction.


## Part 1: Token Portal (Solidity)

The [token portal](../../aztec-nr/framework-description/ethereum_aztec_messaging.md) handles depositing tokens from L1 to L2 and withdrawing from L2 to L1. This version hardcodes `caller_on_l1` to `address(0)` (meaning anyone can execute the withdrawal).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see caller_on_l1 being hardcoded to 0. maybe i missing it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, I think we can link to a better page, the current link is about general message passing, not about a token portal specifically, as the link indicates. maybe a linke to the aztecjs token bridge tutorial would be better?


The [registry](../../aztec-nr/framework-description/ethereum_aztec_messaging.md) provides governance-updateable addresses for core Aztec contracts. Rather than hardcoding rollup addresses, portals query the registry, allowing the protocol to upgrade without redeploying all portals.

Each cross-chain message includes a **content hash** — a `keccak256` digest of the function selector and its parameters that uniquely identifies the message. The content hash in each function uses `abi.encodeWithSignature` to include a function selector, making each message type unique and preventing a deposit message from being confused with a withdrawal message.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt it sha256, not keccak?

#include_code swap_private /docs/examples/contracts/example_uniswap/src/main.nr rust

:::note Why no recipient parameter?
In `swap_private`, the recipient is the transaction sender (implicit). This preserves privacy: revealing a recipient address to L1 would compromise the caller's identity. The output tokens are deposited privately on L2, where only the caller can claim them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In `swap_private`, the recipient is the transaction sender (implicit). This preserves privacy: revealing a recipient address to L1 would compromise the caller's identity. The output tokens are deposited privately on L2, where only the caller can claim them.
In `swap_private`, the recipient is the person that provide the secret used to generate the hash for the L1 to L2 message. This preserves privacy: revealing a recipient address to L1 would compromise the caller's identity. The output tokens are deposited privately to L2, where only the secret holder can claim them.

I think this is more accurate

BridgeA -->|"5. L2→L1 msg"| PortalA

UniL1 -->|"6. Consume msg 1"| PortalA
UniL1 -->|"7. Consume msg 2"| UniL1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this arrow point to the outbox? Its confusing that that the UniL1 box is pointing to itself


#include_code consume_l1_messages_execute /docs/examples/ts/example_swap/index.ts typescript

Finally, claim the output DAI on L2:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also start line 306 with Finally,


### Private Swap

The private swap is similar but uses `transfer_to_public` (private to public transfer) and [`enqueue_self`](../../aztec-nr/framework-description/calling_contracts.md) instead of `call_self`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a brief inline explanation of why enqueue_self instead of call_self would be helpful

Before starting this tutorial, you need:

1. **Aztec local network** running at version #include_aztec_version -- see [the local network guide](../../../getting_started_on_local_network.md) for setup instructions
2. **Foundry** installed for Solidity compilation -- see [Foundry installation](https://book.getfoundry.sh/getting-started/installation)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. **Foundry** installed for Solidity compilation -- see [Foundry installation](https://book.getfoundry.sh/getting-started/installation)

comes with aztec

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you accept this, you'll also have to renumber the following items


Each swap generates **two L2-to-L1 messages**, both of which must be consumed on L1 before the swap executes:

1. **Token bridge exit** - Authorizes releasing input tokens from the bridge to the uniswap portal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. **Token bridge exit** - Authorizes releasing input tokens from the bridge to the uniswap portal
1. **Token bridge exit** - Authorizes releasing input tokens from the token portal to the uniswap portal

Since its referred to as TokenPortal.sol in the contract name above


## Project Setup

This tutorial uses three types of contracts (Solidity, Noir, TypeScript) spread across a project. The code is shown inline via snippets -- you do not need to type it manually. However, understanding the project layout will help you follow along.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mention here that readers do not need to type this out manually. But at the end of Step 2 (Compile Solidity Contracts) has an instruction to run forge build. At that point, I was just following along, reading, so I don't have a project set up. It's not clear if I should be building a project as follow along or just reading. Since it's a tutorial, let's have readers build the project as they go, as much as possible, so we need to add some steps about how to set up the project (either clone a template repo, or specify what commands they should run to get the project set up)

@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from d29b0fd to d30723c Compare March 10, 2026 18:44
@AztecBot AztecBot force-pushed the ek/feat/uniswap-tutorial branch from 7acaa50 to ec3dbbe Compare March 10, 2026 18:58
@AztecBot AztecBot enabled auto-merge March 10, 2026 18:58
@sklppy88 sklppy88 requested a review from critesjosh March 10, 2026 18:58
@AztecBot AztecBot force-pushed the ek/feat/uniswap-tutorial branch from ec3dbbe to 8acd772 Compare March 10, 2026 19:00
@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from 8acd772 to 721d77d Compare March 10, 2026 19:21
@critesjosh critesjosh disabled auto-merge March 11, 2026 15:29
Copy link
Contributor

@critesjosh critesjosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disabled automerge and approving with some nits

Before starting this tutorial, you need:

1. **Aztec local network** running at version #include_aztec_version -- see [the local network guide](../../../getting_started_on_local_network.md) for setup instructions
2. **Node.js** (v18+) and a package manager (yarn or npm)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. **Node.js** (v18+) and a package manager (yarn or npm)
2. **Node.js** (v24+) and a package manager (yarn or npm)

I think we are recommending node 24 now? Its what we use in aztec-packages

The example code lives in the Aztec packages repository:

```bash
git clone --depth 1 --branch #include_aztec_version https://github.com/AztecProtocol/aztec-packages
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
git clone --depth 1 --branch #include_aztec_version https://github.com/AztecProtocol/aztec-packages
git clone --depth 1 --branch #include_aztec_version https://github.com/AztecProtocol/aztec-packages.git


```
examples/
├── solidity/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this actually comes after contracts/

UniL1["ExampleUniswapPortal<br/>(Solidity)"]
PortalA["ExampleTokenPortal A"]
PortalB["ExampleTokenPortal B"]
ERC20A["WETH (ERC20)"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one isnt used in the diagram flow. do we need it?

Image

User -->|"1. swap_public()"| UniL2
UniL2 -->|"2. Transfer WETH"| TokenA
UniL2 -->|"3. Exit to L1"| BridgeA
UniL2 -->|"4. L2→L1 msg"| UniL1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its kind of confusing that the numbers don't flow from one box to the next, they kind of hop around. adding a return arrow might help (e.g. for 2 and 3). Also 4 and 5 have the same message "L2->L1 msg" which is confusing

Image

@aztec/stdlib@#include_aztec_version \
@aztec/ethereum@#include_aztec_version \
@aztec/noir-contracts.js@#include_aztec_version \
@aztec/foundation@#include_aztec_version \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like viem also required? its in the config.yaml

console.log("=== PUBLIC SWAP FLOW ===\n");
console.log("Initiating public swap on L2 (WETH -> DAI)...\n");

// Force L2 block production so the authwit is included in a block before the swap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Force L2 block production so the authwit is included in a block before the swap
// Force L2 block production so the claim message is included in a block before the swap

this is for the claim message, not the authwit right?

adds uniswap tut and sample code
@sklppy88 sklppy88 force-pushed the ek/feat/uniswap-tutorial branch from 721d77d to 290671e Compare March 12, 2026 18:32
@sklppy88 sklppy88 added this pull request to the merge queue Mar 12, 2026
Merged via the queue into next with commit 6ab806f Mar 12, 2026
18 checks passed
@sklppy88 sklppy88 deleted the ek/feat/uniswap-tutorial branch March 12, 2026 19:37
sklppy88 added a commit that referenced this pull request Mar 13, 2026
## Summary

PR #21231 changed the `computeL2ToL1MembershipWitness` API signature
from `(node, epoch, message)` to `(node, message, txHash)`, but the
`example_swap` docs example (added in PR #20233) was written against the
old API. This caused the merge-train CI to fail with `TypeError: Cannot
read properties of undefined (reading 'siblingPath')` because the
function received wrong arguments and returned `undefined`.

## Changes

- Removed `RollupContract` import and usage (no longer needed to
manually compute epoch)
- Updated both `computeL2ToL1MembershipWitness` calls to use new
signature: `(node, message, txHash)`
- Get epoch numbers from the returned witness (`witness.epochNumber`)
instead of computing manually

ClaudeBox log: https://claudebox.work/s/5eb93c1235ed3384?run=2

Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants