ChainScore Labs
LABS
Guides

Range Orders Implemented Through Concentrated Liquidity

Chainscore © 2025
concepts

Core Concepts

Foundational principles of concentrated liquidity and its application for executing range orders on decentralized exchanges.

01

Concentrated Liquidity

Concentrated liquidity allows liquidity providers (LPs) to allocate capital within a specific price range rather than the full 0 to ∞ curve. This dramatically increases capital efficiency, enabling deeper liquidity and lower slippage for trades within the range. LPs earn fees only when the asset price is within their chosen bounds, concentrating their exposure and potential returns.

02

Liquidity Position

A liquidity position is a discrete deposit of two assets within a defined price range on an Automated Market Maker (AMM). It is represented as a non-fungible token (NFT) on platforms like Uniswap V3. The position's value changes based on the current price relative to its range, and it accrues trading fees proportionally to its share of liquidity within the active tick.

03

Price Ticks

Price ticks are the discrete, spaced price points that define the possible boundaries for a liquidity range. Each tick has an index, and the tick spacing is a protocol parameter (e.g., 0.01% for a 0.3% fee pool). Liquidity can only be provided between ticks, which simplifies computation and gas costs. This granularity allows for precise range order placement.

04

Range Order Strategy

A range order is a passive trading strategy implemented by providing single-asset liquidity at the extremes of a price range. For example, depositing only ETH in a range above the current price creates a limit sell order. If the price rises into the range, the ETH is gradually sold for the other asset. This automates DCA exits or entries without active monitoring.

05

Impermanent Loss (Divergence Loss)

Impermanent loss is the opportunity cost incurred when the value of assets in a liquidity pool diverges from simply holding them. In concentrated liquidity, this risk is magnified but targeted. If the price moves outside a narrow range, the position becomes 100% of the less valuable asset, realizing the loss. This is the key risk/reward trade-off for range orders.

06

Fee Tier Selection

Fee tiers are preset percentages (e.g., 0.01%, 0.05%, 0.3%, 1%) that determine the swap fee taken from trades and distributed to LPs. Selecting a tier involves balancing expected volume against competition. Higher fees protect against impermanent loss from volatile, arbitrage-heavy pairs, while lower fees attract high-volume, stable pairs. This choice directly impacts range order profitability.

How Range Orders are Implemented

Process overview

1

Define the Price Range and Deposit Assets

Set the upper and lower bounds for liquidity provision and fund the position.

Detailed Instructions

A range order is created by specifying an active liquidity price interval (tickLower and tickUpper) where you are willing to trade. This range is defined in terms of the pool's price, often represented as a square root price. For a USDC/ETH pool, you might set a range from 1500 to 2500 USDC per ETH. You then deposit a single asset, typically the one you expect to appreciate. If you deposit ETH into this range, you are effectively placing a limit order to sell ETH for USDC if the price rises. The deposited amount determines the initial liquidity depth. The protocol calculates the required amounts of both tokens for the chosen range, but as a single-sided deposit, the other token amount starts at zero.

  • Sub-step 1: Call mint on the pool's manager contract with parameters for tickLower, tickUpper, and amount0Desired or amount1Desired.
  • Sub-step 2: The contract calculates the proportional liquidity (L) value you will receive based on the current price and your deposit.
  • Sub-step 3: Approve the token transfer and confirm the transaction, receiving an NFT representing your concentrated liquidity position.
solidity
// Example call to mint a position (conceptual) INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ token0: USDC, token1: WETH, fee: 3000, // 0.3% tier tickLower: getTickForPrice(1500), tickUpper: getTickForPrice(2500), amount0Desired: 0, // Depositing only ETH amount1Desired: 1 ether, ... });

Tip: Use a tick calculator to translate your target prices into tick indices, as pools store liquidity in discrete tick spaces.

2

Liquidity Becomes Active and Swaps Occur

Your deposited capital is used for swaps as the market price enters your specified range.

Detailed Instructions

Once deposited, your liquidity is active only when the pool's current price is within your [tickLower, tickUpper] range. Within this range, the liquidity is distributed uniformly, creating a constant product curve. As traders execute swaps against the pool, they interact with your position. If you deposited ETH (token1) and the price is below your range, your position holds only ETH and is inactive. When the market price rises and enters your range, your ETH begins to be sold incrementally for USDC (token0) with each swap that moves the price upward. The mechanism is automated by the pool's swap function, which uses the constant product formula x * y = L^2 within the active tick. The L value from your minting step determines your share of the liquidity in each tick crossed.

  • Sub-step 1: Monitor the pool's current sqrtPriceX96 to see if it has entered your position's range.
  • Sub-step 2: As swaps occur, the contract automatically deducts ETH from your position's reserve and adds USDC to it, following the bonding curve.
  • Sub-step 3: Track the accumulated fees earned from swap volume, which are proportional to your active liquidity share.
