Uniswap Protocol Adapter

The Uniswap adapter enables the Yieldinator Facet to integrate with Uniswap's liquidity pools (both V2 and V3), allowing vaults to earn trading fees and optimize yield through concentrated liquidity positions.

Overview

Uniswap is the largest decentralized exchange by volume, offering two distinct liquidity provision mechanisms:

  • Uniswap V2: Traditional automated market maker with 50/50 liquidity pools

  • Uniswap V3: Advanced concentrated liquidity that allows LPs to provide liquidity within specific price ranges

The Uniswap adapter facilitates deposits into both V2 and V3 pools, manages LP token balances for V2, handles NFT positions for V3, and optimizes yield by strategically setting price ranges for concentrated liquidity positions.

Implementation Details

Contract: UniswapAdapter.sol

The adapter implements the standard YieldinatorAdapter interface with Uniswap-specific functionality:

contract UniswapAdapter is YieldinatorAdapter {
    using SafeERC20 for IERC20;
    
    // Uniswap contracts
    IUniswapV2Router02 public v2Router;
    IUniswapV2Factory public v2Factory;
    INonfungiblePositionManager public positionManager;
    IUniswapV3Factory public v3Factory;
    
    // Pool version enum
    enum PoolVersion { V2, V3 }
    
    // Pool configuration
    struct PoolConfig {
        address pair;          // V2 pair address or V3 pool address
        address token0;        // First token in the pair
        address token1;        // Second token in the pair
        uint24 fee;            // Fee tier for V3 (0 for V2)
        PoolVersion version;   // V2 or V3
        int24 tickLower;       // Lower tick for V3 position (0 for V2)
        int24 tickUpper;       // Upper tick for V3 position (0 for V2)
        bool active;           // Whether the pool is active
    }
    
    // Position tracking for V3
    struct Position {
        uint256 tokenId;       // NFT token ID for the position
        uint128 liquidity;     // Current liquidity amount
        int24 tickLower;       // Position's lower tick
        int24 tickUpper;       // Position's upper tick
    }
    
    // Mapping from token to pool configuration
    mapping(address => PoolConfig) public tokenToPool;
    
    // Mapping from token to V3 positions
    mapping(address => Position[]) public tokenToPositions;
    
    // Deposited amounts per token
    mapping(address => uint256) public depositedAmount;
    
    // Constructor
    constructor(
        address _admin,
        address _v2Router,
        address _v2Factory,
        address _positionManager,
        address _v3Factory
    ) YieldinatorAdapter("Uniswap", _admin) {
        require(_v2Router != address(0), "UniswapAdapter: v2Router cannot be zero address");
        require(_v2Factory != address(0), "UniswapAdapter: v2Factory cannot be zero address");
        require(_positionManager != address(0), "UniswapAdapter: positionManager cannot be zero address");
        require(_v3Factory != address(0), "UniswapAdapter: v3Factory cannot be zero address");
        
        v2Router = IUniswapV2Router02(_v2Router);
        v2Factory = IUniswapV2Factory(_v2Factory);
        positionManager = INonfungiblePositionManager(_positionManager);
        v3Factory = IUniswapV3Factory(_v3Factory);
    }
}

Key Functions

Pool Registration

Before using the adapter for a specific token, the pool must be registered:

Deposit

The deposit function handles adding liquidity to Uniswap V2 or V3 based on the pool configuration:

Withdraw

The withdraw function handles removing liquidity from Uniswap V2 or V3 based on the pool configuration:

Harvest Yield

The harvestYield function collects fees from V2 and V3 positions:

Emergency Withdraw

The emergencyWithdraw function provides a way to recover funds in case of emergencies:

Usage Examples

Registering a Uniswap V2 Pool

Registering a Uniswap V3 Pool with Concentrated Liquidity

Depositing into Uniswap

Withdrawing from Uniswap

Harvesting Yield

Security Considerations

Price Impact and Slippage

When depositing or withdrawing, the adapter uses a default slippage tolerance of 5%. This can be adjusted by the protocol administrator based on market conditions.

Concentrated Liquidity Risks

For V3 positions, there's a risk of providing liquidity outside the active trading range, resulting in impermanent loss without earning fees. The adapter mitigates this by:

  1. Allowing administrators to set appropriate tick ranges

  2. Supporting multiple positions with different ranges for the same token

  3. Providing functions to adjust tick ranges as market conditions change

Position Management

V3 positions are represented as NFTs, which the adapter manages internally. The contract includes safeguards to ensure these NFTs cannot be transferred out of the adapter except through the proper withdrawal process.

Oracle Manipulation

The adapter relies on Uniswap's time-weighted average price (TWAP) oracles for certain calculations. To mitigate manipulation risks, the adapter:

  1. Uses multiple oracle observations

  2. Implements circuit breakers for extreme price movements

  3. Allows administrators to pause specific pools during market turbulence

Conclusion

The Uniswap adapter provides comprehensive integration with both Uniswap V2 and V3, allowing the Yieldinator Facet to optimize yield through trading fees and concentrated liquidity strategies. The adapter's flexible design accommodates different risk profiles and market conditions, making it a powerful addition to the Vaultinator Protocol's yield generation capabilities.