ZCHFSavingsRouterHook on Ethereum

Uniswap v4 Hook Contract 0x46ad26e15fc4db3cbff562d3551b7a8bd84daac0 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
6

What it does

A zero-fee routing hook for the ZCHF/svZCHF pool that keeps a fair-price-centred anchor liquidity position and adds temporary directional liquidity around each swap so trades track the svZCHF savings rate.

How it works step by step

  • Creates a single pool keyed to ZCHF and svZCHF with zero LP fee and a tick spacing of 1.
  • Initializes the pool at the fair price derived from svZCHF convertToAssets for one whole share.
  • Maintains an owner-set anchor liquidity range centred on the fair tick, sized from anchorTargetAssets and recentred when drift exceeds a threshold.
  • Blocks external liquidity provision and removal so only the hook manages pool liquidity.
  • Adds directional JIT liquidity in beforeSwap and removes it in afterSwap, reverting on partial fills or price deviation.
  • Lets anyone call syncPrice or materializeClaims to realign the pool to the fair price and convert ERC-6909 claims into raw tokens.
Swap behaviour
beforeSwap checks spot is within a deviation bound of the svZCHF fair price, then adds a directional JIT liquidity position sized to the swap amount; afterSwap verifies exact fill, removes the JIT position and settles deltas, and checks price deviation again.
Liquidity behaviour
Public addLiquidity and removeLiquidity are blocked (beforeAddLiquidity and beforeRemoveLiquidity revert with LiquidityNotAllowed). Liquidity is managed only by the hook itself: a persistent owner-set anchor range recentred around the fair svZCHF price, a temporary bridge range used for price sync, and a directional JIT position added before each swap and removed after it.
Fee behaviour
Fixed LP fee of 0 (LP_FEE constant) on the canonical ZCHF/svZCHF pool; no dynamic fee and no fee sharing. Hook returns zero beforeSwap delta and zero fee override.
Owner & admin controls
Owner (Ownable2Step, two-step transfer) can initialize the pool, set the anchor target assets up to anchorMaxAssets, trigger rebalanceAnchor, fund and withdraw the router's ZCHF/svZCHF reserve, set vault approval, and renounce or transfer ownership. No pause or upgrade mechanism found; the contract is immutable.

Enabled Uniswap v4 callbacks

beforeInitialize, beforeAddLiquidity, beforeRemoveLiquidity, beforeSwap, afterSwap

beforeInitialize: validates the pool key and that the initial sqrt price equals the fair wrapper price. beforeAddLiquidity and beforeRemoveLiquidity: revert to block outside liquidity. beforeSwap: validates the pool, checks spot is within maxPreSwapDeviationTicks of fair price, and adds directional JIT liquidity. afterSwap: verifies the swap filled exactly, removes the JIT position and re-checks the price deviation.

Security & trust assessment

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

Who controls it: The owner controls the anchor target size, the reserve funds the hook uses to provide liquidity, and ERC-20 approval to the savings vault. A malicious or compromised owner could withdraw all reserve ZCHF and svZCHF, set a large anchor target to drain reserves into the pool at the fair price, or set an unlimited vault approval; they cannot change fee or swap routing directly.

Risk to user funds: The hook holds owner-funded reserve ZCHF and svZCHF plus ERC-6909 claims and uses them to provide liquidity for swaps. Users swapping in the pool do not deposit into the hook, but the owner can withdraw reserves or redirect them, and wrapper rate errors flow into pricing.

Security findings

  • [medium] Owner can drain the hook reserve: Owner can withdraw any amount of ZCHF or svZCHF held by the hook to any address via withdrawReserve, which is gated only by onlyOwner and idle lifecycle state.
  • [medium] Owner-controlled vault approval and anchor sizing: setVaultApproval uses forceApprove with an arbitrary amount to the savingsVault, and the owner can set any anchor target up to anchorMaxAssets, so reserve capital can be pushed into the vault or the pool at owner discretion.
  • [low] Trust in the svZCHF wrapper exchange rate: Swaps depend on the fair price from the svZCHF wrapper convertToAssets; a manipulated or misbehaving wrapper rate would set the initial price and the price sync target, and the hook trusts it.
  • [info] Swaps can revert when price is out of sync: Swaps revert if the pool spot tick drifts beyond maxPreSwapDeviationTicks from fair; anyone can call syncPrice to fix this, but if the anchor and claims cannot be settled the pool can be temporarily unswappable.
  • [info] Custom accounting via PoolManager unlock and ERC-6909 claims: Swap-time JIT liquidity and settlement are performed through transient storage and PoolManager unlock with raw ERC-20 transfers; the code has explicit settlement checks and a lock, so no obvious reentrancy path was identified.

Contract details

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

Pools using ZCHFSavingsRouterHook