solidity
// Core swap logic updates reserves and price function swap( address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes calldata data ) external returns (int256 amount0, int256 amount1) { // ... computes swap, crosses ticks, and updates liquidity positions }

Tip: The rate of asset conversion is not linear; more of your deposited asset is sold as the price approaches the range's upper bound.

3

Manage the Position and Collect Fees

Accumulate earned fees and adjust the position parameters as market conditions change.

Detailed Instructions

While the position is active, you accrue swap fees on all trading volume that occurs within your liquidity range. These fees are stored separately from the principal liquidity and must be manually collected. You can also increase or decrease your liquidity in the position, or modify its price range entirely, which is effectively creating a new position. To collect fees, you call collect on the position manager, specifying the token amounts to withdraw. The contract calculates your pro-rata share of the total fees accrued since the last collection. It's critical to monitor impermanent loss dynamics; as the price moves through your range, your asset composition changes, which may diverge from simply holding the assets.

  • Sub-step 1: Call positions(tokenId) on the manager to read the current tokensOwed0 and tokensOwed1 fee balances.
  • Sub-step 2: Execute the collect function with your tokenId, specifying maximum amounts to withdraw the accrued fees.
  • Sub-step 3: To adjust the range, you must first decreaseLiquidity and then potentially increaseLiquidity on a new set of ticks, which involves a new fee calculation.
solidity
// Collecting accrued fees INonfungiblePositionManager.CollectParams memory params = INonfungiblePositionManager.CollectParams({ tokenId: tokenId, recipient: msg.sender, amount0Max: type(uint128).max, amount1Max: type(uint128).max });

Tip: Frequent collection of fees can be gas-intensive. Consider batching operations or using fee-compounding strategies if available.

4

Close the Position or Let It Execute Fully

Withdraw the remaining assets after the range order is complete or exit early.

Detailed Instructions

A range order executes fully when the market price moves past your upper tick (if you deposited the base asset). At that point, 100% of your initially deposited asset has been swapped for the other asset, and your position holds only the quote asset. Your liquidity is now inactive again, sitting above the current price. To realize the profits and reclaim capital, you must burn the liquidity position NFT. Burning the position withdraws all remaining token reserves and any uncollected fees, destroying the NFT. You can also close the position early at any time by burning it, which will withdraw the current asset composition, which could be a mix of both tokens if the price is mid-range.

  • Sub-step 1: Call decreaseLiquidity to set liquidity to zero, which returns the proportional token amounts based on the current price and range.
  • Sub-step 2: Call collect one final time to withdraw the principal tokens and any remaining fees.
  • Sub-step 3: The position manager automatically burns the NFT upon full liquidation if decreaseLiquidity is called with the entire liquidity value.
solidity
// Decreasing liquidity to zero and collecting INonfungiblePositionManager.DecreaseLiquidityParams memory decParams = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: liquidityAmount, // Set to position's total liquidity amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); // Follow with a CollectParams call

Tip: Always set reasonable amountMin slippage tolerances when decreasing liquidity to protect against front-running in volatile conditions.

Range Order vs. Traditional Limit Order

Comparison of order mechanics, capital efficiency, and risk profiles in concentrated liquidity AMMs.

FeatureRange Order (CL AMM)Traditional Limit Order (CEX)Traditional Limit Order (DEX Aggregator)

Order Type & Execution

Passive liquidity provision within a price range; fills via swap activity against the liquidity pool.

Resting order on a centralized order book; fills via matching with a taker order.

On-chain order routed through multiple liquidity sources; fills via an aggregator's smart contract.

Capital Efficiency

High. Capital is only deployed when price is within the specified range (e.g., $1,900-$2,100 for ETH).

Low. 100% of order capital is locked at the single limit price until filled or cancelled.

Low. 100% of order capital is escrowed on-chain at the single limit price.

Fee Structure

Earns swap fees (e.g., 0.01%-1%) on all trades within the range. May incur gas for position management.

Pays a taker fee (e.g., 0.1%) on fill. No gas cost for order placement on CEX.

Pays a taker fee + network gas costs for order placement and potential execution.

Price Flexibility

Defines an active price range. Can earn fees across the range, not just at a single price point.

Defines a single execution price. No earnings, only a fill at the specified price.

Defines a single execution price. No earnings, only a fill at the specified price.

Impermanent Loss Risk

High. Exposure to divergence loss proportional to the narrowness of the range versus asset volatility.

None. No liquidity provision; pure spot exchange at a set price.

