VolatileFi documentation
VolatileFi deploys Uniswap v4 hooks that charge a separate fee to each side of a swap and move both fees with the market. This guide covers how the fees work, how to deploy a hook from the dashboard or the API, how to attach pools, and the full API reference.
https://api.volatile.finance/v1. All examples use Ethereum mainnet (chain id 1).Getting started
What VolatileFi is
A Uniswap v4 pool can name a hook contract that runs code around each swap. A dynamic fee hook uses that to set the LP fee for every swap instead of using one fixed fee tier. VolatileFi is a launchpad for these hooks. You choose a fee strategy from a template, set its parameters, and deploy your own copy of the hook. You own it, and any pool you create with it uses your fee rules.
On the same day Uniswap brings its own VolatilePair Hook to ETH/USDC, VolatileFi lets anyone deploy the same kind of two-sided fee for any pair.
Quickstart
- Open Build and connect a wallet on Ethereum mainnet.
- Pick a template. VolatilePair is the right choice for most pairs.
- Set a floor and ceiling fee, a reaction window and a max tilt. The preview replays your settings on the last hour of live ETH/USDC swaps.
- Click Deploy hook and confirm the transaction. The factory mines a valid hook address and deploys your hook in the same transaction.
- Create a pool with the hook (see Attaching pools) or call
POST /hooks/{id}/pools.
Key terms
| Term | Meaning |
|---|---|
| Buy fee | Fee on swaps that buy the pool's base token (price goes up). |
| Sell fee | Fee on swaps that sell the base token (price goes down). |
| Move | Average size of recent per-block price changes, in basis points. |
| Trend | Average direction of recent price changes. |
| Tilt | How far the two fees are pushed apart, from -1 to 1, scaled by max tilt. |
| Fee units | Uniswap v4 fees are in hundredths of a basis point. 3000 is 0.30%. The maximum is 1000000 (100%). |
How fees move
The fee model
On every swap the hook updates two exponential averages over the reaction window W blocks, then derives the two fees.
alpha = 2 / (W + 1) r = ln(price_now / price_prev) * 10_000 // bps move = alpha * |r| + (1 - alpha) * move trend = alpha * r + (1 - alpha) * trend base = floor + (ceiling - floor) * min(1, move / scale) tilt = clamp(trend / move, -1, 1) * maxTilt buy = max(floor, base * (1 + tilt)) sell = max(floor, base * (1 - tilt))
When the price is rising, trend is positive, the buy fee goes up and the sell fee goes down. Buyers chasing the move pay more. Sellers who bring the price back pay less.
Why LPs earn more
With a fixed fee, a trader who sees a price change on another venue first can trade against the pool's stale price. The LP loses the difference, often called loss-versus-rebalancing. A higher fee on the side that is chasing a move takes part of that difference back for LPs. A lower fee on the other side keeps ordinary flow coming and helps the pool reach fair value faster.
Templates
| Template | Use it for | Extra parameter |
|---|---|---|
| VolatilePair | Most volatile pairs. Fees rise with volatility and split with the trend. | volScaleBps: per-block move that reaches the ceiling |
| Range Guard | Pairs that usually trade near a fair value. Cheap inside a band, expensive on a breakout. | bandBps: distance from the slow average before fees climb |
| Launch Shield | New tokens. Starts near the ceiling to absorb sniping, then eases into a normal curve. | shieldBlocks: blocks until the launch premium is gone |
| Flow Tilt | Pairs where order flow leads price. Tilts by the buy and sell volume imbalance. | flowWeightPct: share of tilt from flow instead of price |
Parameters and limits
| Field | Type | Range | Notes |
|---|---|---|---|
floorFee | uint24 | 100 to 10000 | 0.01% to 1% |
ceilingFee | uint24 | floor + 1000 to 100000 | Up to 10% |
windowBlocks | uint16 | 3 to 60 | About 36 seconds to 12 minutes |
maxTiltBps | uint16 | 0 to 9000 | 0 makes both fees equal |
lpShareBps | uint16 | 8000 to 10000 | The rest goes to the hook owner |
Deploying
From the dashboard
The Build page encodes a single call to the VolatileFi factory, deployHook(...). The factory searches for a CREATE2 salt whose resulting address carries the right v4 permission bits for the template, then deploys. The hook address is returned in the HookDeployed event.
Hook address bits
Uniswap v4 reads a hook's permissions from the lowest 14 bits of its address. VolatileFi templates use:
| Template | Flags |
|---|---|
| VolatilePair, Range Guard | BEFORE_SWAP, AFTER_INITIALIZE |
| Launch Shield | BEFORE_SWAP, AFTER_INITIALIZE |
| Flow Tilt | BEFORE_SWAP, AFTER_SWAP, AFTER_INITIALIZE |
Ownership and changes
The owner can change parameters only inside the template's limits, and every change waits 24 hours before it applies. Pending changes are public, so LPs can see them coming. Ownership can be transferred or renounced. A renounced hook keeps its last parameters forever.
Attaching pools
Pool key
A pool uses your hook when its PoolKey names the hook and sets the dynamic fee flag in the fee field:
PoolKey({
currency0: 0x0000000000000000000000000000000000000000, // ETH
currency1: TOKEN,
fee: 0x800000, // LPFeeLibrary.DYNAMIC_FEE_FLAG
tickSpacing: 60,
hooks: YOUR_HOOK
})
Initialize it through the v4 PoolManager at 0x000000000004444c5dc75cB358380D2e3dE08A90 on Ethereum, then add liquidity through the v4 position manager as usual.
Reading fees on chain
interface IVolatileFiHook {
/// Fees the next swap would pay, in hundredths of a bip.
function currentFees(PoolId id) external view returns (uint24 buyFee, uint24 sellFee);
/// Running averages behind those fees.
function state(PoolId id) external view returns (int256 trend, uint256 move, uint64 lastBlock);
function params() external view returns (Params memory);
function owner() external view returns (address);
}
Inside beforeSwap the hook returns the side's fee with LPFeeLibrary.OVERRIDE_FEE_FLAG set, so each swap pays exactly the fee shown by currentFees for its direction.
API reference
Authentication
Create a key on the API keys page. Send it as a bearer token:
Authorization: Bearer vf_live_...
Keys carry permissions. read is always included. deploy allows preparing hook and pool transactions. params allows proposing parameter changes on hooks your wallet owns. The API never holds your private key. Endpoints that change chain state return an unsigned transaction for you to sign.
Rate limits
| Permission | Requests per minute |
|---|---|
| read | 600 |
| deploy, params | 60 |
Holding $VOL raises these limits. See The $VOL token.
Responses include X-RateLimit-Remaining and X-RateLimit-Reset.
Hooks
/hooksValidates a hook config and returns the deploy transaction. Needs deploy.
{
"template": "volatilepair",
"name": "PEPE/ETH VolatilePair",
"owner": "0x...",
"params": { "floorFee": 500, "ceilingFee": 30000, "windowBlocks": 20, "maxTiltBps": 6000, "volScaleBps": 12 },
"signal": { "type": "pool" },
"lpShareBps": 10000
}
Response:
{
"id": "hk_7Qm2...",
"predictedAddress": "0x...1080",
"tx": { "to": "0xFactory...", "data": "0x...", "value": "0x0", "chainId": 1 }
}
/hooksHooks owned by the key's wallet. Supports ?template= and ?cursor=.
/hooks/{id}Config, deployed address, owner, pending changes and attached pools.
/hooks/{id}/paramsReturns a transaction that proposes new parameters. They apply 24 hours after it confirms. Needs params.
Pools
/hooks/{id}/poolsReturns the transactions to create and seed a pool that uses the hook.
{ "currency0": "ETH", "currency1": "0xToken...", "tickSpacing": 60, "sqrtPriceX96": "79228162514264337593543950336" }
/pools/{poolId}Pool key, hook, liquidity and 24 hour volume.
/pools/{poolId}/fees{ "buyFee": 4120, "sellFee": 2210, "move": 0.41, "tilt": 0.30, "block": 26193248 }
/pools/{poolId}/historyPer-block fees and price. Query with ?from= and ?to= block numbers, up to 10,000 blocks per call.
Webhooks
/webhooksRegister a URL for events: hook.deployed, pool.created, params.proposed, params.applied and fee.crossed (fires when a side's fee crosses a threshold you set). Each delivery is signed with an X-VolatileFi-Signature header, an HMAC-SHA256 of the body using your webhook secret.
/webhooks/{id}Stops deliveries for that webhook.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_params | A value is outside the template's limits. The response names the field. |
| 401 | bad_key | Missing, revoked or unknown key. |
| 403 | missing_scope | The key lacks the permission this call needs. |
| 403 | not_owner | The key's wallet does not own this hook. |
| 404 | not_found | No hook or pool with that id. |
| 429 | rate_limited | Wait until X-RateLimit-Reset. |
JavaScript example
const res = await fetch("https://api.volatile.finance/v1/hooks", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.VOLATILEFI_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify(config)
});
const { tx, predictedAddress } = await res.json();
const sent = await wallet.sendTransaction(tx); // ethers v6 signer
await sent.wait();
console.log("hook live at", predictedAddress);
The $VOL token
$VOL is the token of VolatileFi. It is live on Ethereum mainnet with a fixed supply of 1,000,000,000.
Paying for deployments
Deploying a hook through the VolatileFi factory can be paid in ETH or in $VOL. Paying in $VOL costs less, and the $VOL used is burned.
Higher API limits
Keys issued to a wallet that holds $VOL get higher rate limits. The limit is read from the wallet's balance when the key is used, so moving tokens out lowers it again.
| $VOL held | read per minute | deploy, params per minute |
|---|---|---|
| None | 600 | 60 |
| 100,000 | 3,000 | 300 |
| 1,000,000 | 12,000 | 1,200 |
Choosing new templates
New fee strategies are added to the factory by $VOL holder vote. Holders also vote on the limits each template allows, such as the highest ceiling fee and the shortest reaction window. A vote runs for five days and a passed change waits two more days before it applies.
Safety
What to know
- Fees are capped by the ceiling you set. A swap can never pay more than that.
- The hook cannot move funds out of a pool. It only sets the fee.
- Parameter changes are delayed 24 hours and are visible on chain while pending.
- A pool's hook cannot be swapped later. To change templates, create a new pool.
- Pool price signals can be pushed within a block. Templates average across blocks to blunt this, and the Chainlink signal option avoids it entirely.