# 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.

Source: https://docs.crius.sh/concepts/uniswap-v4-hooks/ · Updated 2026-10-28

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](https://docs.crius.sh/concepts/uniswap/) 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` |

Example [Free plan · 2 credits](https://docs.crius.sh/reference/pools/hook-detail/)

### Shares, not counts: DopplerHookInitializer

DopplerHookInitializer (0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544) runs more pools than any other hook, and some of them were honeypots. Why is it low risk?

GET/v1/robinhood/hook/0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544

 

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/hook/0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544" \
  -H "x-api-key: $CRIUS_API_KEY"
```

**JavaScript**

```js
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();
```

**Python**

```python
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)**

```json
{
  "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: 9` and `liquidity_pulled_pools: 11` out of `pools_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.52` is 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 flag `high_tax_observed`.
-   `verified: true` and `code.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.
-   `events` shows what it emits (7,796 `Swap` and 1,724 `ModifyLiquidity` events in the scan) and `fee_tiers_in_scan` the pool fees seen, such as 10000 (1%) in 3 pools.

[Hook detail reference](https://docs.crius.sh/reference/pools/hook-detail/) [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20Shares%2C%20not%20counts%3A%20DopplerHookInitializer&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fconcepts%2Funiswap-v4-hooks%2F%23doppler%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Fhook%2F0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

## 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](https://docs.crius.sh/guides/check-uniswap-v4-hook-risk/#critical-hooks).

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](https://docs.crius.sh/guides/check-uniswap-v4-hook-risk/).

## 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

[Guide **Check v4 hook risk** Find out what a Robinhood Chain token's Uniswap v4 hook can do and what happened in its pools (taxes, honeypots, rugs). Real examples, including critical hooks. Read](https://docs.crius.sh/guides/check-uniswap-v4-hook-risk/) [Concept **Uniswap v2, v3 & v4** How Crius indexes Uniswap v2 pairs, v3 concentrated-liquidity pools and v4 singleton pools with hooks on Robinhood Chain, including liquidity definitions and v4 hook permissions. Read](https://docs.crius.sh/concepts/uniswap/) [Guide **Check token taxes** Get the real buy and sell tax of any Robinhood Chain token in one call, measured from recent trades and checked by simulation. Real examples with a 5% sell tax and a 7% buy tax. Read](https://docs.crius.sh/guides/check-token-taxes/) [Guide **Token security score** Score any Robinhood Chain token from 0 to 100 with one API call. Honeypot, buy and sell taxes, owner powers, LP locks, v4 hook risk and insider launches, with real examples. Read](https://docs.crius.sh/guides/token-security-score/) [API reference **Hook detail API** One hook: decoded permissions, code (kind, owner, admin functions), what happened in its pools, its code family's history, flags with evidence and risk level, and the events it emits. Read](https://docs.crius.sh/reference/pools/hook-detail/)