None. No liquidity provision; pure spot exchange at a set price.

Slippage Control

Slippage determined by pool depth within the range. Zero slippage at the range edges if pool is deep.

Slippage determined by order book depth at the limit price. Can experience partial fills.

Slippage minimized by aggregator routing, but depends on final venue liquidity.

Gas Cost Profile

High initial gas for minting/position setup. Ongoing gas for compounding fees or adjusting range.

Negligible (off-chain matching).

High. On-chain transaction required for order placement and settlement.

Use Case

Market making and earning yield on anticipated sideways price action.

Precise entry/exit at a specific price level with no yield component.

Precise on-chain entry/exit, often for larger orders benefiting from aggregated liquidity.

Range Order Strategies

Understanding Range Orders

Range orders allow you to provide liquidity within a specific price range on a DEX like Uniswap V3. Unlike a standard market order, you are not executing a trade immediately. Instead, you are setting a conditional order to buy or sell an asset only when its price enters your specified range. This is a passive strategy that earns fees from swaps occurring within your chosen price band.

Key Points

  • Defined Price Range: You select an upper and lower price bound. Your capital is only active and earning fees when the market price is between these two points.
  • Capital Efficiency: Your liquidity is concentrated where you expect trading to happen, allowing you to earn higher fees with less capital compared to full-range liquidity (like in Uniswap V2).
  • Automated Execution: When the market price moves into your range, the protocol automatically swaps one asset for the other at the current price, effectively executing your "order."

Example

If you believe ETH will trade between $3,000 and $3,500, you can deposit ETH and USDC into a Uniswap V3 pool with that range. If ETH price rises from $2,900 to $3,100, your liquidity becomes active. As traders swap within your range, you earn fees. If ETH price then falls to $2,800, your liquidity is again inactive and consists entirely of ETH, having sold some for USDC on the way down.

Calculating Fees and Impermanent Loss

Process for analyzing profitability and risk in concentrated liquidity range orders.

1

Define the Position and Price Range

Establish the initial parameters for fee and IL calculations.

Detailed Instructions

