Developers

Build a hook

Use AvenFairValue in your own hook.

AvenFairValue is a library of internal functions, inlined at compile time. No runtime dependency, nothing to call.

MyHook.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

// forge install SATISH-JALAN/Aven   then remap   aven/=lib/Aven/contracts/
import {BaseHook} from "uniswap-hooks/base/BaseHook.sol";
import {AvenFairValue as FV} from "aven/src/AvenFairValue.sol";

contract MyHook is BaseHook {
    // Permissions must include beforeSwap; the pool must use DYNAMIC_FEE_FLAG.

    function _beforeSwap(address, PoolKey calldata key, SwapParams calldata p, bytes calldata)
        internal override returns (bytes4, BeforeSwapDelta, uint24)
    {
        (uint160 sqrtP,,,) = poolManager.getSlot0(key.toId());

        // Gas-capped, never reverts: a bad read gives ok = false.
        (bool ok, uint64 oracleRaw, uint64 markRaw) = FV.readPrices(cfg.perpIndex, params.precompileGas);

        FV.Breakdown memory b = FV.compute(cfg, params, FV.Inputs({
            oracleRaw: oracleRaw, markRaw: markRaw, anchorMarkRaw: _anchor,
            sqrtPriceX96: sqrtP, sqrtPriceTopX96: _topOfBlock(sqrtP),
            zeroForOne: p.zeroForOne, readOk: ok
        }));

        // Always set the override flag: a dynamic pool's stored LP fee is 0.
        return (IHooks.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA,
                b.fee | LPFeeLibrary.OVERRIDE_FEE_FLAG);
    }
}
Keep a top-of-block price and a mark anchor per pool, like AvenHook.sol does.

Quote from TypeScript#

Routers need no changes: the hook implements IDynamicFeeHook.getFee, and V4Quoter simulates the hook.

quote.ts
import { createPublicClient, http } from "viem";
import { avenHookAbi } from "@aven/core/abi";

const client = createPublicClient({ transport: http("https://rpc.hyperliquid.xyz/evm") });

// Exactly what the next swap in this block pays, with every input (I6).
const b = await client.readContract({
  address: "0xfdd13cA6D7FcF4Ca710Bc8C77546592F42CF6080",
  abi: avenHookAbi,
  functionName: "previewFee",
  args: [poolKey, /* zeroForOne */ true],
});

// Or Uniswap's IDynamicFeeHook: both directions, size-independent.
const [feeZeroForOne, feeOneForZero] = await client.readContract({
  address: "0xfdd13cA6D7FcF4Ca710Bc8C77546592F42CF6080", abi: avenHookAbi, functionName: "getFee", args: [poolKey],
});

Gas#

WhatGasSource
Full swap through the test router (p50)~175kdocs/PROOFS.md
Hook overhead per swap~46.9kAven swap minus control swap
One precompile read≤ 3.1krecon C.5
Aven swaps per 3M-gas small block~16docs/LOADTEST.md

Estimate gas with a margin

The block's first swap writes extra state. Use the estimate × 1.3 + 30k.
Aven · MIT · ETHGlobal MumbaiEdit on GitHub ↗