Ledge protocol specification
Technical specification
1Overview
Ledge is a reserve-backed token deployed on a Uniswap v4 pair whose hook is the sole liquidity provider. The hook maintains a floor price equal to the ratio of its reserve to circulating supply, and continuously redeploys that floor into the pool as a bid wall.
The central property of the protocol is that this floor cannot decrease. That is not a policy, it is an arithmetic consequence of the deployment rules: every possible flow through the system (swap, wall fill, protocol sale, direct redemption) leaves the reserve-to-circulating-supply ratio unchanged or increases it.
Three mechanisms drive it upward: swap fees, a protocol-owned order grid that monetizes volatility, and an exit fee on direct redemptions.
2Components
| Component | Role |
|---|---|
| LedgeToken (T) | ERC-20, fixed supply at deployment, burn restricted to the hook |
| Quote (Q) | ETH or USDC depending on deployment |
| v4 pool T/Q | Single pool, dynamic fee enabled, hook attached at initialization |
| LedgeHook | Holds the reserve, manages positions, arbitrates the ratchet, serves redemptions |
The hook is the only authorized LP. All pool liquidity belongs to it.
3Notation and invariant
- R: Q reserve controlled by the hook, including Q locked in the bid wall
- I: T inventory held by the hook, including T locked in the ask
- Sc: circulating supply = totalSupply − burned − I
- Pfloor = R / Sc
- Pspot: current pool price
Protocol invariant: Pfloor is monotonically increasing. Every operation must be checked against this constraint before execution.
4The bid wall
The entire reserve R is posted as single-sided Q liquidity, over a range located strictly below spot.
The range is [tf, tf + w · tickSpacing], where tf is the largest tick such that:
price(tf + w · tickSpacing) ≤ Pfloor
Rounding always goes down. It is the upper bound of the range, not the lower, that must stay below Pfloor. This guarantees the wall’s average execution price is at most Pfloor, so the reserve buys at least R / Pfloor = Sc tokens: the wall can absorb the entire circulating supply without running dry.
w = 1 gives a single-tick wall, meaning the highest possible floor and the steepest one. Increasing w spreads execution out and slightly lowers the effective floor.
Monotonicity proof on a fill
The wall absorbs ΔT tokens against ΔQ of reserve, with ΔQ ≤ ΔT · Pfloor by construction of the range. The ΔT received leave circulating supply (see §6), so:
Pfloor′ = (R − ΔQ) / (Sc − ΔT) ≥ R / Sc = Pfloor
The more the wall is consumed, the higher the floor rises. In the limiting case, where the wall absorbs the entire supply, the protocol is left with no circulating supply and a residual reserve.
5The protocol grid
In parallel, the hook posts part of its inventory I as single-sided T liquidity, over a range above spot.
Range [ta, ta + wa · tickSpacing], with ta the smallest tick such that:
price(ta) ≥ max(Pspot · (1 + spread), Pfloor · (1 + askMargin))
The second condition is structural. Selling ΔT at average price p gives:
Pfloor′ = (R + ΔT · p) / (Sc + ΔT)
which exceeds Pfloor only if p > Pfloor. Posting the ask above the floor guarantees that any protocol sale raises the floor, whatever the market does next.
The full cycle: the ask fills, the Q received grows the reserve, the wall moves up; price falls back, the wall fills, the T received return to inventory or are burned, the wall moves up again. Every volatility round trip is captured, with no dependence on fee volume.
In a sustained uptrend the inventory drains and the protocol stops participating in the rally. That is the expected behavior: the tradeoff is a reserve that grew at every step along the way.
6Handling of tokens absorbed by the wall
The ΔT absorbed by the wall are split according to the burnShare parameter (β):
- β · ΔT are burned permanently
- (1 − β) · ΔT join inventory I
Either way the tokens leave circulating supply, so the floor rises immediately and identically. The difference is what follows: burning is irreversible, while inventory can be resold through the ask, but only above the floor, which adds reserve.
β = 1 gives a purely deflationary protocol, β = 0 a fully rechargeable grid. An intermediate value, around 0.3 to 0.5, keeps the ask supplied while still shrinking supply.
7Swap fees
Fees are taken in Q in both directions, via afterSwap with afterSwapReturnDelta enabled, and routed straight to the reserve. They never flow through liquidity positions, which avoids having to collect them separately.
- Buy: a fraction fb of incoming Q
- Sell: a fraction fs of outgoing Q
fb is fixed. fs is indexed on distance to the floor:
d = 1 - P_floor / P_spot // in [0, 1) f_s = f_min + (f_max - f_min) · d
At the floor, exiting costs fmin. Far above it, exiting costs up to fmax. The fee is returned by beforeSwap as a dynamic LP fee override, or applied in afterSwap depending on the chosen implementation; the accounting result must be identical.
8Direct redemption
Any holder can call redeem(uint256 amount) on the hook, outside the pool:
payout = amount · Pfloor · (1 − fr)
The amount tokens are burned, payout is paid out in Q. Settlement requires pulling liquidity from the wall for payout, then redeploying.
Effect on the floor:
Pfloor′ = (R − amount · Pfloor · (1 − fr)) / (Sc − amount)
which is strictly greater than Pfloor as soon as fr > 0. Every exit raises the floor for remaining holders.
This function is what makes the floor enforceable independently of pool depth. If the market trades below Pfloor, the arbitrage is to buy on the market and redeem against the hook, which pulls price back to the floor.
9Redeployment conditions
Recomputing and redeploying positions on every swap is too expensive. Redeployment triggers if any of these conditions holds in afterSwap:
- Floor drift: current Pfloor exceeds the wall range’s upper bound by more than θ (0.3 to 0.5%)
- Wall crossed: the wall range has been partially or fully consumed
- Ask crossed: the ask range has been consumed and must be reposted higher
- Spot drift: Pspot has moved away from the ask by more than spreadDrift
A minimum window of minBlocks blocks between two redeployments bounds gas cost. An optional jitter on θ, drawn from the blockhash, desynchronizes triggering from one block to the next.
Full redeployment is a single sequence inside the unlock callback: pull both positions, recompute tf and ta, repost.
10Circulating supply accounting
The most sensitive point of the implementation. Sc must exclude:
- T held in the hook’s balance
- T locked in the ask position, including the portion not yet sold
- burned T
Overestimating Sc undercuts the floor, which has no bearing on the invariant. Underestimating it overstates the floor and breaks the absorption guarantee. Any uncertainty must therefore be resolved by overestimating Sc.
Symmetrically, R must include Q locked in the wall, and exclude any Q already committed to a redemption mid-settlement.
Both quantities are recomputed from PoolManager state at redeployment time, not from an incremental counter, to avoid drift.
11Callbacks
| Callback | Content |
|---|---|
beforeInitialize | Checks the pair, tickSpacing and dynamic fee flag, locks the config |
afterInitialize | Deploys the initial wall and initial ask from seed reserve and inventory |
beforeSwap | Computes fb or fs and returns the fee override |
afterSwap | Takes the Q fee into the reserve, updates accounting, tests the §9 conditions, redeploys if needed |
beforeAddLiquidity | Revert if caller is not the hook |
beforeRemoveLiquidity | Revert if caller is not the hook |
Locking the last two callbacks is not optional: an external LP would make circulating supply unmeasurable and the floor wrong.
12Parameters
| Parameter | Description | Starting value |
|---|---|---|
| w | Wall width, in tickSpacing | 1 |
| wa | Ask width, in tickSpacing | 3 to 5 |
| spread | Minimum ask offset from spot | 2% |
| askMargin | Minimum ask margin over the floor | 5% |
| fb | Buy fee | 0.5% |
| fmin / fmax | Sell fee bounds | 0.5% / 4% |
| fr | Direct redemption fee | 2% |
| β | Burn share of tokens absorbed by the wall | 0.4 |
| θ | Drift threshold triggering redeployment | 0.4% |
| minBlocks | Minimum window between redeployments | 2 |
| askInventoryShare | Share of I posted as ask | 30% |
13Seed
At deployment:
- Mint totalSupply, split between hook inventory and initial distribution
- Deposit the initial reserve R₀ in Q
- Initialize the pool at a price P₀ strictly above R₀ / Sc
afterInitializeposts the wall and the ask
The ratio of R₀ to the supply put into circulation sets the starting floor. That is the only moment this level is chosen; from then on it is entirely determined by the protocol.
14Minimal configuration
The grid is separable. Setting askInventoryShare = 0 and β = 1 reduces the protocol to: swap fees into the reserve, bid wall at the floor, burn everything absorbed, direct redemption. The invariant and the absorption guarantee hold identically, with far less implementation surface. It is a reasonable first-version target, with the grid enabled later by parameter.