ZCHFSavingsRouterHook on Ethereum

Uniswap v4 Hook Contract 0x88ece7e3c7f82957d279d5702dfb1c2fda57eac0 on Ethereum · Liquidity management · Verified contract

Volume (24h)
$0
Value locked (TVL)
$0
All-time volume
$0
Pools using this hook
1
Swaps (24h)
0 (0 traders)
Total swaps
1

What it does

A Uniswap v4 hook for the ZCHF/svZCHF pair that keeps a protocol-owned anchor liquidity band around the savings vault's fair price, blocks outside liquidity provision, and adds directional just-in-time liquidity to each swap so traders get the vault rate with a fixed 0.005% fee.

How it works step by step

  • Keeps a persistent owner-sized anchor liquidity band centered on the svZCHF fair price, rebalanced when drift exceeds a threshold
  • Blocks all external add and remove liquidity calls with LiquidityNotAllowed
  • Adds a directional just-in-time liquidity position in beforeSwap sized to the swap amount and removes it in afterSwap
  • Enforces a maximum price deviation from the svZCHF fair price before and after each swap, requiring syncPrice when exceeded
  • Permissionless syncPrice and materializeClaims functions move the pool price back to fair and convert protocol claims to raw reserves
  • Converts between ZCHF and svZCHF through the savings vault to source or hold the inventory needed for settlement
Swap behaviour
On each swap, beforeSwap checks the pool price is within the allowed deviation of the svZCHF fair price, adds a directional JIT liquidity position sized to the requested amount, and afterSwap verifies exact fill, removes the JIT position, and rechecks the price deviation.
Liquidity behaviour
Direct user liquidity is blocked: beforeAddLiquidity and beforeRemoveLiquidity always revert with LiquidityNotAllowed. Liquidity is managed only by the hook itself: a persistent owner-sized anchor position around the fair price (sized from anchorTargetAssets), a temporary sync bridge position used during price sync, and a per-swap directional JIT position added in beforeSwap and removed in afterSwap.
Fee behaviour
Uses a fixed static LP fee of 50 ppm (0.005%) set via the LP_FEE constant. The hook returns zero fee override and zero beforeSwap delta, so it does not change the fee dynamically and takes no hook fee.
Owner & admin controls
Owner (Ownable2Step, two-step transfer, renounceOwnership available) can: call initialize() to set the pool price, set the anchor target size via setAnchorTargetAssets (capped at the immutable anchorMaxAssets), trigger rebalanceAnchor(), fund and withdraw the hook's raw ZCHF/svZCHF reserves via fundReserve/withdrawReserve (withdrawReserve can send to any address), and set the vault allowance via setVaultApproval(uint256) which can grant the savings vault an arbitrary amount of ZCHF. Constructor parameters (widths, thresholds, jit width, max deviation, anchor max assets) are immutable. No proxy/upgrade mechanism and no pause function was found.

Enabled Uniswap v4 callbacks

beforeInitialize, beforeAddLiquidity, beforeRemoveLiquidity, beforeSwap, afterSwap

beforeInitialize: validates the pool key and that the initial sqrt price equals the svZCHF fair price. beforeAddLiquidity and beforeRemoveLiquidity: revert to block all external liquidity changes. beforeSwap: validates pool, enforces price deviation limits, and adds a directional JIT liquidity position sized to the swap amount. afterSwap: verifies the swap filled exactly, removes the JIT position and settles it, and re-checks price deviation.

Security & trust assessment

Risk level: medium (verified source, high confidence).

Who controls it: The owner controls reserves and the savings vault allowance, can withdraw any raw ZCHF or svZCHF held by the hook to any address, and controls the anchor size and rebalancing timing. A compromised owner key could drain the hook's reserves and redirect the protocol-owned liquidity; it cannot directly change swap fees or pause swaps, but could set the anchor target to zero and remove the anchor liquidity.

Risk to user funds: The hook holds raw ZCHF and svZCHF reserves and protocol-owned pool liquidity; it moves these during swaps, anchor rebalancing and price sync, and the owner can withdraw reserves. Regular swappers are not given direct custody, but their swaps are routed through hook-managed liquidity that depends on owner-funded inventory and the savings vault's exchange rate.

Security findings

  • [high] Owner can withdraw protocol reserves and set vault allowances: withdrawReserve lets the owner send any amount of ZCHF or svZCHF held by the hook to any address, and setVaultApproval can grant the vault an unlimited allowance over the hook's ZCHF.
  • [medium] Owner can remove the anchor liquidity: The owner can set anchorTargetAssets to zero, which causes rebalanceAnchor to remove the entire protocol-owned anchor position, removing liquidity from the pool.
  • [medium] Swaps can be blocked by price deviation checks: Swaps revert with PriceSyncRequired if spot tick deviates from the svZCHF fair tick beyond maxPreSwapDeviationTicks, and syncPrice is needed to recover; if the vault rate or pool state becomes stuck, swaps can be blocked until sync succeeds.
  • [low] Hook moves currency and holds balances during swaps: The hook uses poolManager.mint and the router-unlock settlement path for positive deltas and pays negative deltas from its own raw balance or by converting between ZCHF and svZCHF through the vault, so it holds and moves user and pool funds during swaps.
  • [info] Single owner key, no upgrade proxy: Ownership uses Ownable2Step with renounceOwnership available, and the implementation is immutable with no proxy or upgrade path, which limits upgrade risk but leaves the owner as a single privileged key.

Contract details

Verified source
Yes (ZCHFSavingsRouterHook)
Compiler
solc 0.8.26+commit.8a97fa7a
Bytecode size
22,160 bytes
Upgradeable proxy
No
Detected patterns
liquidity-management, moves-currency, ownable, self-unlock

Pools using ZCHFSavingsRouterHook