# Table of Contents - [Fluid DEX V2: Liquidity Source Integration | Fluid Technical Docs](#fluid-dex-v2-liquidity-source-integration-fluid-technical-docs) - [Understanding Fluid: Key Concepts and Practices | Fluid Technical Docs](#understanding-fluid-key-concepts-and-practices-fluid-technical-docs) - [Get all user vault positions | Fluid Technical Docs](#get-all-user-vault-positions-fluid-technical-docs) - [Fluid Liquidation swaps | Fluid Technical Docs](#fluid-liquidation-swaps-fluid-technical-docs) - [Fluid Dex: Liquidity source integration | Fluid Technical Docs](#fluid-dex-liquidity-source-integration-fluid-technical-docs) - [Decode LogOperate Event | Fluid Technical Docs](#decode-logoperate-event-fluid-technical-docs) - [Get lend, borrow, yield rates | Fluid Technical Docs](#get-lend-borrow-yield-rates-fluid-technical-docs) - [Errors structure | Fluid Technical Docs](#errors-structure-fluid-technical-docs) - [Fluid DEX Lite: Liquidity Source Integration | Fluid Technical Docs](#fluid-dex-lite-liquidity-source-integration-fluid-technical-docs) --- # Fluid DEX V2: Liquidity Source Integration | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#VPContent) Return to top Fluid DEX V2: Liquidity Source Integration [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#fluid-dex-v2-liquidity-source-integration) ====================================================================================================================================================== Complete integration guide for adding Fluid DEX V2 as a liquidity source in DEX aggregators and routing protocols. Table of Contents [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#table-of-contents) ----------------------------------------------------------------------------------------------------- 1. [Overview](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#overview) 2. [Quick Start](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#quick-start) 3. [Data Access with Resolver](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#data-access-with-resolver) 4. [Pool Discovery & State Reading](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#pool-discovery--state-reading) 5. [Router-based Integration](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#router-based-integration) 6. [Callback-based Integration (Advanced)](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#callback-based-integration-advanced) 7. [Operating DEX Modules](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#operating-dex-modules) 8. [Token Settlement with settle()](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#token-settlement-with-settle) 9. [Best Practices](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#best-practices) 10. [Resources](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#resources) * * * Overview [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#overview) ----------------------------------------------------------------------------------- ### What is Fluid DEX v2? [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#what-is-fluid-dex-v2) Fluid DEX v2 is an advanced decentralized exchange built on top of the Fluid Liquidity Layer, featuring: * **Single Contract, Multiple DEX Types**: One contract handles different types of AMMs (Automated Market Makers) * **Smart Collateral & Debt**: Revolutionary financial primitives for enhanced capital efficiency * **Dynamic Fees**: On-chain adaptive fee mechanisms and custom hooks * **Flash Accounting**: Ultra-efficient settlement for complex multi-step operations ### Supported DEX Types [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#supported-dex-types) Currently, DEX v2 supports 4 major DEX types: 1. **DEX Type 1 (D1)**: DEX v1 Smart Collateral _(Coming Soon)_ 2. **DEX Type 2 (D2)**: DEX v1 Smart Debt _(Coming Soon)_ 3. **DEX Type 3 (D3)**: Smart Collateral Range Orders 4. **DEX Type 4 (D4)**: Smart Debt Range Orders **This guide focuses on D3 and D4 integration** as they are currently available for use. ### Architecture [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#architecture) * **Core Contract**: `FluidDexV2` - Singleton contract handling all DEX operations * **Resolver Contract**: `FluidDexV2Resolver` - Provides pool discovery, state reading, position analysis, and liquidity distribution queries * **Router Contract**: `FluidDexV2Router` - Simplified integration with easy-to-use functions * **Callback Pattern**: Gas-efficient but advanced integration requiring custom callback implementation * * * Quick Start [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#quick-start) ----------------------------------------------------------------------------------------- This guide covers both integration methods. Choose the router for simplicity or callbacks for maximum control and gas efficiency. ### 1\. Integration Methods [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_1-integration-methods) **Method 1: Router-based Integration** * **What it is**: Use the `FluidDexV2Router` contract with simple function calls * **Best for**: Most integrators who want straightforward swap functionality * **Pros**: Easy integration, no callback implementation needed, supports both single and multi-hop swaps, native ETH support * **Cons**: Slightly higher gas costs due to additional contract layer **Method 2: Callback-based Integration (Advanced)** * **What it is**: You implement callback functions that the DEX calls during operations * **Best for**: Advanced integrators who want maximum control and gas efficiency * **Pros**: Maximum gas efficiency, full control over token transfers, can batch multiple operations * **Cons**: Complex implementation, requires understanding callback mechanism and security ### 2\. Data Access [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_2-data-access) **Resolver Contract: `FluidDexV2Resolver`** * Pool state reading and analysis * Position data queries * Liquidity distribution analysis * Used by both integration methods for data access ### 3\. Core Data Structures [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_3-core-data-structures) **Essential structures for DEX v2 integration:** solidity // Pool identification - every pool is uniquely identified by this structure struct DexKey { address token0; // Always the smaller token address (lexicographically) address token1; // Always the larger token address (lexicographically) uint24 fee; // Fee tier (e.g., 500 = 0.05%) or 0xFFFFFF for dynamic fees uint24 tickSpacing; // Price granularity (1 = finest, higher = coarser) address controller; // Optional controller contract (use address(0) if none) } // Parameters for exact input swaps (specify input amount, get variable output) struct SwapInParams { DexKey dexKey; // Pool to swap in bool swap0To1; // Direction: true = token0 -> token1, false = token1 -> token0 uint256 amountIn; // Exact amount of input tokens uint256 amountOutMin; // Minimum acceptable output amount (slippage protection) bytes controllerData; // Optional data for controller contract } // Parameters for exact output swaps (specify output amount, pay variable input) struct SwapOutParams { DexKey dexKey; // Pool to swap in bool swap0To1; // Direction: true = token0 -> token1, false = token1 -> token0 uint256 amountOut; // Exact amount of output tokens desired uint256 amountInMax; // Maximum acceptable input amount (slippage protection) bytes controllerData; // Optional data for controller contract } ### 4\. Contract Addresses [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_4-contract-addresses) | Network | Contract | Address | | --- | --- | --- | | Ethereum | FluidDexV2 | `TBD` | | Ethereum | FluidDexV2Resolver | `TBD` | | Ethereum | FluidDexV2Router | `TBD` | | Polygon | FluidDexV2 | `0x7822B3944B1a68B231a6e7F55B57967F28BB369e` | | Polygon | FluidDexV2Resolver | `0x1E45589D501AcED82013c2838552122f943B33Ac` | | Polygon | FluidDexV2Router | `0x713fD04a47Db41AB5684AEC2A2063d5278A53616` | * * * Data Access with Resolver [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#data-access-with-resolver) --------------------------------------------------------------------------------------------------------------------- ### Using the Resolver Contract [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#using-the-resolver-contract) Use the `FluidDexV2Resolver` contract for all pool discovery, state reading, position analysis, and liquidity distribution queries. #### Resolver Data Structures [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#resolver-data-structures) solidity // Pool configuration with metadata struct DexConfig { uint256 dexType; // 3 for D3, 4 for D4 DexKey dexKey; // Pool identification bytes32 dexId; // Computed pool ID bytes32 dexAssetId; // Asset ID for money market integration } // Combined pool configuration and state struct DexPoolInfo { DexConfig dexConfig; DexPoolState dexPoolState; } // Pool state variables (packed and unpacked versions) struct DexVariables { int256 currentTick; uint256 currentSqrtPriceX96; uint256 feeGrowthGlobal0X102; uint256 feeGrowthGlobal1X102; } struct DexVariables2 { uint256 protocolFee0To1; uint256 protocolFee1To0; uint256 protocolCutFee; uint256 token0Decimals; uint256 token1Decimals; uint256 activeLiquidity; bool poolAccountingFlag; // Per pool accounting flag bool fetchDynamicFeeFlag; uint256 feeVersion; // 0 = static fee, 1 = dynamic fee uint256 lpFee; uint256 maxDecayTime; uint256 priceImpactToFeeDivisionFactor; uint256 minFee; uint256 maxFee; int256 netPriceImpact; uint256 lastUpdateTimestamp; uint256 decayTimeRemaining; } // Raw pool state data struct DexPoolStateRaw { uint256 dexVariablesPacked; uint256 dexVariables2Packed; DexVariables dexVariablesUnpacked; DexVariables2 dexVariables2Unpacked; } // Complete pool state (returned by resolver) struct DexPoolState { bytes32 dexId; uint256 dexPriceParsed; DexPoolStateRaw dexPoolStateRaw; } // Position-related structures struct PositionData { uint256 liquidity; uint256 feeGrowthInside0X102; uint256 feeGrowthInside1X102; } struct PositionInfo { PositionData positionData; uint256 amount0; uint256 amount1; uint256 feeAccruedToken0; uint256 feeAccruedToken1; } // Liquidity distribution analysis struct TickLiquidity { int24 tick; uint256 liquidity; } #### Key Methods [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#key-methods) solidity contract FluidDexV2Resolver { // Pool Discovery & Identification function getDexId(DexKey memory dexKey) public pure returns (bytes32 dexId); function getDexKey(uint256 dexType, bytes32 dexId) public view returns (DexKey memory dexKey); // Permissioned Pool Discovery (Money Market Listed Pools) function getD3PermissionedDexes() public view returns (DexKey[] memory dexKeys); function getD4PermissionedDexes() public view returns (DexKey[] memory dexKeys); function getAllPermissionedDexes() public view returns (DexConfig[] memory dexConfigs); function getAllPermissionedDexesPoolState() public view returns (DexPoolInfo[] memory dexPoolInfos); // Pool State Reading function getDexPoolState(uint256 dexType, DexKey memory dexKey) public view returns (DexPoolState memory); // Position Information function getPositionData( uint256 dexType, DexKey memory dexKey, address user, int24 tickLower, int24 tickUpper, bytes32 positionSalt ) public view returns (PositionData memory); function getPositionInfo( uint256 dexType, DexKey memory dexKey, address user, int24 tickLower, int24 tickUpper, bytes32 positionSalt ) public view returns (PositionInfo memory); // Liquidity Analysis function getLiquidityAmounts( uint256 dexType, DexKey memory dexKey, int24 startTick, int24 endTick, uint256 startLiquidity ) public view returns (TickLiquidity[] memory); } #### Basic Usage Example [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#basic-usage-example) solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.29; contract FluidDexV2Integrator { FluidDexV2Resolver constant resolver = FluidDexV2Resolver( 0x1E45589D501AcED82013c2838552122f943B33Ac // Polygon resolver address ); IFluidDexV2 constant dexV2 = IFluidDexV2( 0x7822B3944B1a68B231a6e7F55B57967F28BB369e // Polygon DEX v2 address ); uint256 constant D3_DEX_TYPE = 3; // Smart Collateral Range Orders uint256 constant D4_DEX_TYPE = 4; // Smart Debt Range Orders // Get all available pools from Money Market function getAllAvailablePools() external view returns (DexPoolInfo[] memory) { return resolver.getAllPermissionedDexesPoolState(); } // Get specific pool state function getPoolState(DexKey memory dexKey, uint256 dexType) external view returns ( bytes32 dexId, int256 currentTick, uint256 currentPrice, uint256 activeLiquidity, uint256 fee ) { DexPoolState memory state = resolver.getDexPoolState(dexType, dexKey); dexId = state.dexId; currentTick = state.dexPoolStateRaw.dexVariablesUnpacked.currentTick; currentPrice = state.dexPoolStateRaw.dexVariablesUnpacked.currentSqrtPriceX96; activeLiquidity = state.dexPoolStateRaw.dexVariables2Unpacked.activeLiquidity; fee = state.dexPoolStateRaw.dexVariables2Unpacked.lpFee; } // Reverse lookup: get DexKey from dexId function getDexKeyFromId(uint256 dexType, bytes32 dexId) external view returns (DexKey memory) { return resolver.getDexKey(dexType, dexId); } } * * * Pool Discovery & State Reading [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#pool-discovery-state-reading) ----------------------------------------------------------------------------------------------------------------------------- ### Discovering Available Pools [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#discovering-available-pools) DEX v2 pools can be discovered through multiple methods depending on the current system state: #### 1\. Permissioned Pools (Currently Available) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_1-permissioned-pools-currently-available) **Money Market Listed Pools**: Currently, DEX v2 operates with pools that are **permissioned and listed on the Fluid Money Market**. These pools have been approved through governance and are integrated with the lending protocol for enhanced capital efficiency. **Key Functions for Pool Discovery:** solidity // Get all D3 (Smart Collateral) pools from Money Market DexKey[] memory d3Pools = resolver.getD3PermissionedDexes(); // Get all D4 (Smart Debt) pools from Money Market DexKey[] memory d4Pools = resolver.getD4PermissionedDexes(); // Get all pools with complete metadata and current state DexPoolInfo[] memory allPools = resolver.getAllPermissionedDexesPoolState(); // Get pool configurations with dexType, dexKey, dexId, and dexAssetId DexConfig[] memory allConfigs = resolver.getAllPermissionedDexes(); **Important Notes:** * These functions return **only pools currently listed on the Money Market** * Each pool has been approved through Fluid governance * Pools are integrated with lending protocols for Smart Collateral/Debt functionality * Use `getAllPermissionedDexesPoolState()` for the most comprehensive pool information in a single call #### 2\. Future Permissionless Pools [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_2-future-permissionless-pools) **Event Monitoring**: When DEX v2 transitions to permissionless operation, pools that are **not listed on the Money Market** will need to be discovered via initialization events: solidity // Listen for this event to discover new permissionless pools event LogInitialize( uint256 indexed dexType, bytes32 indexed dexId, DexKey dexKey, uint256 sqrtPriceX96 ); #### 3\. Pool Identification & Reverse Lookup [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_3-pool-identification-reverse-lookup) **DexKey ↔ DexId Conversion**: The resolver provides bidirectional conversion between DexKey and DexId: solidity // Convert DexKey to DexId (pure function - no storage read) bytes32 dexId = resolver.getDexId(dexKey); // Reverse lookup: Convert DexId back to DexKey (reads from storage) DexKey memory dexKey = resolver.getDexKey(dexType, dexId); **Pool Existence Verification:** solidity function checkPoolExists(DexKey memory dexKey, uint256 dexType) external view returns (bool exists) { DexPoolState memory state = resolver.getDexPoolState(dexType, dexKey); // Pool exists if it has been initialized (non-zero sqrt price) exists = state.dexPoolStateRaw.dexVariablesUnpacked.currentSqrtPriceX96 > 0; } ### Reading Pool State [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#reading-pool-state) solidity function readPoolDetails(DexKey memory dexKey, uint256 dexType) external view returns ( int256 currentTick, uint256 sqrtPriceX96, uint256 activeLiquidity, uint256 fee, uint256 token0Decimals, uint256 token1Decimals, bool isDynamicFee ) { DexPoolState memory state = resolver.getDexPoolState(dexType, dexKey); currentTick = state.dexPoolStateRaw.dexVariablesUnpacked.currentTick; sqrtPriceX96 = state.dexPoolStateRaw.dexVariablesUnpacked.currentSqrtPriceX96; activeLiquidity = state.dexPoolStateRaw.dexVariables2Unpacked.activeLiquidity; fee = state.dexPoolStateRaw.dexVariables2Unpacked.lpFee; token0Decimals = state.dexPoolStateRaw.dexVariables2Unpacked.token0Decimals; token1Decimals = state.dexPoolStateRaw.dexVariables2Unpacked.token1Decimals; isDynamicFee = state.dexPoolStateRaw.dexVariables2Unpacked.feeVersion == 1; } ### Analyzing Liquidity Distribution [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#analyzing-liquidity-distribution) solidity function analyzeLiquidity( DexKey memory dexKey, uint256 dexType, int24 tick ) external view returns (TickLiquidity[] memory liquidityDistribution) { DexPoolState memory state = resolver.getDexPoolState(dexType, dexKey); int24 currentTick = state.dexPoolStateRaw.dexVariablesUnpacked.currentTick; uint256 currentLiquidity = state.dexPoolStateRaw.dexVariables2Unpacked.activeLiquidity; liquidityDistribution = resolver.getLiquidityAmounts( dexType, dexKey, currentTick, tick, currentLiquidity ); } * * * Router-based Integration [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#router-based-integration) ------------------------------------------------------------------------------------------------------------------- ### Overview [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#overview-1) The `FluidDexV2Router` provides a simple, user-friendly interface for DEX v2 swaps. It handles all the complex callback logic internally, making integration straightforward while supporting both single-hop and multi-hop swaps across D3 and D4 pools. ### Key Features [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#key-features) * **Simple API**: Just call functions directly, no callback implementation needed * **Native Token Support**: Uses `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` to represent the native token * **Multi-hop Routing**: Support for complex swap paths across multiple pools * **Mixed DEX Types**: Can route through both D3 and D4 pools in a single transaction * **Slippage Protection**: Built-in minimum/maximum amount validation * **Gas Refunds**: Automatically refunds excess ETH sent with transactions ### Router Interface [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#router-interface) solidity interface IFluidDexV2Router { // Single-hop exact input swap function swapIn( uint256 dexType_, // 3 for D3, 4 for D4 SwapInParams calldata swapInParams_, // Swap parameters address to_ // Token recipient ) external payable returns (uint256 amountOut_); // Single-hop exact output swap function swapOut( uint256 dexType_, // 3 for D3, 4 for D4 SwapOutParams calldata swapOutParams_, // Swap parameters address to_ // Token recipient ) external payable returns (uint256 amountIn_); // Multi-hop exact input swap function swapInMulti( address[] calldata path_, // Token path [tokenA, tokenB, tokenC] SwapInConfig[] calldata swapInConfigs_, // Config for each hop uint256 amountIn_, // Input amount address to_ // Token recipient ) external payable returns (uint256 amountOut_); // Multi-hop exact output swap function swapOutMulti( address[] calldata path_, // Token path [tokenA, tokenB, tokenC] SwapOutConfig[] calldata swapOutConfigs_, // Config for each hop uint256 amountOut_, // Desired output amount address to_ // Token recipient ) external payable returns (uint256 amountIn_); } // Multi-hop configuration structs struct SwapInConfig { uint256 dexType; // 3 for D3, 4 for D4 DexKey dexKey; // Pool identification uint256 amountOutMin; // Minimum output for this hop bytes controllerData; // Optional controller data } struct SwapOutConfig { uint256 dexType; // 3 for D3, 4 for D4 DexKey dexKey; // Pool identification uint256 amountInMax; // Maximum input for this hop bytes controllerData; // Optional controller data } ### Router Usage Examples [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#router-usage-examples) #### 1\. Single-hop Exact Input Swap (swapIn) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_1-single-hop-exact-input-swap-swapin) Swap an exact amount of input tokens for a minimum amount of output tokens: solidity import "contracts/periphery/dexV2/router/main.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract MyDEXAggregator { FluidDexV2Router constant router = FluidDexV2Router(0x713fD04a47Db41AB5684AEC2A2063d5278A53616); // Polygon router address function swapUSDCForUSDT( uint256 amountIn, uint256 minAmountOut, address recipient ) external returns (uint256 amountOut) { // Define the pool DexKey memory dexKey = DexKey({ token0: 0xA0b86a33E6441E4C7449e6C4c6E9E6C4c6E9E6C4, // USDC (smaller address) token1: 0xdAC17F958D2ee523a2206206994597C13D831ec7, // USDT (larger address) fee: 500, // 0.05% fee tickSpacing: 10, // Tick spacing controller: address(0) // No controller }); // Setup swap parameters SwapInParams memory swapParams = SwapInParams({ dexKey: dexKey, swap0To1: true, // USDC -> USDT (token0 -> token1) amountIn: amountIn, amountOutMin: minAmountOut, controllerData: "" }); // Approve router to spend USDC IERC20(dexKey.token0).approve(address(router), amountIn); // Execute swap amountOut = router.swapIn( 3, // D3 DEX type swapParams, recipient ); } } #### 2\. Single-hop Exact Output Swap (swapOut) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_2-single-hop-exact-output-swap-swapout) Swap a maximum amount of input tokens for an exact amount of output tokens: solidity function swapETHForExactUSDC( uint256 exactAmountOut, address recipient ) external payable returns (uint256 amountIn) { DexKey memory dexKey = DexKey({ token0: 0xA0b86a33E6441E4C7449e6C4c6E9E6C4c6E9E6C4, // USDC token1: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, // ETH (native token) fee: 3000, // 0.3% fee tickSpacing: 60, controller: address(0) }); SwapOutParams memory swapParams = SwapOutParams({ dexKey: dexKey, swap0To1: false, // ETH -> USDC (token1 -> token0) amountOut: exactAmountOut, amountInMax: msg.value, // Maximum ETH to spend controllerData: "" }); // Execute swap - ETH is sent via msg.value amountIn = router.swapOut{value: msg.value}( 3, // D3 DEX type swapParams, recipient ); // Excess ETH is automatically refunded } #### 3\. Multi-hop Exact Input Swap (swapInMulti) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_3-multi-hop-exact-input-swap-swapinmulti) Swap through multiple pools: ETH → USDC → USDT solidity function swapETHToUSDTViaUSDC( uint256 amountIn, uint256 minAmountOut, address recipient ) external payable returns (uint256 amountOut) { // Define the swap path: ETH -> USDC -> USDT address[] memory path = new address[](3); path[0] = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH path[1] = 0xA0b86a33E6441E4C7449e6C4c6E9E6C4c6E9E6C4; // USDC path[2] = 0xdAC17F958D2ee523a2206206994597C13D831ec7; // USDT // Configure each hop SwapInConfig[] memory configs = new SwapInConfig[](2); // Hop 1: ETH -> USDC (D3 pool) configs[0] = SwapInConfig({ dexType: 3, dexKey: DexKey({ token0: path[1], // USDC (smaller address) token1: path[0], // ETH (larger address) fee: 3000, tickSpacing: 60, controller: address(0) }), amountOutMin: 0, // No intermediate slippage check controllerData: "" }); // Hop 2: USDC -> USDT (D4 pool) configs[1] = SwapInConfig({ dexType: 4, dexKey: DexKey({ token0: path[1], // USDC (smaller address) token1: path[2], // USDT (larger address) fee: 100, tickSpacing: 1, controller: address(0) }), amountOutMin: minAmountOut, // Final slippage protection controllerData: "" }); // Execute multi-hop swap amountOut = router.swapInMulti{value: msg.value}( path, configs, amountIn, recipient ); } #### 4\. Multi-hop Exact Output Swap (swapOutMulti) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#_4-multi-hop-exact-output-swap-swapoutmulti) Get exact USDT output by swapping through ETH → USDC → USDT: solidity function getExactUSDTViaMultiHop( uint256 exactAmountOut, address recipient ) external payable returns (uint256 amountIn) { // Path: ETH -> USDC -> USDT (same as input example) address[] memory path = new address[](3); path[0] = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH path[1] = 0xA0b86a33E6441E4C7449e6C4c6E9E6C4c6E9E6C4; // USDC path[2] = 0xdAC17F958D2ee523a2206206994597C13D831ec7; // USDT SwapOutConfig[] memory configs = new SwapOutConfig[](2); // Hop 1: ETH -> USDC configs[0] = SwapOutConfig({ dexType: 3, dexKey: DexKey({ token0: path[1], // USDC token1: path[0], // ETH fee: 3000, tickSpacing: 60, controller: address(0) }), amountInMax: msg.value, // Max ETH to spend controllerData: "" }); // Hop 2: USDC -> USDT configs[1] = SwapOutConfig({ dexType: 4, dexKey: DexKey({ token0: path[1], // USDC token1: path[2], // USDT fee: 100, tickSpacing: 1, controller: address(0) }), amountInMax: type(uint256).max, // No intermediate limit controllerData: "" }); // Execute exact output multi-hop swap amountIn = router.swapOutMulti{value: msg.value}( path, configs, exactAmountOut, recipient ); } * * * Callback-based Integration (Advanced) [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#callback-based-integration-advanced) ------------------------------------------------------------------------------------------------------------------------------------------- > **💡 New to DEX v2?** Consider starting with the [Router-based Integration](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#router-based-integration) > above for a simpler approach. This section covers the advanced callback method for maximum control and gas efficiency. ### The Callback Architecture [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#the-callback-architecture) **Why Callbacks?** DEX v2 uses callbacks to give you maximum flexibility. You can perform multiple operations, complex routing, or custom logic all in one transaction. **The Flow:** Your Contract → startOperation() → DEX calls your callback → Your Logic → Settlement → Complete **Step by Step:** 1. **You initiate**: Call `dexV2.startOperation(encodedData)` with your operation data 2. **DEX calls back**: DEX immediately calls `startOperationCallback(encodedData)` on your contract 3. **You execute**: Inside the callback, perform swaps using `operate()` and handle tokens using `settle()` 4. **DEX verifies**: DEX checks that all token transfers balance out correctly 5. **Transaction completes**: If everything balances, the transaction succeeds **Key Benefits:** * **Atomic operations**: Multiple swaps and operations in one transaction * **Gas efficiency**: No intermediate token transfers between operations * **Flexibility**: Implement any trading strategy or routing logic you want ### Core Interfaces [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#core-interfaces) solidity interface IFluidDexV2 { // Initiates any operation - calls back to your contract function startOperation(bytes calldata data) external returns (bytes memory result); // Executes specific DEX operations (swap, deposit, etc.) function operate( uint256 dexType, // 3 for D3, 4 for D4 uint256 implementationId, // 1 for swap, 2 for user ops bytes memory data ) external returns (bytes memory returnData); // Handles token transfers and settlement function settle( address token, int256 supplyAmount, // Positive = supply to DEX int256 borrowAmount, // Positive = borrow from DEX int256 storeAmount, // Positive = store in DEX address to, // Recipient address bool isCallback // true = DEX calls dexCallback for transfer, false = approval based transfers ) external payable; } // Your contract must implement this interface IDexV2Callbacks { function startOperationCallback(bytes calldata data) external returns (bytes memory); function dexCallback(address token, address to, uint256 amount) external; } // Swap function interfaces (for encoding with operate()) interface IDexV2SwapModule { function swapIn(SwapInParams calldata params) external returns (uint256 amountOut, uint256 protocolFee, uint256 lpFee); function swapOut(SwapOutParams calldata params) external returns (uint256 amountIn, uint256 protocolFee, uint256 lpFee); } ### Basic Swap Example [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#basic-swap-example) Here's a complete example showing how to implement a simple swap: solidity import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract FluidDexV2Integrator is IDexV2Callbacks { using SafeERC20 for IERC20; IFluidDexV2 public immutable dexV2; constructor(address _dexV2) { dexV2 = IFluidDexV2(_dexV2); } // Public function users call to swap function swapTokens( DexKey memory dexKey, uint256 dexType, // 3 for D3, 4 for D4 bool swap0To1, uint256 amountIn, uint256 minAmountOut, address recipient ) external returns (uint256 amountOut) { // Encode parameters for callback bytes memory callbackData = abi.encode( dexKey, dexType, swap0To1, amountIn, minAmountOut, recipient ); // Start the operation - DEX will call startOperationCallback bytes memory result = dexV2.startOperation(callbackData); // Decode the result (amountOut,,) = abi.decode(result, (uint256, uint256, uint256)); } // DEX calls this function function startOperationCallback(bytes calldata data) external returns (bytes memory) { require(msg.sender == address(dexV2), "Unauthorized"); // Decode parameters from callback data ( DexKey memory dexKey, uint256 dexType, bool swap0To1, uint256 amountIn, uint256 minAmountOut, address recipient ) = abi.decode(data, (DexKey, uint256, bool, uint256, uint256, address)); // 1. Execute the swap via operate() SwapInParams memory swapParams = SwapInParams({ dexKey: dexKey, swap0To1: swap0To1, amountIn: amountIn, amountOutMin: minAmountOut, controllerData: "" }); bytes memory swapData = abi.encodeWithSelector( bytes4(keccak256("swapIn(SwapInParams)")), swapParams ); bytes memory swapResult = dexV2.operate(dexType, 1, swapData); // 1 = swap module // Decode swap result to get actual amounts (uint256 amountOut, uint256 protocolFee, uint256 lpFee) = abi.decode(swapResult, (uint256, uint256, uint256)); // Verify we got at least the minimum amount require(amountOut >= minAmountOut, "Insufficient output amount"); // 2. Handle token settlement if (swap0To1) { // Supply token0, receive token1 dexV2.settle(dexKey.token0, int256(amountIn), 0, 0, address(this), true); dexV2.settle(dexKey.token1, 0, 0, int256(amountOut), recipient, false); } else { // Supply token1, receive token0 dexV2.settle(dexKey.token1, int256(amountIn), 0, 0, address(this), true); dexV2.settle(dexKey.token0, 0, 0, int256(amountOut), recipient, false); } return swapResult; } // DEX calls this when isCallback = true in settle() function dexCallback(address token, address to, uint256 amount) external { require(msg.sender == address(dexV2), "Unauthorized"); // Transfer tokens from the original caller to DEX // Note: tx.origin is the user who initiated the transaction // Note: You can also use transient storage to store the caller address to know whom to transfer tokens from IERC20(token).safeTransferFrom(tx.origin, to, amount); } } * * * Operating DEX Modules [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#operating-dex-modules) ------------------------------------------------------------------------------------------------------------- ### Encoding Swap Operations [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#encoding-swap-operations) To perform swaps, you call `operate()` with properly encoded data: solidity // For D3 and D4 swaps uint256 constant SWAP_MODULE_ID = 1; // Example: Encoding a swapIn operation SwapInParams memory params = SwapInParams({ dexKey: dexKey, swap0To1: true, amountIn: 1000e6, // 1000 USDC amountOutMin: 990e6, // Minimum 990 USDT controllerData: "" }); bytes memory operateData = abi.encodeWithSelector( bytes4(keccak256("swapIn(SwapInParams)")), params ); // Execute the swap dexV2.operate(3, 1, operateData); // dexType=3 (D3), moduleId=1 (swap) ### DEX Types and Module IDs [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#dex-types-and-module-ids) solidity // DEX Types uint256 constant D3_DEX_TYPE = 3; // Smart Collateral Range Orders uint256 constant D4_DEX_TYPE = 4; // Smart Debt Range Orders // Module IDs uint256 constant SWAP_MODULE_ID = 1; // For swapIn/swapOut uint256 constant USER_MODULE_ID = 2; // For deposit/withdraw/borrow/payback uint256 constant CONTROLLER_MODULE_ID = 3; // For controller operations * * * Token Settlement with settle() [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#token-settlement-with-settle) ----------------------------------------------------------------------------------------------------------------------------- The `settle()` function handles all token transfers. Understanding its parameters is crucial: solidity function settle( address token, int256 supplyAmount, // Positive = supply TO the DEX int256 borrowAmount, // Positive = borrow FROM the DEX int256 storeAmount, // Positive = store IN the DEX address to, // Where tokens go bool isCallback // true = DEX calls dexCallback for transfer ) external payable; ### Settlement Patterns [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#settlement-patterns) **1\. Basic Token Input (User → DEX)** solidity // User supplies 1000 USDC to DEX dexV2.settle( USDC_ADDRESS, 1000e6, // supplyAmount: 1000 USDC to DEX 0, // borrowAmount: not borrowing 0, // storeAmount: not storing address(this), // to: callback will transfer from this contract true // isCallback: DEX will call dexCallback ); **2\. Using Stored Balances (Advanced)** solidity // First, store tokens in DEX for later use (saves gas in multi-step operations) dexV2.settle( USDC_ADDRESS, 0, // supplyAmount: not supplying to pool 0, // borrowAmount: not borrowing 1000e6, // storeAmount: store 1000 USDC in DEX address(this), // to: callback source true // isCallback: DEX calls back for transfer ); // Later, use stored tokens for swap (no external transfer needed) dexV2.settle( USDC_ADDRESS, 1000e6, // supplyAmount: use stored tokens for swap 0, // borrowAmount: not borrowing -1000e6, // storeAmount: negative = withdraw from storage address(0), // to: not needed (internal transfer) false // isCallback: not needed (internal transfer) ); * * * Best Practices [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#best-practices) ----------------------------------------------------------------------------------------------- 1. **Implement proper slippage protection** 2. **Validate callback caller authenticity** 3. **Use router based integration for simplicity** 4. **Use callback based integration for gas efficiency** 5. **Batch multiple operations in startOperationCallback and settle at once at the end** * * * Resources [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#resources) ------------------------------------------------------------------------------------- ### Documentation [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#documentation) * [General Fluid Docs](https://docs.fluid.instadapp.io/) * [DEX v2 Blog Post](https://gov.fluid.io/t/introducing-fluid-dex-v2/1665) * [DEX v1 Documentation](https://docs.fluid.instadapp.io/protocols/dex/) ### Contract Addresses [​](https://docs.fluid.instadapp.io/integrate/dex-v2-swaps.html#contract-addresses) | Network | Contract | Address | | --- | --- | --- | | Ethereum | FluidDexV2 | `TBD` | | Ethereum | FluidDexV2Resolver | `TBD` | | Ethereum | FluidDexV2Router | `TBD` | | Polygon | FluidDexV2 | `0x7822B3944B1a68B231a6e7F55B57967F28BB369e` | | Polygon | FluidDexV2Resolver | `0x1E45589D501AcED82013c2838552122f943B33Ac` | | Polygon | FluidDexV2Router | `0x713fD04a47Db41AB5684AEC2A2063d5278A53616` | * * * --- # Understanding Fluid: Key Concepts and Practices | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#VPContent) Return to top Understanding Fluid: Key Concepts and Practices [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#understanding-fluid-key-concepts-and-practices) ================================================================================================================================================================================================== #### Financial Quantities [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#financial-quantities) * **Raw Amounts**: These are preliminary figures that require multiplication by an exchange price to yield the actual token amounts (e.g. with interest mode amounts) * **Normal Amounts**: These figures represent the final token values directly, requiring no further adjustments to reflect accurate balances (e.g. interest free mode amounts). #### User Definition [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#user-definition) * In the context of the Liquidity contract, a **User** typically refers to a protocol layer constructed atop it, such as an fToken or a Vault. This designation underscores the intermediary role these constructs play between the Liquidity contract and the end-users. #### Optimization and Addressing [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#optimization-and-addressing) * **Gas Efficiency**: A cornerstone of Fluid's design philosophy is the prioritization of gas optimization. This focus influences various aspects of the codebase, enhancing performance and reducing transaction costs. * **Native Token Representation**: The placeholder `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` is utilized to denote the native blockchain currency (e.g., ETH, MATIC) within transactions, serving as a universal identifier. ### Error Handling in Fluid [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#error-handling-in-fluid) Our approach to error management is systematic and uniform across Fluid's codebase, facilitating efficient debugging and code maintenance. Each error within the system is associated with a unique code, allowing developers to quickly pinpoint the root cause of issues. For a detailed understanding of our error structuring, please refer to the [Error Handling Guide](https://docs.fluid.instadapp.io/integrate/errors-structure.html) . ### Enhancing Efficiency through Gas Optimizations [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#enhancing-efficiency-through-gas-optimizations) #### Memory Management [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#memory-management) To optimize for gas consumption, we strategically utilize the `temp_` prefix for variables within our code. This practice involves reusing the same memory slot for multiple purposes, significantly reducing the need for additional memory allocations. We strike a balance between gas efficiency and code clarity, supplementing our code with comprehensive comments to maintain readability despite the complex memory management techniques. #### Storage Variable Packing [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#storage-variable-packing) In an effort to further minimize gas costs, Fluid's codebase employs a technique known as storage variable packing. This method is meticulously applied, especially within critical contracts like Liquidity & Vault, to compact data at the bit level: * **Writing to Storage**: To update stacked `uint` values in storage, we first clear the necessary bits using a bitwise AND (`&`) operation with a mask. Subsequently, values are combined using a bitwise OR (`|`), with each value positioned correctly through bit shifting (`<<`). * **Reading from Storage**: The retrieval of stacked values involves shifting the data to align with the start position (`>>`) and then applying a mask (`&`) to extract the precise value. These optimization strategies are essential to Fluid's design philosophy, reducing transaction costs and enhancing the protocol's performance without sacrificing code integrity. ### Leveraging BigMath for Efficient Storage [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#leveraging-bigmath-for-efficient-storage) Fluid employs the BigMath library to optimize numeric value storage, achieving significant savings on storage requirements while accepting minimal and predictable precision loss. This method involves distilling large numbers into a manageable format of coefficients and exponents, ensuring efficient use of blockchain storage without necessitating overflow checks. Here’s a closer look at how BigMath enhances Fluid’s functionality: #### Precision and Rounding [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#precision-and-rounding) The utilization of BigMath introduces a slight precision loss, a compromise that remains favorable for users due to the protocol's strategic handling of rounding to safeguard liquidity and prevent transaction reverts: * **Supply Amounts**: Rounded down to minimize overestimation of assets. * **Borrow Amounts**: User and total borrow amounts are rounded up, ensuring that obligations are not understated. * **Limits**: Implemented limits are rounded down for conservative operation, except for withdrawal limits, where rounding down instead of up avoids minor discrepancies leading to transaction reverts, without compromising the protocol's security. #### Operational Insights [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#operational-insights) * **Precision Threshold**: BigMath's precision is set at 7.2057594e16 for a coefficient size of 56 bits, above which numbers experience precision loss. This design choice ensures that most operations within Fluid are unaffected by rounding errors. * **Impact of Rounding**: The rounding strategy may result in the sum of user borrow amounts surpassing the total borrowed amount. In such cases, corrective measures are applied — for example, setting the total borrow to zero if repayments exceed the outstanding amount. This approach also necessitates seeding new protocols with a nominal initial balance to prevent reverts from negligible imprecision. #### BigMath in Action [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#bigmath-in-action) Discover how to manage BigMath data effectively in the context of Fluid’s operations: [Understanding BigMath with LogOperate Event](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#extracting-fields-from-compact-storage-in-solidity) . ### Configuration and Token Listing Workflow [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#configuration-and-token-listing-workflow) Fluid has implemented comprehensive checks and balances to ensure seamless operation and integration of tokens into the Liquidity protocol. These measures are designed to maintain the system's integrity and prevent potential issues related to token values and operational flows. #### Safeguards Against High Token Amounts [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#safeguards-against-high-token-amounts) The Liquidity `operate()` function is engineered with safeguards that prevent transactions involving exceedingly large token amounts, which could otherwise cause unexpected overflows. Specifically, it rejects values exceeding the maximum integer size of 128 bits (max int 128). Practically, token amounts up to approximately 1e70 are deemed safe, a threshold well beyond the scope of any legitimate token's requirements. #### Token Listing Process [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#token-listing-process) Listing a new token within the Liquidity protocol involves a precise sequence of steps to ensure accurate configuration and integration: 1. **Rate Configuration**: Establish the rate configuration for the token. 2. **Token Configuration**: Proceed to set the token's configuration. 3. **User Access**: Finally, enable access for users (protocols) to interact with the newly listed token. Adhering to this order is crucial; deviations will result in errors, underscoring the importance of following the prescribed workflow for successful token listing. #### Lending fToken Creation [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#lending-ftoken-creation) The creation of a new Lending fToken, a cornerstone of Fluid's lending protocol, also follows a specific procedural framework: 1. **Asset Configuration**: Initiate by setting up the configuration for the underlying asset within the Liquidity protocol. 2. **fToken Deployment**: Utilize the LendingFactory’s `createToken()` method to deploy the new fToken. 3. **Supply Configuration**: Finalize by configuring the user supply settings for the fToken within Liquidity. #### Native Token Addressing [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#native-token-addressing) For operations involving the native underlying fToken, it is imperative to use the official wrapped token address (e.g., WETH for Ethereum, WMATIC for Polygon), rather than the generic placeholder for native blockchain currencies (`0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`). #### Deployment Scripts [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#deployment-scripts) The integration of new fTokens and vaults into the Fluid ecosystem is facilitated by dedicated deployment scripts. ### Managing Liquidity Limits [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#managing-liquidity-limits) Fluid's Liquidity protocol employs dynamic limits for borrowing and withdrawals to maintain stability and flexibility within the ecosystem. These limits adjust based on user activity and market conditions, ensuring a balanced approach to liquidity management. #### Dynamic Borrowing Limits [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#dynamic-borrowing-limits) The borrowing capacity within Fluid is not static; it evolves through a series of predetermined steps: * **Base to Maximum**: Starting at the `baseDebtCeiling`, the borrowing limit can expand by a set percentage `expandPercentage` over a defined duration `expandDuration` until it reaches the `maxDebtCeiling`. * **Synonyms**: "Debt ceiling" and "borrow limit" are interchangeable terms within this context. #### Withdrawal Limits [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#withdrawal-limits) Withdrawal capacities are similarly adaptive, designed to safeguard the protocol's liquidity: * **Base Limit**: Withdrawals up to the `baseWithdrawalLimit` are unrestricted. * **Expansion Mechanism**: Beyond the base limit, the withdrawal capacity can increase by a certain percentage of the user's total supply over time, allowing gradual access to funds above the base threshold. * **Expansion Settings**: Deposits help reach the fully expanded withdrawal limit, if the deposit is big enough it can make this happen instantly. Withdrawals trigger further expansion of the withdrawal limit, starting from the `lastWithdrawal` limit to the fully expanded amount. Example with configs: * Expand percent = 20% * Expand duration = 200 sec * Base withdrawal limit is 5. Some scenarios: * Multiple withdrawals scenario: Starting with user's deposit is 15 and withdrawal limit before operation is 12 (fully expanded). * New withdrawal of 2 -> down to 13. withdrawal limit will expand from previous limit (12) down to full expansion of 13 \* 0.8 -> 10.4. * Instant withdrawal right after this operation of an amount > 1 would revert. * Assuming 100 sec passed (half expand duration). Withdrawal limit would be 12 - (13 \* 0.1) -> 10.7. * Assuming 150 sec passed. Withdrawal limit would be 12 - (13 \* 0.15) -> 10.05, which is below maximum expansion of 10.4 so the actual limit is 10.4. * Further withdrawals will trigger a new expansion process. * Other scenarios: If user's supply is below 5 then limit will be 0 (meaning user can withdraw fully). * New deposit of 5.5: If user supply is 5.5 then withdrawal limit is 5.5 \* 0.8 = 4.4 (instantly expanded 20% because of new deposit). * New withdrawal of 0.6 down to 4.9: If someone withdraws below base limit then the new limit set at the end of the operation will instantly be 0 and user's can withdraw down to 0. So if the current user supply minus the withdrawable amount is below the base withdrawal limit, this has the effect that essentially the full user supply amount is withdrawable. It just happens in two steps: first a withdrawal to below base limit -> triggers new limit becoming 0 -> full rest amount is withdrawable. This is not super elegant but it allows for a easy implementation that serves the desired purpose good enough. * New scenario: user's deposit is 6 and withdrawal limit before operation is 5.5, if someone supplies 0.5 (total supply = 6.5) -> the limit will remain as 5.5 and expand from there to the full 20% expansion -> 5.2. * If user's deposit is 6 and withdrawal limit is 5.5 and someone supplies 1 (total supply = 7) -> now the new limit will become 5.6 (20% of total deposits) instantly. A special case is the first time that the user supply amount comes above the base withdrawal limit: the withdrawal limit immediately becomes the fully expanded withdrawal limit. So this acts like a big deposit that would immediately "fill" the full expanded withdrawal limit. This is a known and acceptable behavior for the withdrawal limit as it does not negatively affect the desired goal of the limit whilst keeping the implementation logic simple. #### Borrow Limits [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#borrow-limits) Paybacks help reach the fully expanded borrow limit, if the payback is big enough it can make this happen instantly. Borrows trigger further expansion of the borrow limit, starting from the last borrow limit to the fully expanded amount. Borrow limit has a hard max limit, above which expansion is never possible. Example with configs: * Expand percent = 20% * Expand duration = 200 sec * Base borrow limit is 5. * Max borrow limit is 7. Some scenarios: * User can always borrow up until base borrow limit of 5. * New borrow of 4.5 (to total borrow of 4.5): would trigger expansion to above base limit (at fully expanded after 200 seconds 4.5 \* 1.2 = 5.4). * Assuming full expand duration passed, new borrow of 0.5 to total borrow of 5 -> triggers expansion from 5.4 to 6 (full expansion: 5 \* 1.2 = 6). * After half duration passed, borrow limit would be lastBorrowLimit + halfExpandedLimit = 5.4 + 0.5 -> 5.9. * Assuming full expand duration passed, new borrow of 1 to total borrow of 6 -> triggers expansion from 5.9 to 7.2 (full expansion: 6 \* 1.2 = 7.2). Note that this would be above max limit. * Even after full expansion, the limit will be hard capped at max limit of 7. User borrow of 1.01 to 7.01 would revert. * Assuming full expand duration passed, new borrow of 1 to max limit 7 total borrow. No higher borrow amount is ever possible (unless max limit config is changed). * Payback of 1.5 down to 5.5 total borrow. Shrinking to fully expanded borrow limit of 5.5 \* 1.2 = 6.6 is immediately active. * Assuming no time passed -> borrow of 1.11 would revert. * Assuming no time passed -> Borrow of 0.1 to total borrow of 5.6 triggers expansion from 6.6 to 6.72 (full expansion: 5.6 \* 1.2 = 6.72). * After half duration, borrow limit would be 6.6 + 0.56 -> 7.16 which is above fully expanded so limit will be 6.72. * Payback of 5.6 down to 0. Shrinking of new borrow limit to base limit of 5 happens instantly. ### Vault protocol [​](https://docs.fluid.instadapp.io/integrate/understanding-fluid-key-concepts-and-practices.html#vault-protocol) See Whitepaper: [https://fluid.guides.instadapp.io/vault-protocol-whitepaper](https://fluid.guides.instadapp.io/vault-protocol-whitepaper) --- # Get all user vault positions | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#VPContent) Return to top Get all user vault positions [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#get-all-user-vault-positions) =================================================================================================================================== To get all Fluid vault user positions, follow these steps: ### Get the user positions from the VaultResolver [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#get-the-user-positions-from-the-vaultresolver) The VaultResolver periphery contract provides a method `positionsByUser` (also see [docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/main.sol/contract.FluidVaultResolver.html#positionsbyuser) ) which returns all user positions together with the vault data. The contract address is listed [here](https://github.com/Instadapp/fluid-contracts-public/blob/main/deployments/deployments.md#resolvers) . This method returns an array of UserPositions (`userPositions_`, see [struct docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/structs.sol/contract.Structs.html#userposition) ), and a corresponding array of VaultEntireData (`vaultsData_`, see [struct docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/structs.sol/contract.Structs.html#vaultentiredata) ). vaultentiredata There are alternative methods on the VaultResolver to also fetch a position by the nft id. ### Retrieve the position amounts and position tokens [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#retrieve-the-position-amounts-and-position-tokens) For each UserPosition element, there are the `supply` and `borrow` amounts as struct params which have the total user deposit and borrow amounts for one position. To get the supply and borrow _tokens_ for each UserPosition, use the VaultEntireData array element at the same index. Under the property `constantVariables` there are the properties `supplyToken` and `borrowToken`, see [struct docs](https://docs.fluid.instadapp.io/autogenerated-docs/protocols/vault/interfaces/iVaultT1.sol/interface.IFluidVaultT1.html#constantsview) . INFO Note: A user can create multiple positions on the same vault, so there can be multiple `UserPosition` with the same supply & borrow token. To get the _total_ user amounts, iterate over all UserPositions and sum up supply & borrow amounts for each token on all positions. ### Smart debt / smart col amounts [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#smart-debt-smart-col-amounts) For smart vault and smart debt the amounts are in DEX shares. There are flags for `isSmartCol` and `isSmartDebt` when fetching `getVaultEntireData()`, if true then the respective amount is in shares. Shares can be resolved to token amounts via either: * oracle price, in `Configs` struct of the VaultResolver * using token amounts per share from the [DexResolver](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/dex/structs.sol#L21-L24) (fetch DexEntireData for the Dex linked as supply or borrow token returned by the VaultResolver) For further info check the [public github repo](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/vault/structs.sol) or the [auto-generated docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/structs.sol/contract.Structs.html) . ### Health factors: Collateral factor, Liquidation threshold, penalty etc. [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#health-factors-collateral-factor-liquidation-threshold-penalty-etc) The VaultEntireData array element also includes the vault config data. Under the property `configs` (see [struct docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/structs.sol/contract.Structs.html#configs) ) there are the following properties: * `collateralFactor`: maximum ratio that can be borrowed * `liquidationThreshold`: ratio above which liquidation happens * `liquidationPenalty`: penalty when liquidation happens * `liquidationMaxLimit`: limit above which 100% could be liquidated All of these values are percent values in 1e2 precision, so 1% = 100, 80% = 8000 etc. ### Summary [​](https://docs.fluid.instadapp.io/integrate/vault-user-positions.html#summary) To summarize the steps: 1. `VaultResolver.positionsByUser(address user)` 2. Iterate through returned `UserPositions` array 3. In each iteration: * `userPositions[i].supply` refers to the user deposit amount of token `vaultsData[i].constantVariables.supplyToken` * `userPositions[i].borrow` refers to the user borrow amount of token `vaultsData[i].constantVariables.borrowToken` 4. More data is available in the `UserPosition` and `VaultEntireData` structs if needed, see [contract docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/structs.sol/contract.Structs.html) . --- # Fluid Liquidation swaps | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#VPContent) Return to top Fluid Liquidation swaps [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#fluid-liquidation-swaps) ====================================================================================================================== Liquidations in Fluid are simpler and more gas-efficient than a UniswapV3 swap. If liquidations are available, the swapper gets a significant discount to the available market rate. Integrating and making use of those available swaps is hence very beneficial. ### VaultLiquidationResolver [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#vaultliquidationresolver) All available swaps, swap paths and helper methods are available via a dedicated resolver contract, see [autogenerated docs for the contract](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vaultLiquidation/main.sol/contract.FluidVaultLiquidationResolver.html) . ##### Deployment addresses [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#deployment-addresses) See [deployment addresses in public repo](https://github.com/Instadapp/fluid-contracts-public/blob/main/deployments/deployments.md#vaultliquidationresolver) . ### General [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#general) * swap methods are expected to be called via `callStatic`, although they would not be doing any state changes anyway. * for native token, send `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. ### Get all currently available swaps [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#get-all-currently-available-swaps) The method `getAllVaultsSwap` returns all currently available swaps, filtered by the best available rate swap for each Fluid vault. This can be useful to find profitable trades, arbitrage opportunities, running a liquidation bot etc. ### Get best available swap for a certain swap and input amount [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#get-best-available-swap-for-a-certain-swap-and-input-amount) The `exactInput` method returns the currently best available swaps, sorted by best ratio and filtered to a given input amount. The returned swaps are optimized for the vast majority of possible cases whilst allowing for a very simple integration. This will be enough for most use-cases. Some custom optimization might be possible, see Advanced methods below. ### Creating execution payloads [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#creating-execution-payloads) The `getSwapTx` or for multiple swaps at once the `getSwapTxs` methods build the calldata for executing the swaps. The returned calldata executes `liquidate()` on the given Fluid vault protocol, with the defined input token amount and maximum allowed slippage. **Note that for swaps where the input token is the native token, it is necessary to send the `inAmt` along as `msg.value`**. ##### Build manually [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#build-manually) Alternatively you can also manually build the payload, the interface for the `liquidate()` method is (also see [contract docs](https://docs.fluid.instadapp.io/autogenerated-docs/protocols/vault/vaultT1/coreModule/main.sol/contract.FluidVaultT1.html#liquidate) ): /// @notice allows to liquidate all bad debt of all users at once. Liquidator can also liquidate partially any amount they want. /// @param debtAmt_ total debt to liquidate (aka debt token to swap into collateral token) /// @param colPerUnitDebt_ minimum collateral token per unit of debt in 1e18 decimals (aka slippage) /// @param to_ address at which collateral token should go to. /// @param absorb_ if true then liquidate from absorbed first /// @return actualDebtAmt_ if liquidator sends debtAmt_ more than debt remaining to liquidate then actualDebtAmt_ changes from debtAmt_ else remains same /// @return actualColAmt_ total liquidated collateral which liquidator will get function liquidate( uint256 debtAmt_, uint256 colPerUnitDebt_, address to_, bool absorb_ ) public payable returns (uint actualDebtAmt_, uint actualColAmt_); Advanced methods [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#advanced-methods) -------------------------------------------------------------------------------------------------------- ### Get swaps for previously fetched paths [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#get-swaps-for-previously-fetched-paths) The return data of the get path view methods can be fed into `getSwapsForPaths` the fetch the available swaps for those. ### Get swaps for a certain output amount [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#get-swaps-for-a-certain-output-amount) It is not possible to guarantee a certain output amount as a Fluid liquidation uses a fixed input amount as input param. The output amount will vary and change between one block and the next also because of oracle pricing etc. This it is only possible to estimate approximate swaps for a given target output amount with the method `approxOutput`. The maximum allowed difference should by tightly controlled via the maximum defined slippage. ### Get all possbile swap paths [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#get-all-possbile-swap-paths) Use the method `getAllSwapPaths` to get all possible swap paths. Alternatively you can use the methods `getSwapPaths` or `getAnySwapPaths` to get possible swap paths for certain input token to certain output token combination(s). ### Getting raw swap data [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#getting-raw-swap-data) The methods named ending with `SwapData` return the raw swap data as currently available on certain Fluid vaults. This is basically the data that the VaultResolver returns for the method `getVaultLiquidation()`. ### Custom optimization via swap methods [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#custom-optimization-via-swap-methods) The default swap methods come with built-in optimization to only return the best rate swap for each Fluid vault. The `exactInput` and `approxOutput` methods come with slightly better built-in optimization which is possible because of the defined input amount. There are however edge cases which could be even better optimized for, e.g. the rate for the `withAbsorb` _only_ liquidity could be better than the without absorb liquidity. See the code for more info. For advanced use-cases, all swap methods also have a `Raw` version method, which returns the exact same data just unoptimized. Meaning for the same vault, both the withAbsorb and the withoutAbsorb swaps will be returned, if both are available. Note that triggering a liquidation with absorb set to true will also tap into the liquidity of without absorb once the with absorb liquidity is used up. ### Filter swaps [​](https://docs.fluid.instadapp.io/integrate/liquidation-swaps.html#filter-swaps) The `filterToTargetInAmt` and `filterToApproxOutAmt` are helper methods which sort and filter the input swaps to a certain target amount. This can be useful when doing custom optimization. These methods should be used in combination with the returned swaps of `Raw` ending methods. Note this only works for swaps of the same path (input token -> output token). For mixed path swaps the result will be wrong. --- # Fluid Dex: Liquidity source integration | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#VPContent) Return to top Fluid Dex: Liquidity source integration [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#fluid-dex-liquidity-source-integration) ============================================================================================================================================= Guide on integrating Fluid Dex swaps as a Liquidity Source. Integration benefits [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#integration-benefits) -------------------------------------------------------------------------------------------------------- Adding Fluid Dex swaps as a liquidity source offers several benefits: 1. Best liquidity: Fluid Dex has the deepest liquidity for almost any token pair with a launched pool (e.g. wstETH-ETH, cbBTC-WBTC, ...). More pools will be launched continuously. 2. Easy Integration: Simple contract calls and payload building process through our resolver contracts. 3. Gas Efficiency: Swaps cost approximately 90k to 145k gas. 4. Arbitrage Opportunities: Can be leveraged with other DEXes for arbitrage setups. 5. Mathematical Consistency: Fluid Dex utilizes the `x * y = k` constant product formula (similar to Uniswap v2). Guide [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#guide) -------------------------------------------------------------------------- #### Liquidity Fetching [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#liquidity-fetching) DexReservesResolver provides each pool's reserves amounts. Triggers for liquidity fetching should be: 1. events: either _any_ event at a pool OR the LogOperate event at the Liquidity Layer (`0x52Aa899454998Be5b000Ad077a46Bbe360F4e497`) filtered by `user == pool addresses`. 2. in addition also trigger if no event happened in the last 5 to max 10 minutes at a pool (otherwise there is some important internal pricing logic not accounted for) #### Price estimation [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#price-estimation) DexReservesResolver provides `estimate()` methods for all types of swaps. Alternatively, we have Fluid Dex math logic replication libraries for JS ([see public repo](https://github.com/Instadapp/fluid-contracts-public/blob/main/dexMath/swapOperations/main.js) ), TS (see Paraswap reference implementation) and Golang (see Kyberswap reference implementation), to be used in combination with the DexReservesResolver for keeping updated pool state data. Note you must pass in the reserves fetched from the "Adjusted" suffix-named methods at the Resolver, which are scaled to 1e12 decimals. #### On-chain settlement [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#on-chain-settlement) Execute the `swapIn()` (or `swapOut`) method at the respective Dex pool. #### Deployment addresses [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#deployment-addresses) See [deployment addresses in public repo](https://github.com/Instadapp/fluid-contracts-public/blob/main/deployments/deployments.md#dexreservesresolver) . ### Important: Avoid reverts [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#important-avoid-reverts) * Due to the innovative architecture, the swappable amount depends on the actual token balance at the liquidity layer, on limits for borrowable and withdrawable amounts (which can expand over time), on an utilization limit and other similar limits. The DexReservesResolver returns all limits as `limits` (available, expandTo, expandDuration) in token decimals. Just pass in this `limits` object to the provided `swap()` methods in the DexMath code in JS or Golang alongside the `syncTime` of when those limits were fetched. The expansion of limits will be considered and all potential reverts will be caught accordingly. The `estimate()` methods on the resolver already include those checks. * The provided DexMath code also includes revert checks for other potential reverts such as much price movement within 1 swap, minimum pool ratio etc. * The pool is pausable, trackable via `event LogPauseSwapAndArbitrage()` and `event LogUnpauseSwapAndArbitrage()`. Alternatively this is available through the [DexState in the DexResolver](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/dex/structs.sol#L18) or can be directly read from storage (check code [here](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/dex/main.sol#L986) ). ### Max swappable amounts [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#max-swappable-amounts) Maximum possible swappable amounts in one swap are `limits.withdrawable.available` + `limits.borrowable.available` from the returned DexReservesResolver struct. Note that these amounts are not guaranteed to be swappable, just that more than this is for sure not swappable. To confirm the swap in depth, it is necessary to run the actual simulation which also catches all possible reverts as mentioned above. ### Provide the best pricing: Optimize gas usage [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#provide-the-best-pricing-optimize-gas-usage) To provide the best swaps to users, Fluid Dex provides a simple way to optimize gas cost by skipping token transfer steps through `swapInWithCallback()`. ![Fluid Dex transfers callback](https://docs.fluid.instadapp.io/assets/fluid-dex-transfers-callback.7BpFwIxk.jpg) The integration contract must implement (see [code](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/mocks/sampleDexCallback.sol) ): interface IDexCallback { function dexCallback(address token_, uint256 amount_) external; } contract MockSampleDexCallback is IDexCallback { using SafeERC20 for IERC20; address constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD; address public immutable FLUID_LIQUIDITY; address public senderTransient; constructor(address fluidLiquidity_) { FLUID_LIQUIDITY = fluidLiquidity_; senderTransient = DEAD_ADDRESS; // so to DEAD_ADDRESS to optimize gas refunds } // [...] Integration logic for swap, which triggers FluidDex.swapInWithCallback() // senderTransient = msg.sender; // tmp store (use transient on newer Solidity versions) // @INTEGRATOR: MUST IMPLEMENT: function dexCallback(address token_, uint256 amount_) external override { // ideally, transfer tokens from User -> Fluid liquidity layer: IERC20(token_).safeTransferFrom(senderTransient, FLUID_LIQUIDITY, amount_); senderTransient = DEAD_ADDRESS; // reset for ~5k gas refund // Alternative if tokens must be transferred from user -> integration contract first // IERC20(token_).safeTransfer(liquidityContract, amount_); } } Additional references [​](https://docs.fluid.instadapp.io/integrate/dex-swaps.html#additional-references) ---------------------------------------------------------------------------------------------------------- * Autogenerated resolver docs [see here](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/dexReserves/main.sol/abstract.DexActionEstimates.html) * Public repo: [https://github.com/Instadapp/fluid-contracts-public/tree/main/contracts/protocols/dex](https://github.com/Instadapp/fluid-contracts-public/tree/main/contracts/protocols/dex) . * Resolvers in public repo: [https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/dexReserves/main.sol](https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/periphery/resolvers/dexReserves/main.sol) * Reference implementation Kyberswap: [https://github.com/KyberNetwork/kyberswap-dex-lib/tree/main/pkg/liquidity-source/fluid/dex-t1](https://github.com/KyberNetwork/kyberswap-dex-lib/tree/main/pkg/liquidity-source/fluid/dex-t1) (includes Golang code for replicating Fluid Dex Math) * Reference implementation Paraswap: [https://github.com/paraswap/paraswap-dex-lib/tree/master/src/dex/fluid-dex](https://github.com/paraswap/paraswap-dex-lib/tree/master/src/dex/fluid-dex) (includes TS code for replicating the Fluid Dex Math) * General Fluid docs: [https://docs.fluid.instadapp.io/](https://docs.fluid.instadapp.io/) * Dex blog post: [https://blog.instadapp.io/fluid-dex/](https://blog.instadapp.io/fluid-dex/) * Dex math derivations [https://app.excalidraw.com/l/12EMdhpNZfV/1jzaWnLnu4H](https://app.excalidraw.com/l/12EMdhpNZfV/1jzaWnLnu4H) --- # Decode LogOperate Event | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#VPContent) Return to top Decode LogOperate Event [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#decode-logoperate-event) ============================================================================================================================ `LogOperate` Event Documentation [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#logoperate-event-documentation) -------------------------------------------------------------------------------------------------------------------------------------------- ### Event Name [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#event-name) `LogOperate` ### Description [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#description) This event is essential for anyone looking to monitor or analyze the protocol's activities, such as tracking total supplies, borrows, borrow rate, fee, utilization, exchange prices and supply and borrow liquidity ratios. It provides a real-time overview of operations, enhancing operational transparency and facilitating detailed analysis. Essentially, it acts as the backbone for understanding and engaging with the dynamic environment of Fluid, making every operation traceable and transparent. The `LogOperate` event is designed to emit detailed information following the execution of an `operate()` function in Liquidity Protocol. This function can perform various operations such as deposits, supplies, withdrawals, and borrows. ### Parameters [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#parameters) * **`user`** (`address indexed`): The protocol or user address that initiated the operation, possibly through an fToken, Vault protocol, or other mechanisms. * **`token`** (`address indexed`): The token address for which the operation was executed, indicating the specific asset being manipulated. * **`supplyAmount`** (`int256`): Indicates the operation's supply amount. Positive for deposit, negative for withdrawal, and zero indicates no supply operation. * **`borrowAmount`** (`int256`): Indicates the operation's borrow amount. Positive for borrow, negative for repayment, and zero indicates no borrow operation. * **`withdrawTo`** (`address`): The recipient address for funds withdrawn, applicable if `supplyAmount` is negative. * **`borrowTo`** (`address`): The recipient address for borrowed funds, applicable if `borrowAmount` is positive. * **`totalAmounts`** (`uint256`): A packed `uint256` representing updated total amounts post-operation, using the BigMath number format. It includes: * **First 64 bits (0-63)**: Total supply with interest in raw format (totalSupplyRaw \* supplyExchangePrice). BigMath format: 56 | 8. * **Next 64 bits (64-127)**: Total interest-free supply in normal token amount. BigMath format: 56 | 8. * **Next 64 bits (128-191)**: Total borrow with interest in raw format (totalBorrowRaw \* borrowExchangePrice). BigMath format: 56 | 8. * **Next 64 bits (192-255)**: Total interest-free borrow in normal token amount. BigMath format: 56 | 8. * **`exchangePricesAndConfig`** (`uint256`): A packed `uint256` containing updated exchange prices and configuration settings, detailed as follows: * **First 16 bits (0-15)**: Borrow rate in 1e2 format (100% = 10,000). * **Next 14 bits (16-29)**: Fee on interest from borrowers to lenders, configurable. * **Next 14 bits (30-43)**: Last stored utilization rate. * **Next 14 bits (44-57)**: Update on storage threshold, configurable. * **Next 33 bits (58-90)**: Last update timestamp. * **Next 64 bits (91-154)**: Supply exchange price in 1e12 format. * **Next 64 bits (155-218)**: Borrow exchange price in 1e12 format. * **One bit (219)**: Indicates the ratio direction for supply. * **Next 14 bits (220-233)**: SupplyRatio, indicating the supplyInterestFree / supplyWithInterest ratio. * **One bit (234)**: Indicates the ratio direction for borrow. * **Next 14 bits (235-248)**: BorrowRatio, indicating the borrowInterestFree / borrowWithInterest ratio. ### Detailed Breakdown [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#detailed-breakdown) #### `totalAmounts` [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#totalamounts) Encapsulates the state of total supplies and borrows within the protocol, including interest-bearing and interest-free amounts. This aids in understanding the protocol's liquidity and debts post-operation. #### `exchangePricesAndConfig` [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#exchangepricesandconfig) Provides a comprehensive view of economic factors influencing the operation, such as interest rates, fees, market utilization, and supply/borrow exchange prices. It also includes configuration settings impacting operations' execution and pricing. This enhanced documentation offers a thorough understanding of the `LogOperate` event, enabling developers and users to track, analyze, and integrate with the DeFi protocol effectively. Extracting Fields from Compact Storage in Solidity [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#extracting-fields-from-compact-storage-in-solidity) ================================================================================================================================================================================== This part outlines the process for extracting field values from `totalAmounts` and `exchangePricesAndConfig` within a Solidity contract, employing bit manipulation techniques and the `BigMathMinified` library for BigNumber operations. Having helper variables: solidity uint256 internal constant X8 = 0xff; uint256 internal constant X14 = 0x3fff; uint256 internal constant X15 = 0x7fff; uint256 internal constant X16 = 0xffff; uint256 internal constant X18 = 0x3ffff; uint256 internal constant X24 = 0xffffff; uint256 internal constant X33 = 0x1ffffffff; uint256 internal constant X64 = 0xffffffffffffffff; uint256 internal constant DEFAULT_COEFFICIENT_SIZE = 56; uint256 internal constant DEFAULT_EXPONENT_SIZE = 8; Extracting Fields from totalAmounts [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#extracting-fields-from-totalamounts) ---------------------------------------------------------------------------------------------------------------------------------------------------- The totalAmounts is another packed uint256 representing various totals within the protocol. Here is how to access each value: ### Total Supply with Interest [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#total-supply-with-interest) solidity uint256 totalSupplyWithInterestBigNumber = totalAmounts_ & X64; //bignumber form uint256 totalSupplyWithInterest = BigMathMinified.fromBigNumber( totalSupplyWithInterestBigNumber, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); ### Total Interest-Free Supply [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#total-interest-free-supply) solidity uint256 totalInterestFreeSupplyBigNumber = (totalAmounts_ >> BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64; //bignumber form uint256 totalInterestFreeSupply = BigMathMinified.fromBigNumber( totalInterestFreeSupplyBigNumber, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); ### Total Borrow with Interest [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#total-borrow-with-interest) solidity uint256 totalBorrowWithInterestBigNumber = (totalAmounts_ >> BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64; //bignumber form uint256 totalBorrowWithInterest = BigMathMinified.fromBigNumber( totalBorrowWithInterestBigNumber, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); ### Total Interest-Free Borrow [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#total-interest-free-borrow) solidity uint256 totalInterestFreeBorrowBigNumber = totalAmounts_ >> BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE; //bignumber form uint256 totalInterestFreeBorrow = BigMathMinified.fromBigNumber( totalInterestFreeBorrowBigNumber, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); Using BigMathMinified for BigNumber Operations [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#using-bigmathminified-for-bignumber-operations) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- For handling large numbers accurately, especially when dealing with exchange prices and ratios, the BigMathMinified library is utilized. Here is an example of converting from BigNumber format to uint256: ### Converting BigNumber to uint256 [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#converting-bignumber-to-uint256) solidity uint256 value = BigMathMinified.fromBigNumber( (totalAmounts_ >> someBitsPosition) & bitMask, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); Extracting Fields from `exchangePricesAndConfig` [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#extracting-fields-from-exchangepricesandconfig) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The `exchangePricesAndConfig` is a packed `uint256` value that stores multiple configurations and prices. Below are the methods to extract each value: ### Borrow Rate [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#borrow-rate) solidity uint256 borrowRate = exchangePricesAndConfig_ & X16; ### Fee [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#fee) solidity uint256 fee = (exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_FEE) & X14; ### Utilization [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#utilization) solidity uint256 utilization = (exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_UTILIZATION) & X14; ### Supply and Borrow Exchange Price [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#supply-and-borrow-exchange-price) solidity uint256 supplyExchangePrice = (exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) & X64; uint256 borrowExchangePrice = (exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) & X64; ### Ratios [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#ratios) Ratios are encoded with a leading direction bit, followed by the ratio value itself. solidity bool supplyRatioDirection = ((exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & 1) == 1; uint256 supplyRatio = (exchangePricesAndConfig_ >> (BITS_EXCHANGE_PRICES_SUPPLY_RATIO + 1)) & X14; bool borrowRatioDirection = ((exchangePricesAndConfig_ >> BITS_EXCHANGE_PRICES_BORROW_RATIO) & 1) == 1; uint256 borrowRatio = (exchangePricesAndConfig_ >> (BITS_EXCHANGE_PRICES_BORROW_RATIO + 1)) & X14; Interacting and decoding data with JavaScript, Ethers.js, and Infura [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#interacting-and-decoding-data-with-javascript-ethers-js-and-infura) ==================================================================================================================================================================================================================== This section will provide an example of how to fetch and decode the `exchangePricesAndConfig` and `totalAmounts` data from the Liquidity Protocol using LiquidityResolver smart contract using `ethers.js` and `infura`. Setup and Initialization [​](https://docs.fluid.instadapp.io/integrate/encode-logOperate-event.html#setup-and-initialization) ------------------------------------------------------------------------------------------------------------------------------ First, ensure `ethers.js` is included in your project: bash npm install ethers@5.6.9 Replace `YOUR_INFURA_KEY` with your actual Infura project key to connect to the Ethereum network through the JSON RPC provider. Substitute `TOKEN_ADDRESS` with the actual Ethereum address of the token you're interested in analyzing, like USDC. javascript const { ethers } = require("ethers"); const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_INFURA_KEY"); const liquidityResolverContractABI = [\ // Add the ABI definition for the functions you're going to call from liquidity contract\ "function getExchangePricesAndConfig(address) public view returns (uint256)",\ "function getTotalAmounts(address) public view returns (uint256)",\ ]; const liquidityResolverAddress = "0x741c2Cd25f053a55fd94afF1afAEf146523E1249"; // LiquidityResolver contract on Ethereum mainnet const liquidityResolver = new ethers.Contract(liquidityResolverAddress, liquidityResolverContractABI, provider); const tokenAddress = "TOKEN_ADDRESS"; //ex. USDC on Ethereum mainnet - 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 const DEFAULT_EXPONENT_SIZE = 8n; const DEFAULT_EXPONENT_MASK = BigInt("0xFF"); const X64 = BigInt("0xFFFFFFFFFFFFFFFF"); // Helper function to shift and mask according to Solidity's BigMath function decodeBigMath(value) { let memVar = value & X64; let coefficient = memVar >> DEFAULT_EXPONENT_SIZE; let exponent = memVar & DEFAULT_EXPONENT_MASK; return coefficient << exponent; // Simulate BigMath logic } async function fetchAndDecode() { const totalAmounts = (await liquidityResolver.getTotalAmounts(tokenAddress)).toBigInt(); // Decode the totalAmounts fields using the decodeBigMath function let supplyRawInterest = decodeBigMath(totalAmounts); let supplyInterestFree = decodeBigMath((totalAmounts >> 64n) & X64); let borrowRawInterest = decodeBigMath((totalAmounts >> 128n) & X64); let borrowInterestFree = decodeBigMath(totalAmounts >> 192n); // No need for & X64 due to shifting all the way console.log(`Supply Raw Interest: ${supplyRawInterest.toString()}`); console.log(`Supply Interest Free: ${supplyInterestFree.toString()}`); console.log(`Borrow Raw Interest: ${borrowRawInterest.toString()}`); console.log(`Borrow Interest Free: ${borrowInterestFree.toString()}`); const exchangePricesAndConfig = (await liquidityResolver.getExchangePricesAndConfig(tokenAddress)).toBigInt(); // Decode fields from exchangePricesAndConfig const borrowRate = exchangePricesAndConfig & BigInt("0xffff"); const fee = (exchangePricesAndConfig >> 16n) & BigInt("0x3fff"); const utilization = (exchangePricesAndConfig >> 30n) & BigInt("0x3fff"); const supplyExchangePrice = (exchangePricesAndConfig >> 91n) & BigInt("0xffffffffffffffff"); const borrowExchangePrice = (exchangePricesAndConfig >> 155n) & BigInt("0xffffffffffffffff"); console.log(`Borrow Rate: ${borrowRate.toString()}`); console.log(`Fee: ${fee.toString()}`); console.log(`Utilization: ${utilization.toString()}`); console.log(`Supply Exchange Price: ${supplyExchangePrice.toString()}`); console.log(`Borrow Exchange Price: ${borrowExchangePrice.toString()}`); } fetchAndDecode().catch(console.error); --- # Get lend, borrow, yield rates | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#VPContent) Return to top Get lend, borrow, yield rates [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#get-lend-borrow-yield-rates) ====================================================================================================================================== See below guides for fetching lending, borrow and yield incl. reward rates for the various Fluid protocols. All contract addresses for the resolvers are listed [here](https://github.com/Instadapp/fluid-contracts-public/blob/main/deployments/deployments.md#resolvers) . **Resolver methods are not intended for on-chain use and most resolver methods are expected to be called via callStatic.** All rate values are returned in percent 1e2 precision (1% = 100, 100% = 10000) unless otherwise specified. ### Types of rewards [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#types-of-rewards) * Native rewards: Protocol built-in on-chain rewards, e.g. USDC on fUSDC or ETH on an ETH/USDC vault. Accrue automatically by increasing the user balance, no claiming needed. * Merkle rewards: Separately claimable rewards that can be in any token, usually FLUID, on e.g. fUSDC. Note that merkle reward rates are not available on-chain via our resolvers, those have to be fetched through our API instead. * Third party rewards e.g. KING APR from ether.fi or rewards handled by merkl etc. For merkl, please refer to the [merkl docs](https://docs.merkl.xyz/) to fetch any related data. Lendings (fTokens) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#lendings-ftokens) ---------------------------------------------------------------------------------------------------------------- #### via API [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#via-api) Use [https://api.fluid.instadapp.io/v2/lending/1/tokens](https://api.fluid.instadapp.io/v2/lending/1/tokens) to fetch data for all tokens or `https://api.fluid.instadapp.io/v2/lending//tokens/` (e.g. [fUSDC](https://api.fluid.instadapp.io/v2/lending/1/tokens/0x9Fb7b4477576Fe5B32be4C1843aFB1e55F251B33) ) to fetch data for a specific fToken. Returned fields: * supplyRate: interest at the Liquidity Layer (paid from borrowers) * rewardsRate: additional interest from native rewards, if active * totalRate: supplyRate + rewardsRate * asset.stakingApr (optional): if the asset has some native APR like e.g. WSTETH staking rate, this is included in asset -> stakingApr. This is not included in `totalRate`. * rewards array (optional): all other rewards, only present if any exist. Fluid handled merkle rewards when rewardType is 'merkle', in that case "rate" is the merkle rewards APR. This is not included in `totalRate`. Metadata -> merkle -> programId can be used to fetch emission per second via this endpoint, which might not be available for all programs: `https://merkle.api.fluid.instadapp.io/programs//apr`. When other reward types like e.g. handled by merkl, please refer to the [merkl docs](https://docs.merkl.xyz/) to fetch any additional data or the respective reward source or check the metadata for useful included info (e.g. claimUrl). #### on-chain (without merkle rewards) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#on-chain-without-merkle-rewards) The LendingResolver contract methods like `getFTokenDetails` (also see [docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/lending/main.html#getFTokenDetails) ) or `getFTokensEntireData` include all APR info incl. rewards. The returned struct `FTokenDetails` has the following fields: * supplyRate: interest at the Liquidity Layer (paid from borrowers) * rewardsRate: additional interest from native rewards, if active Vaults [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#vaults) ------------------------------------------------------------------------------------------ For smart vaults, refer to the specific section further below. #### via API [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#via-api-1) Use [https://api.fluid.instadapp.io/v2/borrowing/1/vaults](https://api.fluid.instadapp.io/v2/borrowing/1/vaults) to fetch data for all vaults or `https://api.fluid.instadapp.io/v2/borrowing//vaults/` (e.g. [vault 1](https://api.fluid.instadapp.io/v2/borrowing/1/vaults/1) ) to fetch data for a specific vault. Returned fields: * supplyRate.liquidity.token0: interest earned by lenders at the Liquidity Layer (paid from borrowers) * supplyRate.vault.rate: rate at liquidity combined with rewards or fee rate (see `supplyRate.vault.feeRat` below). can never be < 0 * supplyRate.vault.feeRate: rewards or fee rate. when positive rewards, when negative fee. The value is in relative percent to `supplyRate.liquidity.token0`, e.g.: * when rewards: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = 20%, supplyRateVault = 4.8% * when fee: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = -30%, supplyRateVault = 2.8% * borrowRate.liquidity.token0: interest payed by borrowers at the Liquidity Layer * borrowRate.vault.rate: rate at liquidity combined with rewards or fee rate (see `borrowRate.vault.feeRate` below). can never be < 0 * borrowRate.vault.feeRate: rewards or fee rate. when positive fee, when negative rewards. The value is in relative percent to `borrowRate.liquidity.token0`, e.g.: * when rewards: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = -20%, borrowRateVault = 3.2%. * when fee: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = 30%, borrowRateVault = 5.2%. * supplyToken.token0.stakingApr: native APR of the supply asset itself, e.g. WSTETH staking rate * borrowToken.token0.stakingApr: native APR of the borrow asset itself, e.g. WSTETH staking rate * rewards array (optional): all other rewards, only present if any exist. More info see [Lendings (fTokens)](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#lendings-ftokens) #### on-chain (without merkle rewards) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#on-chain-without-merkle-rewards-1) The VaultResolver contract methods like `getVaultEntireData` (also see [docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/vault/main.html#getVaultEntireData) ) include all APR info incl. rewards. The returned struct `VaultEntireData` -> `exchangePricesAndRates` has the following fields: * supplyRateLiquidity: interest earned by lenders at the Liquidity Layer (paid from borrowers) * borrowRateLiquidity: interest payed by borrowers at the Liquidity Layer * supplyRateVault: rate at liquidity combined with rewards or fee rate (see `rewardsOrFeeRate` below). can never be < 0 * borrowRateVault: rate at liquidity combined with rewards or fee rate (see `rewardsOrFeeRate` below). can never be < 0 * rewardsOrFeeRateSupply: rewards or fee rate. when positive rewards, when negative fee. The value is in relative percent to `supplyRateLiquidity`, e.g.: * when rewards: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = 20%, supplyRateVault = 4.8% * when fee: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = -30%, supplyRateVault = 2.8% * rewardsOrFeeRateBorrow: rewards or fee rate. when positive fee, when negative rewards. The value is in relative percent to `borrowRateLiquidity`, e.g.: * when rewards: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = -20%, borrowRateVault = 3.2%. * when fee: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = 30%, borrowRateVault = 5.2%. Smart vaults (with dex liquidity on collateral or debt side) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#smart-vaults-with-dex-liquidity-on-collateral-or-debt-side) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Smart vaults can be either smart collateral / normal debt, normal collateral / smart debt or both smart collateral / smart debt. For normal collateral and debt, the previous section applies. For smart collateral and smart debt, the below info applies. Use the same process as for [normal vaults](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#vaults) , but note the following differences: #### via API [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#via-api-2) Additional fields: Token1 infos: * supplyRate.liquidity.token1: interest earned by lenders at the Liquidity Layer (paid from borrowers) for token1 of the dex pair * supplyToken.token1.stakingApr: native APR of the supply asset token1 itself, e.g. WSTETH staking rate * borrowRate.liquidity.token1: interest payed by borrowers at the Liquidity Layer for token1 of the dex pair * borrowToken.token1.stakingApr: native APR of the borrow asset token1 itself, e.g. WSTETH staking rate Dex trading APR: * supplyRate.dex.trading: smart collateral dex pool APR earned through swap fees * borrowRate.dex.trading: smart debt dex pool APR earned through swap fees Differences for vault rate values: "rate" refers to the reward / fee rate at the vault itself instead. "feeRate" can be ignored, it will always be 0. * supplyRate.vault.rate: smart collateral rewards or fee rate at the vault. when positive rewards, when negative fee. Absolute percent APR amount referring to the dex shares, i.e. treat it the same way as Dex trading APR. * borrowRate.vault.rate: smart debt rewards or fee rate at the vault. when positive fee, when negative rewards. Absolute percent APR amount referring to the dex shares, i.e. treat it the same way as Dex trading APR. #### on-chain (without merkle rewards and dex trading APR) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#on-chain-without-merkle-rewards-and-dex-trading-apr) Dex trading APR and merkle rewards info is only available via API. Differences to normal collateral / normal debt: * supplyRateLiquidity: always 0, must be fetched per token via the DexResolver instead (see below). * borrowRateLiquidity: always 0, must be fetched per token via the DexResolver instead (see below). * rewardsOrFeeRateSupply: can be ignored, always == supplyRateVault * rewardsOrFeeRateBorrow: can be ignored, always == borrowRateVault * supplyRateVault: smart collateral rewards or fee rate at the vault. when positive rewards, when negative fee. Absolute percent APR amount referring to the dex shares, i.e. treat it the same way as Dex trading APR. * borrowRateVault: smart debt rewards or fee rate at the vault. when positive fee, when negative rewards. Absolute percent APR amount referring to the dex shares, i.e. treat it the same way as Dex trading APR. To fetch the dex pair token rates use the DexResolver contract methods like `getDexSwapLimitsAndAvailability` (also see [docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/dex/main.html#getDexSwapLimitsAndAvailability) ) or `getDexEntireData`. The returned struct `SwapLimitsAndAvailability` includes the info for each token in the liquidityTokenData0 and liquidityTokenData1 returned `OverallTokenData` structs -> "supplyRate" and "borrowRate". These values refer to the rates earned as lenders or paid as borrowers at the LL. Smart lendings (dex pool lendings) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#smart-lendings-dex-pool-lendings) ------------------------------------------------------------------------------------------------------------------------------------------------ #### via API [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#via-api-3) Use [https://api.fluid.instadapp.io/v2/smart-lending/1/tokens](https://api.fluid.instadapp.io/v2/smart-lending/1/tokens) to fetch data for all smart lendings (replace chain-id as needed) Returned fields: * tokens.token0.stakingApr: native APR of the supply asset token0 itself, e.g. WSTETH staking rate * tokens.token1.stakingApr: native APR of the supply asset token1 itself, e.g. WSTETH staking rate * rate.liquidity.token0: interest earned by lenders at the Liquidity Layer (paid from borrowers) for token0 of the dex pair * rate.liquidity.token1: interest earned by lenders at the Liquidity Layer (paid from borrowers) for token1 of the dex pair * rate.dex.trading: smart lending dex pool APR earned through swap fees * rate.lending.rate: smart lending rewards or fee rate If positive then rewards, if negative then fee. 1e6 = 100%, 1e4 = 1%, minimum 0.0001% fee or reward. Absolute percent APR that increases/decreases the SmartLending ERC20 token exchange rate to the underlying dex shares. * rewards array (optional): all other rewards, only present if any exist. More info see [Lendings (fTokens)](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#lendings-ftokens) #### on-chain (without merkle rewards and dex trading APR) [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#on-chain-without-merkle-rewards-and-dex-trading-apr-1) Dex trading APR and merkle rewards info is only available via API. The SmartLendingResolver contract methods like `getSmartLendingEntireData` (also see [docs](https://docs.fluid.instadapp.io/autogenerated-docs/periphery/resolvers/smartLending/main.html#getSmartLendingEntireData) ) include all APR info incl. rewards. The returned struct `SmartLendingEntireData` has the following fields: * feeOrReward: The fee or reward rate for the SmartLending itself. If positive then rewards, if negative then fee. 1e6 = 100%, 1e4 = 1%, minimum 0.0001%. Absolute percent APR that increases/decreases the SmartLending ERC20 token exchange rate to the underlying dex shares. * dexEntireData.limitsAndAvailability: The struct `SwapLimitsAndAvailability` includes the info for each token in the liquidityTokenData0 and liquidityTokenData1 returned `OverallTokenData` structs -> "supplyRate" and "borrowRate". These values refer to the rates earned as lenders or paid as borrowers at the LL. Note that this is not set when using the "View" methods like `getSmartLendingEntireViewData`! Claim Merkle Rewards [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#claim-merkle-rewards) ---------------------------------------------------------------------------------------------------------------------- Use `https://merkle.api.fluid.instadapp.io/programs//users//claims` to fetch the merkle rewards related data (claimable amount, merkle proofs and cycle). Call the `claim` method on the merkle distributor contract (refer to the distributor addresses [here](https://github.com/Instadapp/fluid-contracts-public/blob/main/deployments/deployments.md#merkledistributor) ) with the following params: * `recipient_` : The user address (should be the owner of the position). * `cumulativeAmount_` : The `cumulativeAmount_` (in wei) from the claim API data. * `positionId_` : * For Borrow - The NFT id of the position (should be converted to bytes32). * For Lending - The positionId is same as the fToken address. * `cycle_` : `cycle_` from the claim API data. * `merkleProof_` : Merkle proof from the claim API data. #### How to find the `programId` to be used in the claims API? [​](https://docs.fluid.instadapp.io/integrate/lend-borrow-yield-rates.html#how-to-find-the-programid-to-be-used-in-the-claims-api) * For Lending (fTokens): Use the API `https://api.fluid.instadapp.io/v2/lending//tokens` and find the `programId` metadata under rewards\[\] from the response. * For Vaults: Use the API `https://api.fluid.instadapp.io/v2/borrowing//vaults/` and find the `programId` metadata under rewards\[\] from the response. --- # Errors structure | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/errors-structure.html#VPContent) Return to top Errors structure [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#errors-structure) ======================================================================================================= In Fluid, errors are organized systematically to enhance clarity and ease of reference. Each protocol or module within a protocol has its dedicated set of error definitions and types. Error IDs Specification [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#error-ids-specification) --------------------------------------------------------------------------------------------------------------------- To maintain consistency and avoid clashes, we follow a unique numbering system for error IDs. Each protocol or even each contract within a protocol gets a distinct range. For instance: * **Liquidity Protocol**: * **Liquidity UserModule module:** 10001, 10002, 10003, etc. * **Liquidity AdminModule module:** 11001, 11002, 11003, etc. * **Lending Protocol**: * **Lending fToken module:** 20001, 20002, 20003, etc. * **Lending LendingFactory module:** 21001, 21002, etc. By adhering to this structure, developers can easily trace errors back to their source module and protocol, simplifying debugging and maintenance. Error ID Ranges [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#error-id-ranges) ----------------------------------------------------------------------------------------------------- ### 1\. Liquidity Protocol - [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_1-liquidity-protocol) * **Admin Module** - Prefix: AdminModule\_\_: * **Range:** 10001-10999 * **User Module** - Prefix: UserModule\_\_: * **Range:** 11001-11999 * **Helpers** - Prefix: LiquidityHelpers\_\_: * **Range:** 12001-12999 ### 2\. Lending Protocol [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_2-lending-protocol) * **fToken Module** - Prefix: fToken\_\_: * **Range:** 20001-20999 * **fToken Native Underlying Module** - Prefix: fTokenNativeUnderlying\_\_: * **Range:** 21001-21999 * **Lending Factory Module** - Prefix: LendingFactory\_\_: * **Range:** 22001-22999 * **Lending Rewards Rate Model Module** - Prefix: LendingRewardsRateModel\_\_: * **Range:** 23001-23999 ### 3\. Vault Protocol [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_3-vault-protocol) * **Vault Factory Module** - Prefix: VaultFactory\_\_: * **Range:** 30001-30999 * **VaultT1 Module** - Prefix: VaultT1\_\_: * **Range:** 31001-31999 * **ERC721 Module** - Prefix: ERC721\_\_: * **Range:** 32001-32999 * **VaultT1 Admin** - Prefix: VaultT1Admin\_\_: * **Range:** 33001-33999 * **Vault Rewards** - Prefix: VaultRewards\_\_: * **Range:** 34001-34999 * **Vault Dex** - Prefix: VaultDex\_\_: * **Range:** 35001-35999 * **Vault Borrow Rewards** - Prefix: VaultBorrowRewards\_\_: * **Range:** 36001-36010 ### 4\. StETH Protocol - Prefix: StETH\_\_ [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_4-steth-protocol-prefix-steth) * **Range:** 40001-40999 ### 5\. InfiniteProxy / DEX protocol [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_5-infiniteproxy-dex-protocol) * **InfiniteProxy** - Prefix: InfiniteProxy\_\_: * **Range:** 50001-50999 * **DexT1** - Prefix: DexT1\_\_: * **Range:** 51001-51999 * **DexT1Admin** - Prefix: DexT1Admin\_\_: * **Range:** 52001-52999 * **DexFactory** - Prefix: DexFactory\_\_: * **Range:** 53001-53999 ### 6\. Oracles [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_6-oracles) * **FluidOracleL2** - Prefix: FluidOracleL2\_\_: * **Range:** 60000 * **UniV3CheckCLRSOracle oracle** - Prefix: UniV3CheckCLRSOracle\_\_: * **Range:** 60001-60009 * **FluidOracle** - Prefix: FluidOracle\_\_: * **Range:** 60010 * **sUSDe oracle** - Prefix: SUSDeOracle\_\_: * **Range:** 60101-60199 * **Pendle oracle** - Prefix: PendleOracle\_\_: * **Range:** 60201-60299 * **CLRS2UniV3CheckCLRSOracleL2** - Prefix: CLRS2UniV3CheckCLRSOracleL2\_\_: * **Range:** 60301-60310 * **Ratio2xFallbackCLRSOracleL2** - Prefix: Ratio2xFallbackCLRSOracleL2\_\_: * **Range:** 60311-60320 * **WeETHsOracle** - Prefix: WeETHsOracle\_\_: * **Range:** 60321-60330 * **DexSmartColOracle** - Prefix: DexSmartColOracle\_\_: * **Range:** 60331-60340 * **DexSmartDebtOracle** - Prefix: DexSmartDebtOracle\_\_: * **Range:** 60341-60350 * **ContractRate** - Prefix: ContractRate\_\_: * **Range:** 60351-60360 * **SUSDsOracle** - Prefix: SUSDsOracle\_\_: * **Range:** 60361-60370 * **PegOracle** - Prefix: PegOracle\_\_: * **Range:** 60371-60380 * **Chainlink oracle** - Prefix: ChainlinkOracle\_\_: * **Range:** 61001-61999 * **UniV3Oracle oracle** - Prefix: UniV3Oracle\_\_: * **Range:** 62001-62999 * **WstETh oracle** - Prefix: WstETHOracle\_\_: * **Range:** 63001-63999 * **Redstone oracle** - Prefix: RedstoneOracle\_\_: * **Range:** 64001-64999 * **Fallback oracle** - Prefix: FallbackOracle\_\_: * **Range:** 65001-65999 * **FallbackCLRS oracle** - Prefix: FallbackCLRSOracle\_\_: * **Range:** 66001-66999 * **WstETHCLRS oracle** - Prefix: WstETHCLRSOracle\_\_: * **Range:** 67001-67999 * **CLFallbackUniV3 oracle** - Prefix: CLFallbackUniV3Oracle\_\_: * **Range:** 68001-68999 * **WstETHCLRS2UniV3CheckCLRS oracle** - Prefix: WstETHCLRS2UniV3CheckCLRSOracle\_\_: * **Range:** 69001-69999 * **WeETH oracle** - Prefix: WeETHOracle\_\_: * **Range:** 70001-79999 ### 7\. Libraries [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_7-libraries) * **LiquidityCalcs** - Prefix: LiquidityCalcs\_\_: * **Range:** 70001-70999 * **SafeTransfer** - Prefix: SafeTransfer\_\_: * **Range:** 71001-71999 ### 8\. Flashloan Protocol - Prefix: FlashLender\_\_ [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_8-flashloan-protocol-prefix-flashlender) * **Range:** 80001-80999 ### 9\. Reserve Contract - Prefix: ReserveContract\_\_ [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_9-reserve-contract-prefix-reservecontract) * **Range:** 90001-90999 ### 10\. Configs [​](https://docs.fluid.instadapp.io/integrate/errors-structure.html#_10-configs) * **ExpandPercentConfigHandler** - Prefix: ExpandPercentConfigHandler\_\_: * **Range:** 100001-100009 * **EthenaRateConfigHandler** - Prefix: EthenaRateConfigHandler\_\_: * **Range:** 100011-100019 * **MaxBorrowConfigHandler** - Prefix: MaxBorrowConfigHandler\_\_: * **Range:** 100021-100029 * **BufferRateConfigHandler** - Prefix: BufferRateConfigHandler\_\_: * **Range:** 100031-100039 * **RatesAuth** - Prefix: RatesAuth\_\_; * **Range:** 100041-100045 * **ListTokenAuthHandler** - Prefix: ListTokenAuth\_\_: * **Range:** 100051-100053 * **CollectRevenueAuth** - Prefix: CollectRevenueAuth\_\_: * **Range:** 100061-100062 * **WithdrawLimitAuth** - Prefix: WithdrawLimitAuth\_\_: * **Range:** 100071-100076 --- # Fluid DEX Lite: Liquidity Source Integration | Fluid Technical Docs [Skip to content](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#VPContent) Return to top Fluid DEX Lite: Liquidity Source Integration [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#fluid-dex-lite-liquidity-source-integration) ============================================================================================================================================================ Complete integration guide for adding Fluid DEX Lite as a liquidity source in DEX aggregators and routing protocols. Table of Contents [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#table-of-contents) ------------------------------------------------------------------------------------------------------- 1. [Overview](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#overview) 2. [Quick Start](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#quick-start) 3. [Integration Methods](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#integration-methods) 4. [Pool Discovery & State Reading](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#pool-discovery--state-reading) 5. [Price Estimation](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#price-estimation) 6. [Swap Execution](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#swap-execution) 7. [Gas Optimization](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#gas-optimization) 8. [Legacy Integration](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#legacy-integration) 9. [Best Practices](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#best-practices) 10. [Resources](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#resources) * * * Overview [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#overview) ------------------------------------------------------------------------------------- ### What is Fluid DEX Lite? [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#what-is-fluid-dex-lite) Fluid DEX Lite is an ultra-gas-optimized DEX specialized for correlated asset pairs, featuring: * **Ultra-Low Gas**: ~10k gas per swap (most efficient on Ethereum) * **Singleton Architecture**: Multiple pools under one contract for efficient multi-hop routing * **Easy Integration**: Comprehensive resolver contract with clean APIs * **Multi-hop Support**: Native support for complex routing paths ### Architecture [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#architecture) * **Core Contract**: `FluidDexLite` - Handles all swaps and pool state * **Resolver Contract**: `FluidDexLiteResolver` - Provides discovery, state reading, and estimation APIs * **Storage**: Packed storage design for gas optimization * **Pools**: Governance-controlled pool launches for correlated pairs * * * Quick Start [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#quick-start) ------------------------------------------------------------------------------------------- ### 1\. Integration Method [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#_1-integration-method) **Standard: Resolver-based Integration** * Use `FluidDexLiteResolver` for discovery, state reading, and estimation * Clean APIs, no storage manipulation required * Gas-free price estimation * This is the recommended approach for all new integrations **Note**: This guide also includes a legacy section for integrators who have already implemented direct contract integration. ### 2\. Core Data Structures [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#_2-core-data-structures) solidity struct DexKey { address token0; // Lexicographically smaller token address token1; // Lexicographically larger token bytes32 salt; // Pool salt } struct DexState { DexVariables dexVariables; CenterPriceShift centerPriceShift; RangeShift rangeShift; ThresholdShift thresholdShift; } struct DexVariables { uint256 fee; uint256 revenueCut; uint256 rebalancingStatus; bool isCenterPriceShiftActive; uint256 centerPrice; address centerPriceAddress; bool isRangePercentShiftActive; uint256 upperRangePercent; uint256 lowerRangePercent; bool isThresholdPercentShiftActive; uint256 upperShiftThresholdPercent; uint256 lowerShiftThresholdPercent; uint256 token0Decimals; uint256 token1Decimals; uint256 totalToken0AdjustedAmount; uint256 totalToken1AdjustedAmount; } struct CenterPriceShift { uint256 lastInteractionTimestamp; uint256 rebalancingShiftingTime; uint256 maxCenterPrice; uint256 minCenterPrice; uint256 shiftPercentage; uint256 centerPriceShiftingTime; uint256 startTimestamp; } struct RangeShift { uint256 oldUpperRangePercent; uint256 oldLowerRangePercent; uint256 shiftingTime; uint256 startTimestamp; } struct ThresholdShift { uint256 oldUpperThresholdPercent; uint256 oldLowerThresholdPercent; uint256 shiftingTime; uint256 startTimestamp; } struct Prices { uint256 poolPrice; uint256 centerPrice; uint256 upperRangePrice; uint256 lowerRangePrice; uint256 upperThresholdPrice; uint256 lowerThresholdPrice; } struct Reserves { uint256 token0RealReserves; uint256 token1RealReserves; uint256 token0ImaginaryReserves; uint256 token1ImaginaryReserves; } ### 3\. Contract Addresses [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#_3-contract-addresses) | Network | Contract | Address | | --- | --- | --- | | Ethereum Mainnet | FluidDexLite | `0xBbcb91440523216e2b87052A99F69c604A7b6e00` | | Ethereum Mainnet | FluidDexLiteResolver (v1.0.0) | `0x26b696D0dfDAB6c894Aa9a6575fCD07BB25BbD2C` | * * * Integration Methods [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#integration-methods) ----------------------------------------------------------------------------------------------------------- ### Resolver-based Integration (Recommended) [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#resolver-based-integration-recommended) Use the resolver contract for all discovery, state reading, and estimation operations. #### Key Methods [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#key-methods) solidity contract FluidDexLiteResolver { // Pool Discovery function getAllDexes() public view returns (DexKey[] memory); // State Reading function getDexState(DexKey memory dexKey) public view returns (DexState memory); function getPricesAndReserves(DexKey memory dexKey) public returns (Prices memory, Reserves memory); function getDexEntireData(DexKey memory dexKey) public returns (DexEntireData memory); function getAllDexesEntireData() public returns (DexEntireData[] memory); // Price Estimation (Gas-free) function estimateSwapSingle(DexKey calldata dexKey, bool swap0To1, int256 amountSpecified) public returns (uint256); function estimateSwapHop(address[] calldata path, DexKey[] calldata dexKeys, int256 amountSpecified) public returns (uint256); } #### Basic Integration Example [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#basic-integration-example) solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.29; import "contracts/periphery/resolvers/dexLite/main.sol"; contract FluidDexLiteIntegrator { FluidDexLiteResolver constant resolver = FluidDexLiteResolver( 0x26b696D0dfDAB6c894Aa9a6575fCD07BB25BbD2C ); function getPoolData() external returns ( uint256 poolCount, bytes8 firstDexId, uint256 poolPrice, uint256 token0Reserves, uint256 token1Reserves ) { // Discover all pools DexKey[] memory dexes = resolver.getAllDexes(); poolCount = dexes.length; if (poolCount > 0) { // Get complete data for first pool DexEntireData memory data = resolver.getDexEntireData(dexes[0]); firstDexId = data.dexId; poolPrice = data.prices.poolPrice; token0Reserves = data.reserves.token0RealReserves; token1Reserves = data.reserves.token1RealReserves; } } function estimateSwap( DexKey memory dexKey, bool swap0To1, uint256 amountIn ) external returns (uint256 amountOut) { return resolver.estimateSwapSingle(dexKey, swap0To1, int256(amountIn)); } } * * * Pool Discovery & State Reading [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#pool-discovery-state-reading) ------------------------------------------------------------------------------------------------------------------------------- ### Discovering Available Pools [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#discovering-available-pools) solidity function discoverPools() external view returns (DexKey[] memory pools) { pools = resolver.getAllDexes(); // Each pool is identified by DexKey with: // - token0: lexicographically smaller token address // - token1: lexicographically larger token address // - salt: unique identifier (typically 0x00...) } ### Reading Pool State [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#reading-pool-state) solidity function readPoolDetails(DexKey memory dexKey) external returns ( uint256 fee, uint256 poolPrice, uint256 token0Decimals, uint256 token1Decimals, uint256 realReserves0, uint256 realReserves1 ) { // Get complete pool data DexEntireData memory data = resolver.getDexEntireData(dexKey); fee = data.dexState.dexVariables.fee; poolPrice = data.prices.poolPrice; token0Decimals = data.dexState.dexVariables.token0Decimals; token1Decimals = data.dexState.dexVariables.token1Decimals; realReserves0 = data.reserves.token0RealReserves; realReserves1 = data.reserves.token1RealReserves; } ### Batch Reading All Pools [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#batch-reading-all-pools) solidity function readAllPoolsData() external returns (DexEntireData[] memory) { // Get complete data for all pools in one call return resolver.getAllDexesEntireData(); } * * * Price Estimation [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#price-estimation) ----------------------------------------------------------------------------------------------------- ### Single Pool Estimation [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#single-pool-estimation) solidity function estimateSingleSwap( DexKey memory dexKey, bool swap0To1, uint256 amountIn ) external returns (uint256 amountOut) { // Gas-free estimation using resolver amountOut = resolver.estimateSwapSingle( dexKey, swap0To1, int256(amountIn) // Positive for exact input ); } function estimateExactOutput( DexKey memory dexKey, bool swap0To1, uint256 amountOut ) external returns (uint256 amountIn) { // Estimate required input for exact output amountIn = resolver.estimateSwapSingle( dexKey, swap0To1, -int256(amountOut) // Negative for exact output ); } ### Multi-hop Estimation [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#multi-hop-estimation) solidity function estimateMultiHop( address[] memory path, DexKey[] memory dexKeys, uint256 amountIn ) external returns (uint256 amountOut) { // Gas-free multi-hop estimation amountOut = resolver.estimateSwapHop(path, dexKeys, int256(amountIn)); } ### Example: USDC → USDT → DAI [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#example-usdc-%E2%86%92-usdt-%E2%86%92-dai) solidity function estimateUSDCToDAI(uint256 usdcAmount) external returns (uint256 daiAmount) { // Define path: USDC → USDT → DAI address[] memory path = new address[](3); path[0] = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC path[1] = 0xdAC17F958D2ee523a2206206994597C13D831ec7; // USDT path[2] = 0x6B175474E89094C44Da98b954EedeAC495271d0F; // DAI // Define pools for each hop DexKey[] memory dexKeys = new DexKey[](2); dexKeys[0] = DexKey({ token0: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, // USDC-USDT token1: 0xdAC17F958D2ee523a2206206994597C13D831ec7, salt: 0x0000000000000000000000000000000000000000000000000000000000000000 }); dexKeys[1] = DexKey({ token0: 0x6B175474E89094C44Da98b954EedeAC495271d0F, // USDT-DAI token1: 0xdAC17F958D2ee523a2206206994597C13D831ec7, salt: 0x0000000000000000000000000000000000000000000000000000000000000000 }); daiAmount = resolver.estimateSwapHop(path, dexKeys, int256(usdcAmount)); } * * * Swap Execution [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#swap-execution) ------------------------------------------------------------------------------------------------- After estimation, execute swaps through the core FluidDexLite contract. ### Single Pool Swap [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#single-pool-swap) solidity interface IFluidDexLite { function swapSingle( DexKey calldata dexKey, bool swap0To1, int256 amountSpecified, uint256 amountLimit, address to, bool isCallback, bytes calldata callbackData, bytes calldata extraData ) external payable returns (uint256 amountUnspecified); } function executeSwap( DexKey memory dexKey, bool swap0To1, uint256 amountIn, uint256 minAmountOut, address recipient ) external { IFluidDexLite dexLite = IFluidDexLite(0xBbcb91440523216e2b87052A99F69c604A7b6e00); // Execute swap uint256 amountOut = dexLite.swapSingle( dexKey, swap0To1, int256(amountIn), // Exact input amount minAmountOut, // Minimum output (slippage protection) recipient, // Token recipient false, // No callback "", // No callback data "" // No extra data ); } ### Multi-hop Swap [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#multi-hop-swap) solidity struct TransferParams { address to; bool isCallback; bytes callbackData; bytes extraData; } function executeMultiHop( address[] memory path, DexKey[] memory dexKeys, uint256 amountIn, uint256 minAmountOut, address recipient ) external { IFluidDexLite dexLite = IFluidDexLite(0xBbcb91440523216e2b87052A99F69c604A7b6e00); // Set amount limits for each hop (0 = no limit except final) uint256[] memory amountLimits = new uint256[](dexKeys.length); amountLimits[amountLimits.length - 1] = minAmountOut; // Final output limit TransferParams memory transferParams = TransferParams({ to: recipient, isCallback: false, callbackData: "", extraData: "" }); uint256 finalAmount = dexLite.swapHop( path, dexKeys, int256(amountIn), amountLimits, transferParams ); } * * * Gas Optimization [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#gas-optimization) ----------------------------------------------------------------------------------------------------- ### Callback Pattern [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#callback-pattern) Implement callbacks to save ~5k gas per swap by optimizing token transfers. solidity interface IDexLiteCallback { function dexCallback(address token, uint256 amount, bytes calldata data) external; } contract OptimizedIntegrator is IDexLiteCallback { address constant FLUID_DEX_LITE = 0xBbcb91440523216e2b87052A99F69c604A7b6e00; function executeOptimizedSwap( DexKey memory dexKey, bool swap0To1, uint256 amountIn, uint256 minAmountOut ) external { IFluidDexLite(FLUID_DEX_LITE).swapSingle( dexKey, swap0To1, int256(amountIn), minAmountOut, msg.sender, true, // Enable callback "", "" ); } function dexCallback(address token, uint256 amount, bytes calldata) external override { require(msg.sender == FLUID_DEX_LITE, "Unauthorized"); // Transfer tokens to DEX contract IERC20(token).transferFrom(tx.origin, FLUID_DEX_LITE, amount); } } ### Multi-hop Optimization [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#multi-hop-optimization) Use `swapHop` instead of multiple separate swaps to save gas on intermediate token transfers. * * * Legacy Integration [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#legacy-integration) --------------------------------------------------------------------------------------------------------- ### Direct Contract Integration [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#direct-contract-integration) For existing integrations using direct contract interaction: #### Storage-based Pool Discovery [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#storage-based-pool-discovery) solidity // Read pool count uint256 poolCount = uint256(fluidDexLite.readFromStorage(bytes32(1))); // Read DexKey at index function readDexKeyAtIndex(uint256 index) view returns (DexKey memory) { bytes32 baseSlot = keccak256(abi.encode(1)); address token0 = address(uint160(uint256( fluidDexLite.readFromStorage(bytes32(uint256(baseSlot) + index * 3)) ))); address token1 = address(uint160(uint256( fluidDexLite.readFromStorage(bytes32(uint256(baseSlot) + index * 3 + 1)) ))); bytes32 salt = fluidDexLite.readFromStorage( bytes32(uint256(baseSlot) + index * 3 + 2) ); return DexKey(token0, token1, salt); } #### Manual Estimation Pattern [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#manual-estimation-pattern) solidity bytes32 constant ESTIMATE_SWAP = keccak256("ESTIMATE_SWAP"); try fluidDexLite.swapSingle( dexKey, swap0To1, int256(amountIn), 0, address(0), false, "", abi.encode(ESTIMATE_SWAP) ) { revert("Should not succeed"); } catch (bytes memory reason) { if (reason.length >= 36) { bytes4 selector = bytes4(reason); if (selector == bytes4(keccak256("EstimateSwap(uint256)"))) { assembly { amountOut := mload(add(reason, 36)) } } } } * * * Best Practices [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#best-practices) ------------------------------------------------------------------------------------------------- ### Gas Optimization [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#gas-optimization-1) 1. Implement callback pattern for swap execution 2. Batch multi-hop swaps using `swapHop` ### Error Handling [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#error-handling) 1. Always use try-catch for estimation 2. Implement proper slippage protection 3. Handle edge cases (zero liquidity, large swaps) ### Security [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#security) 1. Validate all DexKey parameters 2. Use proper slippage calculations 3. Implement deadline checks 4. Verify callback caller authenticity * * * Resources [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#resources) --------------------------------------------------------------------------------------- ### Documentation [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#documentation) * [General Fluid Docs](https://docs.fluid.instadapp.io/) * [DEX Blog Post](https://gov.fluid.io/t/introducing-fluid-dex-lite/1665) * [Math Derivations](https://app.excalidraw.com/l/12EMdhpNZfV/1jzaWnLnu4H) ### Production Implementations [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#production-implementations) 1. **ParaSwap Integration** (TypeScript) * Repository: [VeloraDEX/paraswap-dex-lib](https://github.com/VeloraDEX/paraswap-dex-lib/tree/master/src/dex/fluid-dex-lite) * Features: Complete integration with pool discovery, pricing, and execution 2. **KyberSwap Integration** (Golang) * Repository: [KyberNetwork/kyberswap-dex-lib](https://github.com/KyberNetwork/kyberswap-dex-lib/tree/main/pkg/liquidity-source/fluid/dex-lite) * Features: High-performance integration with comprehensive testing ### Contract Addresses [​](https://docs.fluid.instadapp.io/integrate/dex-lite-swaps.html#contract-addresses) | Network | Contract | Address | | --- | --- | --- | | Ethereum Mainnet | FluidDexLite | `0xBbcb91440523216e2b87052A99F69c604A7b6e00` | | Ethereum Mainnet | FluidDexLiteResolver (v1.0.0) | `0x26b696D0dfDAB6c894Aa9a6575fCD07BB25BbD2C` | * * * ---