ReClamm Pools

Overview

ReClamm (Readjusting Concentrated Liquidity AMM) Pools are two-token pools that concentrate liquidity within a price range, like a fungible concentrated-liquidity position, but with a range that moves by itself. When the market price drifts toward the edge of the range, the pool gradually shifts the range back around the current price. Liquidity providers get the capital efficiency of concentrated liquidity without having to monitor and rebalance a position: a "fire-and-forget" approach to concentrated liquidity.

Because every LP holds the same fungible BPT, ReClamm liquidity can be composed with the rest of Bush like any other pool token.

Info

ReClamm Pools support exactly 2 tokens. Liquidity can only be added and removed proportionally; unbalanced operations and donations are disabled.

Ideal For

  • Volatile pairs with a known trading band - pairs such as ETH/BTC, where most volume happens within a range that changes slowly over time
  • Correlated or pegged pairs - stablecoins or liquid staking tokens, using a tight range for deep liquidity near the peg
  • Passive LPs - providers who want concentrated-liquidity returns without active range management

How It Works

Virtual Balances

A ReClamm Pool tracks a virtual balance for each token, an offset added to its real balance. Swaps are priced on the constant-product invariant applied to the combined balances:

where are the real balances and the virtual balances. The spot price of token A in terms of token B is .

The virtual balances define the edges of the price range. When the real balance of one token reaches zero, the pool has hit an edge:

The price ratio describes the width of the range. Smaller ratios concentrate liquidity more tightly and give greater capital efficiency around the current price.

Centeredness and the Target Range

Centeredness measures how close the pool is to the middle of its range: 1 (100%) at the center, falling toward 0 as the price approaches either edge. It is computed as

The centeredness margin marks out a target range within the full price range. While centeredness is at or above the margin, the pool is in range, and its virtual balances stay fixed. A margin of 0 means the pool is always considered in range, so the range never moves.

Range Shifting

When centeredness falls below the margin, the pool is out of range, and the virtual balance of the overvalued token starts to decay every second. This moves the whole range toward the market price until the pool is back within its target range.

The speed of the shift is set by the dailyPriceShiftExponent. Virtual balances change by about per day (somewhat faster while the overvalued token still has a real balance), so the maximum exponent of 50% moves the range by roughly 1.41x per day. An exponent of 0 disables shifting.

Shifting is time-based and is applied lazily: the pool stores the virtual balances and timestamp from its last interaction, and computes the current values when it is next used. Quotes therefore depend on the timestamp of the block the transaction lands in, not just on stored state.

Price Ratio Updates

The width of the range can be changed gradually, much like the gradual weight changes of a Liquidity Bootstrapping Pool. The pool's swap fee manager (or governance, if none is set) calls startPriceRatioUpdate with a target ratio and a start and end time, and the ratio is interpolated between them.

The range stays positioned around the current price at the same centeredness while it widens or narrows. For example, a pool with a range of 1,000-4,000 and a price of 2,000 has a ratio of 4. Updating the ratio to 8 gives a range of roughly 707-5,657, not 1,000-8,000.

An update can be cancelled at any time with stopPriceRatioUpdate, which freezes the ratio at its current value.

Creating a ReClamm Pool

Pools are deployed with the ReClammPoolFactory. The pool contract acts as its own hook, so no separate hook is configured.

ParameterDescriptionRange
tokensThe two tokens and their rate providersExactly 2
swapFeePercentageStatic swap fee0.001% - 10%
initialMinPriceLower edge of the initial range (token A in terms of B, 18 decimals)> 0
initialMaxPriceUpper edge of the initial range> initialMinPrice
initialTargetPriceStarting price of the poolWithin the target range defined by the margin
tokenAPriceIncludesRate / tokenBPriceIncludesRateWhether prices are quoted in terms of the underlying (rate applied) rather than the wrapped tokenRequires WITH_RATE token type
dailyPriceShiftExponentSpeed of range shifting when out of range0 - 50%
centerednessMarginCenteredness below which the pool counts as out of range0 - 90%

The initial price ratio (initialMaxPrice / initialMinPrice) must be between 1.0001 and 20.

Tips

The factory only checks that the target price clears the centeredness margin. A target near an edge of the range will pass, but any small price movement then puts the pool out of range. Placing the target near the geometric center of the range () gives the pool the most headroom.

Initialization

The two tokens must be supplied in the ratio implied by the initial prices. Call computeInitialBalancesRaw(referenceToken, referenceAmountInRaw) on the pool to get the matching amount of the other token, then initialize through the standard Router. Initialization reverts if the balances diverge from the expected ratio by more than 0.01%.

Choosing the Swap Fee

Faster range shifting increases the pool's exposure to round-trip repricing: pushing the pool out of range, waiting for the range to move, and trading back. As a guide, keep the swap fee at or above dailyPriceShiftExponent (in %) x 0.0002%. A 5% exponent is safe at the minimum fee of 0.001%, while a 50% exponent calls for a fee of at least 0.01%.

Rate-Bearing Tokens

ReClamm Pools can hold rate-bearing tokens such as ERC4626 wrappers. The rate is read once at initialization and built into the virtual balances; it is not re-applied afterwards. As the rate grows, the pool's quoted price drifts from the true underlying price until the range shifts to follow it.

What matters is how quickly the rate moves between trades, not how large it is. A rate that accrues slowly and in one direction is a good fit. A rate that is volatile, can jump, or can be moved by an outside party is not.

A rate that anyone can move needs the most care, because changing the rate also changes the pool's centeredness without any swap, and can push the pool out of range on its own. An ERC4626 wrapper, for example, accepts transfers from anyone, which raise its assets per share. A pool holding a small share of a deeply backed wrapper is well protected; one holding a large share of a thinly backed wrapper is not.

Pool Management

The following functions can be called by the pool's swap fee manager, or by governance if no swap fee manager is set:

FunctionEffectConstraints
startPriceRatioUpdate(endPriceRatio, startTime, endTime)Gradually change the range widthRatio 1.0001 - 20; duration of at least 1 day; at most ~1.41x change per day
stopPriceRatioUpdate()Freeze the ratio at its current valueAn update must be in progress
setDailyPriceShiftExponent(exponent)Change the range shifting speed0 - 50%; cannot be called mid-transaction
setCenterednessMargin(margin)Change the target range0 - 90%; pool must be within both the current and new target range; cannot be called mid-transaction

Integration Notes

  • Time-dependent pricing: swap results depend on the current timestamp whenever the pool is out of range or a price ratio update is in progress. Quote with the timestamp of the block the transaction will land in. See Pool Maths and Details for the state the maths needs.
  • No BPT rate: getRate() reverts, so ReClamm BPT cannot be used as a rate-bearing token in another pool.
  • Proportional liquidity only: adds and removes scale the virtual balances in proportion, so liquidity changes do not move the price, range, or centeredness.
  • Live state getters: computeCurrentPriceRange(), computeCurrentVirtualBalances(), computeCurrentPoolCenteredness() and isPoolWithinTargetRange() return time-adjusted values.

Contracts