VolatilityGuardHookV8
EthereumVolatilityGuardHookV8 is a Uniswap v4 hook on Ethereum. Runs code on every swap. Can take tokens from swaps. Sets its own swap fee. Runs at pool creation.
- Contract name
- VolatilityGuardHookV8
How this hook works
Trading taxA trading tax hook. It changes its fee with the market, takes a cut of every trade and pays extra to liquidity providers.
Fee changes with the market
Instead of a fixed fee, it works out the fee on every trade from how the price is moving.
The code that does this (beforeSwap):function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) { PoolId poolId = key.toId(); PoolState storage state = _states[poolId]; (, int24 currentTick,,) = poolManager.getSlot0(poolId); _updateAnchor(state, currentTick); uint24 fee = feeForDeviation(_deviation(currentTick, state.anchorTick)); assembly ("memory-safe") { tstore(PRE_FEE_SLOT, fee) } // ETH (currency0) is the specified side: only here can the treasury share be taken in ETH int128 treasuryTake; if ((params.amountSpecified < 0) == params.zeroForOne) { int256 s = params.amountSpecified; uint256 amount = uint256(s < 0 ? -s : s); uint256 t = (amount * _share(fee, TREASURY_BPS)) / PIPS_DENOMINATOR; if (t != 0) { poolManager.mint(address(this), ETH_ID, t); treasuryTake = int128(int256(t)); } } return ( IHooks.beforeSwap.selector, toBeforeSwapDelta(treasuryTake, 0), _share(fee, LP_BPS) | LPFeeLibrary.OVERRIDE_FEE_FLAG // …Takes a cut of every trade
On top of the normal pool fee, it keeps a share of each trade.
The code that does this (beforeSwap):function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) { PoolId poolId = key.toId(); PoolState storage state = _states[poolId]; (, int24 currentTick,,) = poolManager.getSlot0(poolId); _updateAnchor(state, currentTick); uint24 fee = feeForDeviation(_deviation(currentTick, state.anchorTick)); assembly ("memory-safe") { tstore(PRE_FEE_SLOT, fee) } // ETH (currency0) is the specified side: only here can the treasury share be taken in ETH int128 treasuryTake; if ((params.amountSpecified < 0) == params.zeroForOne) { int256 s = params.amountSpecified; uint256 amount = uint256(s < 0 ? -s : s); uint256 t = (amount * _share(fee, TREASURY_BPS)) / PIPS_DENOMINATOR; if (t != 0) { poolManager.mint(address(this), ETH_ID, t); treasuryTake = int128(int256(t)); } } return ( IHooks.beforeSwap.selector, toBeforeSwapDelta(treasuryTake, 0), _share(fee, LP_BPS) | LPFeeLibrary.OVERRIDE_FEE_FLAG // …Pays extra to liquidity providers
It sends extra rewards straight into the pool for liquidity providers.
The code that does this (charge):function _charge(PoolKey calldata key, bool ethSpecified, uint256 base, uint24 totalFee, uint24 preFee) internal returns (uint256) { PoolId poolId = key.toId(); // With ETH specified the treasury share was fixed in beforeSwap, so the LPs get the whole // top-up. Otherwise they get their 90% of it and the treasury its 10% below. uint256 topUp = ethSpecified ? (base * (totalFee - preFee)) / PIPS_DENOMINATOR : (base * (_share(totalFee, LP_BPS) - _share(preFee, LP_BPS))) / PIPS_DENOMINATOR; // Donating to a pool with no active liquidity reverts if (topUp != 0 && poolManager.getLiquidity(poolId) == 0) topUp = 0; if (topUp != 0) { ethSpecified ? poolManager.donate(key, 0, topUp, "") : poolManager.donate(key, topUp, 0, ""); } uint256 t; if (!ethSpecified) { t = (base * _share(totalFee, TREASURY_BPS)) / PIPS_DENOMINATOR; if (t != 0) poolManager.mint(address(this), ETH_ID, t); } return topUp + t; }Uses an outside price feed
It reads a price from an outside source (an oracle) and uses it in its rules.
The code that does this (maybePayout):function _maybePayout() internal { uint256 accrued = poolManager.balanceOf(address(this), ETH_ID); if (accrued <= payoutThreshold) return; uint256 amount; unchecked { amount = accrued - 1; } try poolManager.take(CurrencyLibrary.ADDRESS_ZERO, treasury, amount) { poolManager.burn(address(this), ETH_ID, amount); } catch { return; // the treasury rejected ETH: keep accruing, swaps go on } uint256 next = payoutThreshold; try ethUsdFeed.latestRoundData() returns (uint80, int256 answer, uint256, uint256, uint80) { if (answer > 0) next = (PAYOUT_USD * 1e18) / uint256(answer); } catch {} payoutThreshold = next; emit TreasuryPaid(amount, next); }
Who controls it: Nobody. The hook has no admin functions, and the code cannot be changed.
Based on the hook’s published code.
What it can do
Its code executes inside each trade in pools that use it.
It can take or add tokens during a swap. Fees, burns and custom curves work this way, and so do scams.
Pools using it let the hook choose the swap fee instead of a fixed tier.
It runs when a pool is created, often to lock in that pool’s settings.
Hook history
Nothing recorded yet.
Counted from what the hook recorded on-chain across all its pools, for every action in its published code, plus token transfers in and out of it.