Uniswap v4 hook risk: levels, flags and code families
How Crius rates every Uniswap v4 hook on Robinhood Chain, from its permissions, its code and owner, what happened in its pools and its code family's record, with each risk flag and its threshold.
A Uniswap v4 hook is a contract the pool calls around swaps and liquidity changes. It can take a fee, change swap amounts, block swaps or stop liquidity from moving, so a hook is part of a token’s risk even when the token’s own contract is clean. Crius rates every hook on Robinhood Chain from four kinds of evidence, turns each finding into a flag with a severity and an evidence sentence, and sets the hook’s risk_level to its worst flag.
Four kinds of evidence
| Evidence | What it is | Field |
|---|---|---|
| Permissions | The callbacks the hook can run, fixed in the low 14 bits of its address when it is deployed. They say what the hook could do. See Uniswap v2, v3 & v4 for the table. | permissions, flags_hex, capabilities |
| Code | What sits at the address and who controls it: kind (contract, minimal_proxy, upgradeable_proxy, beacon_proxy, delegated wallet or no_code), owner and ownership, and the admin_functions found in its code (fee_setter, pause, blacklist, withdraw, upgrade, arbitrary_call). | code |
| Observed | What happened in its own pools. A pool counts as traded with 10+ trades; as a honeypot with 10+ buys and no sells; as pulled when 80%+ of the liquidity added was removed again; as taxed when its median tax is 1% or more over 5+ measured trades; as dynamic when its sell tax swings by 5 points or more. | observed |
| Family and pattern | The same record summed over every hook with the same code (family) and over every hook with the same swap permissions (pattern). A new hook carries its family's history. | family, pattern |
Shares, not counts: DopplerHookInitializer
DopplerHookInitializer (0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544) runs more pools than any other hook, and some of them were honeypots. Why is it low risk?
curl "https://api.crius.sh/v1/robinhood/hook/0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544" \ -H "x-api-key: $CRIUS_API_KEY"const res = await fetch("https://api.crius.sh/v1/robinhood/hook/0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544", { headers: { "x-api-key": process.env.CRIUS_API_KEY },});const { data, meta } = await res.json();import os, requests
r = requests.get( "https://api.crius.sh/v1/robinhood/hook/0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544", headers={"x-api-key": os.environ["CRIUS_API_KEY"]},)body = r.json()print(body["data"])Real response 200 Captured Oct 28, 2026 · 124 lines (arrays trimmed)
{ "data": { "abi_events": [ "Collect(bytes32,uint256,uint256)", "Create(address,address,address)", "DelegateAuthority(address,address)" ], "address": "0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544", "attribution": "unattributed", "capabilities": { "can_block_swaps": false, "can_gate_liquidity": false, "can_modify_liquidity_amounts": false, "can_modify_swap_amounts": true }, "code": { "admin_functions": [], "checked_ts": 1793207143998, "code_hash": "0xc41a91106002f15bf70ae266824317f3f3ac638ac72ca5253bae395fa47ee631", "family": "0xaa37a5a3457a", "kind": "contract", "logic": null, "owner": null, "ownership": "none", "size": 25533 }, "events": [ { "emitted_in_scan": 7796, "event": "Swap(address,(address,address,uint24,int24,address),bytes32,(bool,int256,uint160),int128,int128,bytes)", "topic0": "0x1d9f7b5e406d8c887155e1a78e070d2d41c5d0444dab8b21612f846835c27183" }, { "emitted_in_scan": 1724, "event": "ModifyLiquidity((address,address,uint24,int24,address),(int24,int24,int256,bytes32))", "topic0": "0xdb675a606e5aa8f039e93c54673258dc875053bdaa5dbb96de1670bfdece53b3" }, { "emitted_in_scan": 545, "event": "Create(address,address,address)", "topic0": "0xb224da6575b2c2ffd42454faedb236f7dbe5f92a0c96bb99c0273dbe98464c7e" } ], "family": { "honeypot_pct": 0.0318652, "hooks": 1, "id": "0xaa37a5a3457a", "liquidity_pulled_pct": 0.0389463, "pools_traded": 28244, "taxed_pct": 1.78091, "verified_hooks": 1 }, "fee_tiers_in_scan": [ { "fee": 10000, "pools": 3 }, { "fee": 15000, "pools": 2 }, { "fee": 16000, "pools": 1 } ], "flags": [], "flags_hex": "0x2544", "launchpad": null, "launchpad_name": null, "name": "DopplerHookInitializer", "observed": { "dynamic_tax_pools": 24, "first_trade_ts": 1782922953000, "honeypot_pools": 9, "last_trade_ts": 1793223683000, "liquidity_pulled_pct": 0.0389463, "liquidity_pulled_pools": 11, "max_buy_tax_pct": 99.52, "max_sell_tax_pct": 93.49, "median_pool_life_min": 2138, "pools": 224061, "pools_traded": 28244, "tax_measured_pools": 5814, "taxed_10pct_pools": 29, "taxed_pools": 503, "volume_usd": 1968346259 }, "pattern": { "description": "hooks that change swap amounts only", "honeypot_pct": 0.0696347, "id": "swap_delta_only", "liquidity_pulled_pct": 7.93603, "pools_traded": 43082, "taxed_pct": 15.7537 }, "permissions": [ "beforeInitialize", "afterAddLiquidity", "afterRemoveLiquidity" ], "pools": 224090, "risk": [ "can_modify_swap_amounts" ], "risk_level": "low", "stats": { "pools_created_24h": 1181, "trades_24h": 59387, "volume_usd_24h": 7478239 }, "verified": true }, "meta": { "block": 100406861, "block_age_ms": 985, "block_ts": 1793225084000, "chain": "robinhood", "finalized_block": 100397649, "intel_computed_ts": 1793223685333, "lag_ms": 107, "safe_block": 100401329 }}What this tells you
observed.honeypot_pools: 9andliquidity_pulled_pools: 11out ofpools_traded: 28244. In absolute numbers that sounds bad; as shares it is 0.03% and 0.04% (family.honeypot_pct: 0.0318652,liquidity_pulled_pct: 0.0389463).observed.max_buy_tax_pct: 99.52is one pool’s tax; only 29 of 5,814 measured pools take 10% or more (taxed_10pct_pools,tax_measured_pools), far short of the half that would flaghigh_tax_observed.verified: trueandcode.ownership: "none": a known protocol hook with no owner, so its permissions and pattern don’t add flags.flags: [],risk_level: "low".pattern.id: "swap_delta_only": hooks that change swap amounts but can’t block swaps. Across 43,082 traded pools, 0.07% of them became honeypots.eventsshows what it emits (7,796Swapand 1,724ModifyLiquidityevents in the scan) andfee_tiers_in_scanthe pool fees seen, such as 10000 (1%) in 3 pools.
Risk flags
| Flag | Severity | Raised when |
|---|---|---|
no_code | critical | There is no contract at the hook address: every callback the pool makes to it fails. |
delegated_wallet | critical | The hook is a wallet delegating to code (EIP-7702): its owner can replace the code at any time. |
honeypot_observed | critical | 20% or more of its own traded pools had 10+ buys and no sells. |
honeypot_family | critical | 20% or more of its code family's traded pools (10+ needed) became honeypots. |
rug_family | high (medium with a clean record) | Liquidity was pulled in 80% or more of its family's traded pools. |
rugs_observed | high | Liquidity was pulled in 80% or more of its own traded pools (3+ needed). |
can_block_swaps | high (medium with a clean record) | It runs before swaps without taking a delta, a pattern with a high honeypot rate. The evidence quotes that rate. |
high_tax_observed | high | Half or more of its measured pools take 10% or more per trade. |
upgradeable | medium | It is an upgradeable or beacon proxy: what it does can change after launch. |
tax_observed | medium | A fifth or more of its measured pools take 1% or more per trade. |
dynamic_tax | medium | A tenth or more of its measured pools had their tax swing by 5 points or more. |
honeypot_pools_seen | medium | Some of its pools were honeypots, but fewer than 20%. |
fee_changeable | medium | It has a fee or tax setter and an owner that hasn't renounced. |
owner_controls | medium | Its owner can call pause, blacklist, withdraw, upgrade or arbitrary-call functions. |
new_unknown | medium | Its first trade was under 24 hours ago and its code family has fewer than 10 traded pools. |
can_modify_swap_amounts | low | It can take part of every swap. For information: this is how launchpad fee hooks work, and the safest pattern on chain. |
Real examples of the critical flags, with their evidence sentences (no_code with 142 of 143 pools rugged, honeypot_family, honeypot_observed), are in the critical hooks example.
A clean record is 20+ traded pools of its own, no honeypots and liquidity pulled in under a fifth of them. It outweighs the family and permission statistics, which is why those two flags drop to medium for a hook that has proven itself.
Verified hooks (verified: true: launchpads and known protocols) can only get honeypot_observed, high_tax_observed and dynamic_tax from what happened in their pools, and no_code or delegated_wallet from their code. Family, permission and ownership flags, and the milder tax and honeypot flags, don’t apply to them.
How hook risk reaches a token
/security attaches the hook of the pool the token is priced from. The token loses 60 points for a critical hook (hook_critical_risk, which also makes the token high risk), 30 for high (hook_high_risk) and 10 for medium (hook_medium_risk). If the hook can block swaps, hook_can_block_swaps is listed for information. For an example of a medium-risk hook that taxes, and how to show the evidence in an app, see Check the risk of a Uniswap v4 hook.
Frequently asked questions
What is a hook code family?
Hooks whose code has the same set of functions belong to one family, even when values set at deployment differ. Families are how a hook deployed a minute ago can already have a history: if other hooks with the same code trapped their buyers, the new one is flagged honeypot_family. Hook 0x593da569c2a5a6999f59fcc5b06477d8bb4dc080 is critical with no traded pools of its own, because 94% of the 35 traded pools of its family 0x6f11e9734465 (34 hooks) became honeypots.
Why are verified hooks treated differently?
Hooks verified in Crius's registry (launchpad and known protocol hooks) have known code and a known operator, so their permissions and family statistics say little. They are judged only on what happened in their own pools, and a launchpad's standard fee isn't flagged as a tax.
Can a hook's risk level change?
Yes. Risk is recomputed every 30 minutes from what happens in its pools, and hooks whose code can change (proxies, delegated wallets) are re-inspected every 6 hours. A new hook with no history can drop from high to medium once it has a long clean record of its own.
Related
Get your free Crius API key
Every example on this page works with a free key: higher rate limits than the anonymous plan, holders, wallets and the WebSocket stream. No card needed.
- Robinhood Chain (4663) only, from our own archive nodes
- REST + WebSocket
- Pay on-chain or by card