# 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: ```json { "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. ```python "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. ```python # 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` |