Degen Code

Degen Code

Share this post

Degen Code
Degen Code
Aerodrome — V3 Pool Helper
Copy link
Facebook
Email
Notes
More

Aerodrome — V3 Pool Helper

Part III: A Familiar Structure

Sep 25, 2024
∙ Paid
1

Share this post

Degen Code
Degen Code
Aerodrome — V3 Pool Helper
Copy link
Facebook
Email
Notes
More
Share

Parts I and II of the Aerodrome series outlined the overall architecture of the DEX and an initial sketch of the V2 pool helper.

Aerodrome — Overview

Aerodrome — Overview

BowTiedDevil
·
September 1, 2024
Read full story
Aerodrome — V2 Pool Helper

Aerodrome — V2 Pool Helper

BowTiedDevil
·
September 14, 2024
Read full story

Today we’ll tackle the Aerodrome V3 pool helper, which is based on the Velodrome Slipstream Concentrated Liquidity contracts. Slipstream was originally forked from Uniswap V3, which I’ve covered in great detail here already.

Since the Uniswap V3 pool helper is already built, the effort here will be mostly focused on identifying the differences between Aerodrome V3 and the original, reusing the shared code, and allowing for differences wherever possible to avoid rework.

Deterministic Pool Address

The pool contracts for Aerodrome V3 are minimal proxy contracts aka “clones”, and built from the same OpenZeppelin Clones contract discussed in the previous post.

So we get to reuse that same CREATE2 address verification, with only a slight difference in the salt structure. Where V2’s salt was built from the token addresses and the stable boolean flag, V3’s salt is built from the token addresses and the tick spacing.

def generate_aerodrome_v3_pool_address(
    deployer_address: str | bytes,
    token_addresses: Sequence[str | bytes],
    implementation_address: str | bytes,
    tick_spacing: int,
) -> ChecksumAddress:
    """
    Get the deterministic V3 pool address generated by CREATE2. 
    Uses the token address to generate the salt. The token addresses 
    can be passed in any order.

    Adapted from https://github.com/aerodrome-finance/slipstream/blob/main/contracts/core/CLFactory.sol
    and https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Clones.sol
    """

    sorted_token_addresses = sorted(
        [
            HexBytes(address) for address in token_addresses
        ]
    )

    salt = keccak(
        eth_abi.abi.encode(
            ("address", "address", "int24"),
            [*sorted_token_addresses, tick_spacing],
        )
    )

    return eip_1167_clone_address(
        deployer=deployer_address,
        implementation_contract=implementation_address,
        salt=salt,
    )

slot0

The slot0 data struct is named because it is held at the first storage position (slot 0), and it holds several packed state values that are frequently updated during swaps. We care about the first two values, sqrtPriceX96 and tick, but there are others contained within the struct and which get returned when we call the public getter method slot0().

The first difference we find with Aerodrome V3 is that the slot0 struct is built differently. It is defined by CLPool.sol as:

struct Slot0 {
    uint160 sqrtPriceX96;
    int24 tick;
    uint16 observationIndex;
    uint16 observationCardinality;
    uint16 observationCardinalityNext;
    bool unlocked;
}

Whereas UniswapV3Pool.sol defines it:

struct Slot0 {
    uint160 sqrtPriceX96;
    int24 tick;
    uint16 observationIndex;
    uint16 observationCardinality;
    uint16 observationCardinalityNext;
    uint8 feeProtocol;
    bool unlocked;
}

Another well-known Uniswap fork, Pancakeswap, makes yet another similar-but-different modification to the struct by changing the feeProtocol from uint8 to uint32.

Aerodrome does not include the feeProtocol value at all. In any case, when we work with these forked pools, we have to be aware of and handle that difference.

We can handle it in two ways:

  1. Fetch it with a validated Contract object

  2. Make a direct call over JSON-RPC

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 BowTiedDevil
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More