Begin by defining the position's key parameters. You need the initial deposit amounts for both tokens (e.g., 1 ETH and 2000 USDC), the current pool price (P_current), and the lower and upper ticks (P_lower, P_upper) of your chosen range. The liquidity (L) is derived from these values. For a concentrated liquidity position, the active liquidity is only deployed when the price is within your set range. Calculate the virtual reserves using the constant product formula x = L / sqrt(P) and y = L * sqrt(P) for the token amounts within the range. This establishes the baseline for tracking value changes.

  • Sub-step 1: Record initial token amounts and the pool's current tick.
  • Sub-step 2: Convert your price bounds (e.g., $1800-$2200) into their corresponding tick indices.
  • Sub-step 3: Use a liquidity calculator (like Uniswap V3's SDK) to compute the position's liquidity value from the inputs.
typescript
// Example using Uniswap V3 SDK to get tick and liquidity import { TickMath, Position } from '@uniswap/v3-sdk'; const lowerTick = TickMath.getTickAtSqrtRatio(P_lower); const upperTick = TickMath.getTickAtSqrtRatio(P_upper); const position = new Position({ pool, tickLower: lowerTick, tickUpper: upperTick, liquidity: calculatedLiquidity });

Tip: The initial value of the position is simply the sum of the two token deposits at the current market price.

2

Track Accumulated Fees Over Time

Calculate the fees earned by the position while the price is active.

Detailed Instructions

Fees accrue in real-time as swaps occur through your active price range. You must query the pool contract for the fee growth global variables (feeGrowthGlobal0X128 and feeGrowthGlobal1X128). The fees owed to your position are proportional to your share of liquidity and the difference in these global accumulators since your last interaction. The calculation is: fees_owed = (feeGrowthGlobal - feeGrowthInside_last) * position_liquidity / 2^128. This yields the amount of each token earned as fees. For accurate tracking, you need to snapshot the feeGrowthInside values when you open the position and again when you check.

  • Sub-step 1: Fetch the current feeGrowthGlobal values from the pool contract.
  • Sub-step 2: Retrieve the stored feeGrowthInsideLast values from your position's on-chain data.
  • Sub-step 3: Compute the delta and multiply by your liquidity to get raw token amounts.
solidity
// Pseudocode for calculating uncollected fees function getFeesOwed( uint128 liquidity, uint256 feeGrowthGlobal, uint256 feeGrowthInsideLast ) internal pure returns (uint256) { uint256 feeGrowthDelta = feeGrowthGlobal - feeGrowthInsideLast; return FullMath.mulDiv(liquidity, feeGrowthDelta, FixedPoint128.Q128); }

Tip: Fees are only claimable upon withdrawing or collecting; they are not automatically reinvested.

3

Calculate Impermanent Loss at a Future Price

Compare the value of the LP position against a simple holding strategy.

Detailed Instructions

Impermanent loss quantifies the opportunity cost of providing liquidity versus holding the assets. To calculate it, determine the value of your LP position tokens (including accrued fees) at a new price P_new, and compare it to the value of your initial deposit if simply held. First, compute the token amounts in your position at P_new using the concentrated liquidity formulas: if P_new is within your range, the amounts are x = L / sqrt(P_new) - L / sqrt(P_upper) and y = L * sqrt(P_new) - L * sqrt(P_lower). Add any unclaimed fees. Then, calculate the hold value as: (Initial_Amount_TokenA * P_new) + Initial_Amount_TokenB. IL is: (LP_Value - Hold_Value) / Hold_Value.

  • Sub-step 1: Compute the position's token composition at the new market price.
  • Sub-step 2: Sum the value of these tokens plus accrued fees (converted to a common unit).
  • Sub-step 3: Calculate the value of the initial deposit if it had never been provided as liquidity.
  • Sub-step 4: Apply the IL formula; a negative result indicates a loss versus holding.

Tip: IL is most severe when the price exits your provided range entirely, as one token reserve depletes to zero.

4

Analyze Net Profit/Loss with Fee Income

Combine fee revenue and impermanent loss for the final P&L.

Detailed Instructions

The net profitability of a range order is the sum of earned fees and the impermanent loss (or gain) on the principal. Calculate the total LP position value as the market value of the current token reserves plus the market value of all fees earned. Subtract from this the initial capital invested. A positive result means fees outweighed IL. Express this as a percentage return. Use the formula: Net P&L = (Value_Reserves_New + Value_Fees - Value_Initial) / Value_Initial. This requires pricing both tokens and fees at the current market rate. For accurate analysis, model this over different price trajectories and fee rate assumptions to understand break-even points.

  • Sub-step 1: Aggregate the current token amounts from the position and the uncollected fees.
  • Sub-step 2: Convert the total amount of each token to a common currency (e.g., USD) using P_new.
  • Sub-step 3: Sum these values to get the total LP value.
  • Sub-step 4: Subtract the initial investment value (also in USD) to determine absolute profit/loss.
python
# Example Python snippet for net P&L calculation initial_value = (amt_token0_init * price0) + (amt_token1_init * price1) current_reserve_value = (amt_token0_now * price0) + (amt_token1_now * price1) fee_value = (fees_token0 * price0) + (fees_token1 * price1) net_pnl = current_reserve_value + fee_value - initial_value pnl_percentage = (net_pnl / initial_value) * 100

Tip: High fee rates can compensate for significant IL, but this is highly dependent on trading volume and price volatility.

5

Simulate Outcomes with Different Price Scenarios

Model fee accumulation and IL under various market conditions.

Detailed Instructions

Use historical or projected price data to simulate performance. The key is to model the price path and its interaction with your range. When the price is within your range, fees accumulate and reserves rebalance. When it's outside, fee accumulation stops for the depleted asset, and IL is maximized. Create a script that steps through price changes, updating virtual reserves and tracking fee growth. You can approximate fee income by assuming a constant daily volume percentage of the pool's TVL that flows through your price range. Tools like Python with pandas or specialized DeFi simulators (e.g., from Gauntlet) can automate this. The output should be a chart of net value over time compared to a hold strategy.

  • Sub-step 1: Define a time-series of price data (e.g., daily ETH/USD prices).
  • Sub-step 2: For each period, check if the price is within [P_lower, P_upper].
  • Sub-step 3: If active, calculate fees earned based on estimated volume and your liquidity share.
  • Sub-step 4: Recalculate token reserves based on the price change using the CL formulas.
  • Sub-step 5: Aggregate results to plot total position value versus time.

Tip: This simulation is crucial for setting realistic range widths and understanding the trade-off between potential fees and risk of IL.

Frequently Asked Questions

A range order is a liquidity provision strategy within a concentrated liquidity AMM, not a pending trade instruction on an order book. You deposit two assets into a predefined price range, earning fees from swaps that occur within it. A traditional limit order is a promise to trade at a specific price on a centralized or order book DEX. The key difference is execution: range orders are passive and probabilistic, earning fees over time, while limit orders are active and deterministic, executing a single trade when the market price hits the target. For example, a USDC/ETH range order from $3,000 to $3,500 provides liquidity and earns 0.3% fees on all trades in that band, whereas a limit order to sell ETH at $3,500 is a one-time event.