The contract prices nothing
A vault that never reads a price cannot be attacked by moving one — and almost every other decision here follows from being unable to.
Design · 4 September 2026 · 6 min
There is a family of bugs that only exists because a contract asked what something was worth. A vault reads a price to decide how many shares to mint; somebody moves that price for one block, mints against the lie, and moves it back. The details differ — spot instead of TWAP, a manipulable oracle, a stale one — but the shape is always the same, and the shape begins with reading.
Mantle contains no price. Not a bad one, not a well-guarded one: none.
Every amount the vault moves is a number the PoolManager handed back from the call that moved it. When liquidity is added, modifyLiquidity returns what the pool charged. When it is removed, the same function returns what the pool paid. The vault settles those numbers and records them. It never forms an opinion about them, so there is nothing to manipulate: pushing the pool price around changes what a deposit costs and what a redemption returns in exactly the way it changes those things for anyone else providing liquidity, which is not an attack, it is the market.
What the rule forbids
Stated as a rule it sounds like restraint. In practice it is a constraint that removes options, and most of the design followed from being unable to take them.
The first thing it forbids is a concentrated range. To manage a range you have to decide when the price has moved far enough to rebalance, and that decision requires a view about the price. You can put that view in the contract, in which case the contract prices things; or you can put it in a keeper, in which case the vault has a manager and everyone in it is exposed to that manager’s judgement and uptime. Full range needs neither. It never leaves the market, so there is no moment at which somebody has to decide anything.
The second thing it forbids is converting amounts to liquidity on chain. Uniswap’s getLiquidityForAmounts needs the square-root price at both range bounds, which needs TickMath, which is a table of twenty magic constants and about a hundred and fifty lines of arithmetic sitting on the money path. Mantle takes the liquidity number as an argument instead and lets the pool price it. If the caller passes a number the pool will not honour, the settlement reverts and they have spent gas. Nobody can be robbed by a wrong number, because a wrong number buys nothing.
That arithmetic still has to happen somewhere, and it happens in your browser: lib/v4math.ts is a port of TickMath and LiquidityAmounts, and npm run verify:math checks it against the chain rather than against my typing — for every live pool, getSqrtRatioAtTick(tick) must be at most the pool’s own sqrtPriceX96, which must be below getSqrtRatioAtTick(tick + 1). One wrong hex digit breaks that for most ticks. It currently passes over 164 live pools.
The one subtraction that matters
There is a single piece of real arithmetic in the vault, and it is a subtraction. Uniswap v4 only moves a position’s accrued fees when that position is modified, and it returns them folded into the same delta as the principal:
(int128 d0, int128 d1, int128 f0, int128 f1) = _run(Action.Seed, liq); // what the pool charged for the liquidity itself, with the fees it // credited in the same call stripped back out used0 = uint256(uint128(-(d0 - f0))); used1 = uint256(uint128(-(d1 - f1)));
callerDelta is principal plus fees. Settle it naively and a new depositor pays less than the liquidity cost, because the fees everyone else earned quietly subsidised their entry. Subtract feesAccrued and the depositor pays the full principal while the fees stay with the people who earned them. That one line is the whole of the fee attribution, and it is arithmetic on numbers the pool reported — not a price.
What it costs
Full range earns fewer fees on the same capital than a tight range around the current price would. That is not a rounding error; it is the headline trade. A managed vault that rebalances well will out-earn this one in a quiet market, and the argument for Orient is not that it earns more. It is that what it earns comes with a redemption that cannot be gamed and a position nobody has to babysit.
The other cost is that the contract cannot help you decide what to deposit. It will not quote you, because quoting is pricing. The app does that arithmetic in the open, on the client, where you can read it.
None of this removes impermanent loss. You hold a liquidity position; its two tokens can be worth less than what you put in, and compounding fees does not undo that. A vault that prices nothing is not a vault that promises anything.
NextWhat a share is worth