ShibaSwap v2’s concentrated liquidity system rewards liquidity providers based on their position’s effectiveness within specific price ranges and time spent in range.
Rewards are proportional to liquidity share, time in range, and the effectiveness of your position’s price range.

Concentrated Liquidity Reward Mechanisms

Fee Distribution Algorithm

Trading fees are distributed proportionally based on liquidity share and time in range:
contracts/LiquidityRewards.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract ConcentratedLiquidityRewards {
    // Fee growth tracking for concentrated liquidity
    struct FeeGrowthInfo {
        uint256 feeGrowthGlobal0X128;
        uint256 feeGrowthGlobal1X128;
        uint256 feeGrowthOutside0X128;
        uint256 feeGrowthOutside1X128;
        uint256 feeGrowthInside0LastX128;
        uint256 feeGrowthInside1LastX128;
    }
    
    // Position information for reward calculation
    struct PositionInfo {
        uint256 tokenId;
        uint128 liquidity;
        int24 tickLower;
        int24 tickUpper;
        uint256 feeGrowthInside0LastX128;
        uint256 feeGrowthInside1LastX128;
        uint128 tokensOwed0;
        uint128 tokensOwed1;
    }
    
    // Calculate fees earned by a concentrated liquidity position
    function calculatePositionFees(
        PositionInfo memory position,
        FeeGrowthInfo memory feeGrowth
    ) public pure returns (uint256 fee0, uint256 fee1) {
        // Calculate fee growth inside the position's tick range
        uint256 feeGrowthInside0X128 = feeGrowth.feeGrowthGlobal0X128 - feeGrowth.feeGrowthOutside0X128;
        uint256 feeGrowthInside1X128 = feeGrowth.feeGrowthGlobal1X128 - feeGrowth.feeGrowthOutside1X128;
        
        // Calculate fees earned since last update
        uint256 feeGrowthInside0DeltaX128 = feeGrowthInside0X128 - position.feeGrowthInside0LastX128;
        uint256 feeGrowthInside1DeltaX128 = feeGrowthInside1X128 - position.feeGrowthInside1LastX128;
        
        // Calculate actual fees earned
        fee0 = (feeGrowthInside0DeltaX128 * position.liquidity) / 2**128;
        fee1 = (feeGrowthInside1DeltaX128 * position.liquidity) / 2**128;
    }
    
    // Calculate reward multiplier based on time in range
    function calculateTimeInRangeMultiplier(
        uint256 timeInRange,
        uint256 totalTime
    ) public pure returns (uint256 multiplier) {
        if (timeInRange >= totalTime * 90 / 100) {
            return 2; // 2x for 90%+ time in range
        } else if (timeInRange >= totalTime * 75 / 100) {
            return 15; // 1.5x for 75%+ time in range
        } else if (timeInRange >= totalTime * 50 / 100) {
            return 12; // 1.2x for 50%+ time in range
        } else {
            return 1; // 1x for less than 50% time in range
        }
    }
    
    // Calculate concentrated liquidity effectiveness
    function calculateLiquidityEffectiveness(
        uint128 liquidity,
        uint256 totalLiquidity,
        uint256 timeInRange
    ) public pure returns (uint256 effectiveness) {
        // Base effectiveness is proportional to liquidity share
        uint256 baseEffectiveness = (liquidity * 1e18) / totalLiquidity;
        
        // Apply time in range multiplier
        uint256 timeMultiplier = calculateTimeInRangeMultiplier(timeInRange, 365 days);
        
        effectiveness = (baseEffectiveness * timeMultiplier) / 1e18;
    }
}

Fee Collection and Distribution

Concentrated liquidity positions automatically collect fees as trades occur within their price range.
contracts/FeeCollection.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract FeeCollection {
    // Fee collection for concentrated liquidity positions
    function collectFees(
        uint256 tokenId,
        uint128 amount0Max,
        uint128 amount1Max
    ) external returns (uint128 amount0, uint128 amount1) {
        // Get position information
        PositionInfo memory position = getPosition(tokenId);
        
        // Calculate fees earned
        (uint256 fee0, uint256 fee1) = calculatePositionFees(position, getCurrentFeeGrowth());
        
        // Limit collection to requested amounts
        amount0 = uint128(fee0 > amount0Max ? amount0Max : fee0);
        amount1 = uint128(fee1 > amount1Max ? amount1Max : fee1);
        
        // Update position's fee tracking
        updatePositionFees(tokenId, amount0, amount1);
        
        // Transfer fees to recipient
        if (amount0 > 0) {
            transferToken0(msg.sender, amount0);
        }
        if (amount1 > 0) {
            transferToken1(msg.sender, amount1);
        }
    }
    
    // Calculate total fees earned by a position
    function getPositionFees(uint256 tokenId) external view returns (uint256 fee0, uint256 fee1) {
        PositionInfo memory position = getPosition(tokenId);
        return calculatePositionFees(position, getCurrentFeeGrowth());
    }
    
    // Get current fee growth for the pool
    function getCurrentFeeGrowth() internal view returns (FeeGrowthInfo memory) {
        // This would interface with the actual pool contract
        // to get current fee growth values
    }
}

