Files
uniswap_auto_clp/florida/doc/AERODROME_CL_INTEGRATION.md

4.8 KiB

Aerodrome Slipstream (CLP) Integration Guide

This document details the specific technical requirements for integrating Aerodrome Slipstream (Concentrated Liquidity) pools into a Uniswap V3-compatible bot. Aerodrome Slipstream is a fork of Uniswap V3 (via Velodrome V2) but introduces critical ABI and logic changes that cause standard implementations to fail.

1. Key Differences from Uniswap V3

Feature Standard Uniswap V3 Aerodrome Slipstream
Factory Pool Lookup getPool(tokenA, tokenB, fee) getPool(tokenA, tokenB, tickSpacing)
NPM Mint Parameter uint24 fee int24 tickSpacing
NPM Mint Struct MintParams { ..., deadline } MintParams { ..., deadline, sqrtPriceX96 }
Pool Identification Fee Tier (e.g., 500, 3000) Tick Spacing (e.g., 1, 100)

2. ABI Modifications

To interact with the Aerodrome NonfungiblePositionManager (NPM), you must use a modified ABI. The standard Uniswap V3 NPM ABI will result in revert errors during encoding.

MintParams Struct

The MintParams struct in the mint function input must be defined as follows:

{
  "components": [
    {"internalType": "address", "name": "token0", "type": "address"},
    {"internalType": "address", "name": "token1", "type": "address"},
    {"internalType": "int24", "name": "tickSpacing", "type": "int24"}, // CHANGED from uint24 fee
    {"internalType": "int24", "name": "tickLower", "type": "int24"},
    {"internalType": "int24", "name": "tickUpper", "type": "int24"},
    {"internalType": "uint256", "name": "amount0Desired", "type": "uint256"},
    {"internalType": "uint256", "name": "amount1Desired", "type": "uint256"},
    {"internalType": "uint256", "name": "amount0Min", "type": "uint256"},
    {"internalType": "uint256", "name": "amount1Min", "type": "uint256"},
    {"internalType": "address", "name": "recipient", "type": "address"},
    {"internalType": "uint256", "name": "deadline", "type": "uint256"},
    {"internalType": "uint160", "name": "sqrtPriceX96", "type": "uint160"} // ADDED
  ],
  "internalType": "struct INonfungiblePositionManager.MintParams",
  "name": "params",
  "type": "tuple"
}

3. Python Implementation Strategy

A. Configuration

When defining the pool configuration, use the Tick Spacing value (e.g., 100) where you would normally put the Fee.

"AERODROME_BASE_CL": {
    "NAME": "Aerodrome SlipStream (Base) - WETH/USDC",
    "NPM_ADDRESS": "0x827922686190790b37229fd06084350E74485b72", # Aerodrome NPM
    "POOL_FEE": 100, # Actual TickSpacing (e.g., 100 for volatile, 1 for stable)
    ...
}

B. Logic Changes (clp_manager.py)

  1. ABI Selection: Dynamically switch between Standard and Aerodrome ABIs based on the target DEX.
  2. Parameter Construction: When calling mint, check if the target is Aerodrome. If so, append 0 (for sqrtPriceX96) to the arguments tuple.
# Pseudo-code for Mint Call
base_params = [
    token0, token1, 
    tick_spacing, # Passed as int24
    tick_lower, tick_upper, 
    amount0, amount1, 
    amount0_min, amount1_min, 
    recipient, 
    deadline
]

if is_aerodrome:
    base_params.append(0) # sqrtPriceX96 must be present and 0 for existing pools

npm_contract.functions.mint(tuple(base_params)).transact(...)

C. Swap Router

Aerodrome Slipstream's SwapRouter (0xbe6D...) uses the SwapRouter01 ABI style (includes deadline in ExactInputSingleParams), whereas standard Uniswap V3 on Base often uses SwapRouter02 (no deadline).

  • Tip: For simplicity, you can use the Standard Uniswap V3 Router (0x2626...) on Base to swap tokens (WETH/USDC) even if you are providing liquidity on Aerodrome, provided the tokens are standard. This avoids ABI headaches with the Aerodrome Router if you only need simple swaps.

4. Troubleshooting Common Errors

  • ('execution reverted', 'no data'):
    • Cause 1: Passing fee (uint24) instead of tickSpacing (int24).
    • Cause 2: Missing sqrtPriceX96 parameter in the struct.
    • Cause 3: Tick range (tickLower, tickUpper) not aligned to the pool's tickSpacing (e.g., must be multiples of 100).
  • BadFunctionCallOutput / InsufficientDataBytes:
    • Cause: Using the wrong Contract Address for the chain (e.g., using Mainnet NPM address on Base).
    • Cause: Calling factory() on a contract that doesn't have it (wrong ABI or Proxy).

5. Addresses (Base)

Contract Address
Aerodrome NPM 0x827922686190790b37229fd06084350E74485b72
Aerodrome Factory 0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A
Uniswap V3 NPM 0xC36442b4a4522E871399CD717aBDD847Ab11FE88
WETH 0x4200000000000000000000000000000000000006
USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913