Existing leveraged tokens rely on centralized rebalancing engines, daily NAV resets, or off-chain keepers. This introduces counterparty risk, rebalance lag, funding costs, and liquidation exposure. Perpetual futures require margin, carry funding rates, and can be liquidated.
bald replaces all of this with a single Uniswap v4 hook. The hook is the keeper. Every trade triggers the rebalance logic. There is no external party, no cron job, no trusted operator.
At pool initialization, the hook records two values: the initial ETH/USD price P₀ (from Chainlink) and the initial pool sqrtPrice S₀ (from the Uniswap v4 PoolManager). These serve as the leverage baseline — the point of zero synthetic move.
Where Pt is the current Chainlink price and P0 is the price at pool creation.
The synthetic move is capped at ±25% per evaluation to limit extreme oracle moves from causing pathological behavior.
Uniswap v4 represents prices as sqrtPriceX96 — the square root of the price ratio, scaled by 2⁹⁶. The target sqrtPrice is derived from the initial sqrtPrice scaled by the square root of the leverage ratio:
This is computed using a Babylonian integer square root to stay fully on-chain with no floating point:
When the pool price is below the oracle target, selling bald pushes it further off peg. The hook charges a dynamic penalty fee on sells proportional to the gap between current and target sqrtPrice.
Operating on sqrtPrices rather than raw prices avoids overflow and naturally scales with the pool's internal representation.
| Direction | Base fee | Dynamic fee | Max total |
|---|---|---|---|
| Buy bald | 1% | none | 1% |
| Sell bald (at peg) | 1% | 0% | 1% |
| Sell bald (below peg) | 1% | 0–10% | 11% |
Fees are collected in WETH. The base 1% is sent instantly to the protocol via take() inside the PoolManager. The dynamic portion is minted as ERC-6909 claims inside the PoolManager, accumulating in the hook's treasury balance.
After every swap, the hook evaluates whether the pool price is meaningfully below the oracle target. If it is, and the treasury holds WETH, the hook executes a buy of bald directly inside the same transaction — no external call, no keeper, no delay.
The hook calls poolManager.swap() directly — it is already inside the PoolManager's unlock context from the user's swap, so no nested unlock is needed. A reentrancy guard (_rebalancing flag) prevents the hook from triggering itself recursively.
The price limit prevents the rebalance from overshooting — if the treasury has more WETH than needed to reach the target, the swap stops at the target and unused WETH is returned to the treasury balance.
After the swap, the hook burns WETH ERC-6909 claims to cover the WETH it sold to the pool, and takes the purchased bald. The bald accumulates in the hook's address as protocol inventory.
The hook address encodes its required permissions in the low 14 bits, enforced by the Uniswap v4 PoolManager at registration time:
| Permission | Bit | Purpose |
|---|---|---|
| afterInitialize | 0x1000 | Capture baseline price and oracle reference |
| beforeSwap | 0x0080 | Compute dynamic fee, collect fee on buys |
| afterSwap | 0x0040 | Collect fee on sells, trigger rebalance |
| beforeSwapReturnDelta | 0x0008 | Absorb WETH input on buys (fee deduction) |
| afterSwapReturnDelta | 0x0004 | Absorb WETH output on sells (fee deduction) |
Required hook address suffix: 0x10CC. The contract address is mined via CREATE2 until the suffix matches.
The pool is initialized with DYNAMIC_FEE_FLAG. The hook overrides the LP fee to zero on every swap via OVERRIDE_FEE_FLAG | 0 — LPs receive no fee. All fees are taken by the hook and distributed as described above.
If the Chainlink oracle has not been updated within the staleness window (default 2 days), all swaps revert with OracleStale. This prevents the hook from acting on a stale price target. The pool can also be paused instantly by the owner.
| Contract | Address |
|---|---|
| bald token | 0x2F8934007eeE3947e9Daf0959f0c673f8E1C5CB2 |
| Hook | 0xB1c22fbbb4e520D9Be683cF093C9A7789C0CD0CC |
| Oracle (Chainlink ETH/USD) | 0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70 |
| Pool Manager | 0x498581fF718922c3f8e6A244956aF099B2652b2b |