Reward Calculation

Fee Distribution Formula

Fees are distributed based on the following formula:
Fees = (FeeGrowthInside * Liquidity) / 2^128
Where:
  • FeeGrowthInside = Global fee growth - Fee growth outside position range
  • Liquidity = Position’s liquidity amount
  • 2^128 = Fixed-point precision factor

Time-in-Range Multipliers

Positions earn bonus multipliers based on time spent in range:
Time in RangeMultiplierDescription
90%+2.0xMaximum bonus for consistent in-range positions
75%+1.5xHigh bonus for mostly in-range positions
50%+1.2xModerate bonus for balanced positions
Less than 50%1.0xBase rate for out-of-range positions

Position Effectiveness

The effectiveness of a concentrated liquidity position is calculated as:
Effectiveness = (Liquidity Share * Time Multiplier) / Total Pool Liquidity
This rewards positions that:
  • Provide liquidity in high-traffic price ranges
  • Maintain consistent in-range status
  • Contribute significant liquidity relative to the pool

## Fee Growth Tracking

The fee growth tracking system ensures accurate fee distribution:

```solidity contracts/FeeGrowthTracker.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract FeeGrowthTracker {
    // Global fee growth for the entire pool
    uint256 public feeGrowthGlobal0X128;
    uint256 public feeGrowthGlobal1X128;
    
    // Fee growth outside specific tick ranges
    mapping(int24 => uint256) public feeGrowthOutside0X128;
    mapping(int24 => uint256) public feeGrowthOutside1X128;
    
    // Update global fee growth when swaps occur
    function updateFeeGrowth(uint256 fee0, uint256 fee1, uint128 liquidity) external {
        if (liquidity > 0) {
            feeGrowthGlobal0X128 += (fee0 * 2**128) / liquidity;
            feeGrowthGlobal1X128 += (fee1 * 2**128) / liquidity;
        }
    }
    
    // Calculate fee growth inside a tick range
    function getFeeGrowthInside(
        int24 tickLower,
        int24 tickUpper,
        int24 tickCurrent
    ) external view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) {
        if (tickCurrent < tickLower) {
            // Current tick is below the range
            feeGrowthInside0X128 = feeGrowthOutside0X128[tickLower] - feeGrowthOutside0X128[tickUpper];
            feeGrowthInside1X128 = feeGrowthOutside1X128[tickLower] - feeGrowthOutside1X128[tickUpper];
        } else if (tickCurrent >= tickUpper) {
            // Current tick is above the range
            feeGrowthInside0X128 = feeGrowthOutside0X128[tickUpper] - feeGrowthOutside0X128[tickLower];
            feeGrowthInside1X128 = feeGrowthOutside1X128[tickUpper] - feeGrowthOutside1X128[tickLower];
        } else {
            // Current tick is inside the range
            feeGrowthInside0X128 = feeGrowthGlobal0X128 - feeGrowthOutside0X128[tickLower] - feeGrowthOutside0X128[tickUpper];
            feeGrowthInside1X128 = feeGrowthGlobal1X128 - feeGrowthOutside1X128[tickLower] - feeGrowthOutside1X128[tickUpper];
        }
    }
}

Best Practices

1

Choose optimal price ranges

Concentrate liquidity around current price for maximum fee earnings.
Use the ShibaSwap interface to visualize optimal price ranges and liquidity distribution.
2

Monitor position status

Regularly check if your position is still in range and earning fees.
Out-of-range positions don’t earn fees and may suffer impermanent loss.
3

Collect fees regularly

Collect accumulated fees to compound your earnings.
Regular fee collection helps maximize your returns from concentrated liquidity.
4

Optimize range width

Balance between fee earnings and impermanent loss risk.
Narrower ranges earn more fees but have higher impermanent loss risk.

Concentrated Liquidity Optimization