# Add safety checks to a Robinhood Chain trading bot

> Keep a Robinhood Chain trading bot away from honeypots, high taxes and pullable liquidity: pre-trade checks with Crius, then live tax and LP alerts.

Source: https://docs.crius.sh/guides/add-safety-checks-to-a-trading-bot/ · Updated 2026-10-28

Short answer

Before each buy, call `GET /v1/robinhood/token/{address}/security` (skip `risk: "critical"`, honeypots and taxes above your limit; read `flags` for unlocked or single-wallet liquidity) and `GET /v1/robinhood/token/{address}/price` (skip `thin_liquidity` and trades large against `quote_liquidity_usd`). That's 2 credits per check, anonymous plan. While you hold, subscribe to `tax:` and `lp:` for the token on the WebSocket stream.

[GET `/token/{address}/security`](https://docs.crius.sh/reference/security/security-checks/) [GET `/token/{address}/price`](https://docs.crius.sh/reference/tokens/token-price/) [GET `/token/{address}/liquidity`](https://docs.crius.sh/reference/security/liquidity-locks/) [GET `/token/{address}/bundles`](https://docs.crius.sh/reference/wallet-graph/snipers-bundles-clusters/)

A trading bot on Robinhood Chain needs to answer four questions before it buys: can it sell again, what will the round trip cost in taxes, can the liquidity disappear while it holds, and is the price real enough for the size it wants to trade. Crius answers the first three in one [security](https://docs.crius.sh/reference/security/security-checks/) call and the fourth in one [price](https://docs.crius.sh/reference/tokens/token-price/) call, both on the anonymous plan. While the bot holds a position, the WebSocket stream tells it when the token’s tax changes or liquidity is removed.

## Check 1: can the bot sell, and at what tax?

Example [Anonymous · no key · 1 credit](https://docs.crius.sh/reference/security/security-checks/)

### A honeypot with 0% realized tax

Let's End AI (0xc882f10529a5518ee3393af5a80e9ff00d38d44b) shows no tax on past trades. Should the bot buy?

GET/v1/robinhood/token/0xc882f10529a5518ee3393af5a80e9ff00d38d44b/security

  

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/token/0xc882f10529a5518ee3393af5a80e9ff00d38d44b/security"
```

**JavaScript**

```js
const res = await fetch("https://api.crius.sh/v1/robinhood/token/0xc882f10529a5518ee3393af5a80e9ff00d38d44b/security");
const { data, meta } = await res.json();
```

**Python**

```python
import requests

r = requests.get(
    "https://api.crius.sh/v1/robinhood/token/0xc882f10529a5518ee3393af5a80e9ff00d38d44b/security",
)
body = r.json()
print(body["data"])
```

**Real response 200 Captured Oct 28, 2026 · 140 lines (arrays trimmed)**

```json
{
  "data": {
    "contract": {
      "blacklist": false,
      "can_change_limits": false,
      "can_change_tax": false,
      "cooldown": false,
      "implementation": null,
      "is_proxy": false,
      "mintable": false,
      "owner": "0x0000000000000000000000000000000000000000",
      "ownership": "renounced",
      "pausable": false,
      "proxy_kind": null,
      "self_destruct": false,
      "trading_switch": true,
      "upgradeable": false,
      "verified": "none"
    },
    "flags": [
      "honeypot",
      "unverified",
      "uniform_holders"
    ],
    "honeypot": {
      "is_honeypot": true,
      "reason": "simulated sell failed",
      "selective": false
    },
    "hook": null,
    "known_asset": false,
    "launch": {
      "flags": [
        "uniform_holders"
      ],
      "lp_top_wallet": {
        "address": "0xabe3a51937eb4c76ab6449e9823dbffd4409776f",
        "liquidity_usd": 8.58651,
        "pct": 0.0253312
      },
      "sniper_supply_pct": 0.000299049,
      "sniper_top_wallet_pct": 0.000299049,
      "sniper_wallets": 1,
      "sniper_window_blocks": 10,
      "uniform_holders": {
        "balance_pct": 0.112731,
        "holders": 51,
        "of_top": 100
      },
      "wallet_farm": null
    },
    "limits": {
      "max_tx": "1000000000",
      "max_tx_getter": "maxTxAmount()",
      "max_tx_pct": 100,
      "max_wallet": "1000000000",
      "max_wallet_getter": "maxWalletSize()",
      "max_wallet_pct": 100
    },
    "liquidity": {
      "status": "burned",
      "summary": {
        "burned_pct": 99.9715,
        "locked_pct": 0,
        "next_unlock_ts": null,
        "protocol_fee_pct": 0,
        "unlocked_in_wallets_pct": 0.0284848,
        "weighting": "by pool liquidity_usd"
      }
    },
    "primary_dex": "uniswap_v2",
    "risk": "critical",
    "score": 0,
    "tax": {
      "buy_pct": 0,
      "confidence": "high",
      "realized": {
        "buy_pct": 0,
        "by_wallet_class": {
          "dev_sell_pct": null,
          "others_sell_pct": 0
        },
        "last_sample_ts": 1793224820000,
        "max_sell_pct_seen": 0,
        "samples": {
          "buys": 27197,
          "sells": 3423
        },
        "sell_pct": 0,
        "window": "30d"
      },
      "sell_pct": 0,
      "simulated": {
        "amount_eth": 0.042454083286938696,
        "buy_gas": 159144,
        "buy_pct": 0,
        "can_buy": true,
        "can_sell": false,
        "can_transfer": true,
        "from": "eoa",
        "revert_reason": {
          "code": 3,
          "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000245472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c454400000000000000000000000000000000000000000000000000000000",
          "message": "execution reverted: TransferHelper: TRANSFER_FROM_FAILED"
        },
        "router": "0x89e5db8b5aa49aa85ac63f691524311aeb649eba",
        "sell_gas": 229228,
        "sell_pct": null,
        "transfer_pct": 0
      },
      "source": "realized",
      "transfer_pct": 0
    },
    "tax_history": [
      {
        "from_block": 62239227,
        "pct": 0,
        "side": "buy"
      },
      {
        "from_block": 62240181,
        "pct": 0,
        "side": "sell"
      }
    ],
    "tax_history_total": 2,
    "tax_mode": "static",
    "token": "0xc882f10529a5518ee3393af5a80e9ff00d38d44b"
  },
  "meta": {
    "block": 100406838,
    "block_age_ms": 1257,
    "block_ts": 1793225081000,
    "chain": "robinhood",
    "finalized_block": 100397649,
    "lag_ms": 14,
    "safe_block": 100401329,
    "simulation": "eth_simulateV1 via Uniswap V2 router at head"
  }
}
```

What this tells you

-   `risk: "critical"`, `score: 0`, `honeypot.is_honeypot: true` with `reason: "simulated sell failed"`. The bot must not buy.
-   The trap is invisible in the tax numbers: `tax.buy_pct` and `tax.sell_pct` are 0 and `tax.realized.samples` counts 27,197 buys and 3,423 sells. A bot that only checks realized tax would buy this token.
-   `tax.simulated` shows what happened at the head block: `can_buy: true`, `can_transfer: true`, `can_sell: false`, and the revert message `"execution reverted: TransferHelper: TRANSFER_FROM_FAILED"`.
-   `meta.simulation` names the method: `"eth_simulateV1 via Uniswap V2 router at head"`.

[Security checks reference](https://docs.crius.sh/reference/security/security-checks/) Runs from your browser on the anonymous plan [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20A%20honeypot%20with%200%25%20realized%20tax&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fguides%2Fadd-safety-checks-to-a-trading-bot%2F%23honeypot%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Ftoken%2F0xc882f10529a5518ee3393af5a80e9ff00d38d44b%2Fsecurity%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

## Check 2: can the liquidity disappear?

Example [Anonymous · no key · 1 credit](https://docs.crius.sh/reference/security/security-checks/)

### A $1 billion market cap backed by $3,795 in one wallet's hands

MJDQ (0x124597e2d8bbe472825c4918a36de246ed0c92f7) ranks near the top by market cap. Is it safe to hold?

GET/v1/robinhood/token/0x124597e2d8bbe472825c4918a36de246ed0c92f7/security

  

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/token/0x124597e2d8bbe472825c4918a36de246ed0c92f7/security"
```

**JavaScript**

```js
const res = await fetch("https://api.crius.sh/v1/robinhood/token/0x124597e2d8bbe472825c4918a36de246ed0c92f7/security");
const { data, meta } = await res.json();
```

**Python**

```python
import requests

r = requests.get(
    "https://api.crius.sh/v1/robinhood/token/0x124597e2d8bbe472825c4918a36de246ed0c92f7/security",
)
body = r.json()
print(body["data"])
```

**Real response 200 Captured Oct 28, 2026 · 111 lines (arrays trimmed)**

```json
{
  "data": {
    "contract": {
      "blacklist": false,
      "can_change_limits": false,
      "can_change_tax": false,
      "cooldown": false,
      "implementation": null,
      "is_proxy": false,
      "mintable": false,
      "owner": null,
      "ownership": "none",
      "pausable": false,
      "proxy_kind": null,
      "self_destruct": false,
      "trading_switch": false,
      "upgradeable": false,
      "verified": "match"
    },
    "flags": [
      "lp_unlocked",
      "lp_single_wallet"
    ],
    "honeypot": {
      "is_honeypot": false,
      "reason": null,
      "selective": false
    },
    "hook": null,
    "known_asset": false,
    "launch": {
      "flags": [
        "lp_single_wallet"
      ],
      "lp_top_wallet": {
        "address": "0xe591376415858cae27c81c0813bbaef3a0a46d6a",
        "liquidity_usd": 3795.38,
        "pct": 100
      },
      "sniper_supply_pct": 0.000000291623,
      "sniper_top_wallet_pct": 0.000000291623,
      "sniper_wallets": 1,
      "sniper_window_blocks": 10,
      "uniform_holders": null,
      "wallet_farm": null
    },
    "limits": {},
    "liquidity": {
      "status": "unlocked",
      "summary": {
        "burned_pct": 0,
        "locked_pct": 0,
        "next_unlock_ts": null,
        "protocol_fee_pct": 0,
        "unlocked_in_wallets_pct": 100,
        "weighting": "by pool liquidity_usd"
      }
    },
    "primary_dex": "uniswap_v4",
    "risk": "medium",
    "score": 55,
    "tax": {
      "buy_pct": 0,
      "confidence": "medium",
      "realized": {
        "buy_pct": 0,
        "by_wallet_class": {
          "dev_sell_pct": null,
          "others_sell_pct": 0
        },
        "last_sample_ts": 1792087347000,
        "max_sell_pct_seen": 0,
        "samples": {
          "buys": 6,
          "sells": 4
        },
        "sell_pct": 0,
        "window": "30d"
      },
      "sell_pct": 0,
      "simulated": null,
      "source": "realized",
      "transfer_pct": null
    },
    "tax_history": [
      {
        "from_block": 89408576,
        "pct": 0,
        "side": "buy"
      },
      {
        "from_block": 89421448,
        "pct": 0,
        "side": "sell"
      }
    ],
    "tax_history_total": 2,
    "tax_mode": "static",
    "token": "0x124597e2d8bbe472825c4918a36de246ed0c92f7"
  },
  "meta": {
    "block": 100409718,
    "block_age_ms": 765,
    "block_ts": 1793225377000,
    "chain": "robinhood",
    "finalized_block": 100401329,
    "lag_ms": 48,
    "safe_block": 100405028,
    "simulation": "no V2 WETH pair: realized tax only"
  }
}
```

What this tells you

-   `score: 55`, `risk: "medium"`, `flags`: `lp_unlocked` and `lp_single_wallet`. No honeypot, no tax, and the source is verified (`contract.verified: "match"`).
-   `launch.lp_top_wallet` is `0xe591376415858cae27c81c0813bbaef3a0a46d6a` with `pct: 100` and `liquidity_usd: 3795.38`: one wallet owns the whole pool and can withdraw it at any time (`liquidity.summary.unlocked_in_wallets_pct: 100`).
-   The tax is measured from only 6 buys and 4 sells (`tax.realized.samples`), so `tax.confidence` is `medium`, and `tax.simulated` is `null` (`meta.simulation`: `"no V2 WETH pair: realized tax only"`).
-   The token list shows this token with a market cap of about $1 billion and 4 holders. Size trades by liquidity, never by market cap. The [Telegram scanner guide](https://docs.crius.sh/guides/build-a-telegram-token-scanner/#after-pull) shows a token with the same two flags whose pool was emptied a minute after its check.

[Security checks reference](https://docs.crius.sh/reference/security/security-checks/) Runs from your browser on the anonymous plan [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20A%20%241%20billion%20market%20cap%20backed%20by%20%243%2C795%20in%20one%20wallet's%20hands&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fguides%2Fadd-safety-checks-to-a-trading-bot%2F%23single-wallet-lp%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Ftoken%2F0x124597e2d8bbe472825c4918a36de246ed0c92f7%2Fsecurity%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

## The rules

| Check | Field | Suggested rule |
| --- | --- | --- |
| Sellable | `honeypot.is_honeypot`, `risk` | Never buy `critical` or a honeypot; treat `honeypot.selective` (only some wallets can sell) the same |
| Taxes | `tax.buy_pct`, `tax.sell_pct`, `tax.confidence` | Skip above your round-trip budget; require `high` confidence or a fresh simulation for size |
| Launch | `flags`: `insider_launch`, `wallet_farm` | Skip: insiders sniped most of the supply, or the holders are a farm of wallets funded together |
| Liquidity | `flags`: `lp_unlocked`, `lp_single_wallet`; `liquidity.summary` | Skip or cut size when one wallet can pull the pool |
| Hook | `flags`: `hook_critical_risk`, `hook_high_risk` | Skip: the pool's v4 hook can block swaps, has no code, or its code family has a record of rugs or honeypots |
| Price | `thin_liquidity`, `confidence`, `quote_liquidity_usd` | Skip thin or low-confidence prices; keep the trade a small share of the quote side |

The thresholds are yours to choose. The fields are the same for every token, so the rules stay a few lines of code.

## Use it in your bot

1.  **Check before every buy.** Call security and price in parallel (2 credits). Cache the result for a minute or two per token: a bot that fires several orders into the same token doesn’t need a new check for each.
    
2.  **Re-simulate before large trades.** On Starter and above, `?fresh=1&amount_usd=<size>` runs a new buy, transfer and sell simulation at your trade size (20 credits, `simulate` scope).
    
3.  **Watch what you hold.** Subscribe to `tax:<token>` and `lp:<token>` on the stream for each open position. A tax change arrives as `side`, `from`, `to`; a liquidity removal as `type: "remove_liquidity"` with the pool, `provider` and amounts.
    
4.  **Go deeper when it matters.** [Liquidity & locks](https://docs.crius.sh/reference/security/liquidity-locks/) (5 credits, Free) shows each LP position and unlock date; [snipers & bundles](https://docs.crius.sh/reference/wallet-graph/snipers-bundles-clusters/) (10 credits, Starter) shows who bought the launch.
    

```js
// safety.mjs: pre-trade checks and position watch for a Robinhood Chain bot (Node.js 22+)
const API = "https://api.crius.sh/v1/robinhood";
const KEY = process.env.CRIUS_API_KEY;
const HEADERS = KEY ? { "x-api-key": KEY } : {};
const MAX_TAX_PCT = 5;
const MAX_SHARE_OF_QUOTE = 0.01; // trade at most 1% of the pool's quote side
const BLOCK_FLAGS = ["insider_launch", "wallet_farm", "hook_critical_risk", "hook_high_risk", "lp_single_wallet"];

const get = async (path) => (await (await fetch(`${API}${path}`, { headers: HEADERS })).json()).data;

export async function preTradeCheck(token, sizeUsd) {
  const [s, p] = await Promise.all([get(`/token/${token}/security`), get(`/token/${token}/price`)]);
  const no = [];
  if (!s || !p) return { ok: false, reasons: ["no data for this token"] };
  if (s.risk === "critical" || s.honeypot?.is_honeypot || s.honeypot?.selective) no.push(`can't sell: ${s.honeypot?.reason ?? s.risk}`);
  if ((s.tax?.buy_pct ?? 0) + (s.tax?.sell_pct ?? 0) > MAX_TAX_PCT) no.push(`round-trip tax ${s.tax.buy_pct}% + ${s.tax.sell_pct}%`);
  for (const f of s.flags ?? []) if (BLOCK_FLAGS.includes(f)) no.push(`flag ${f}`);
  if (p.thin_liquidity || p.confidence === "low") no.push(`unreliable price (${p.confidence})`);
  if (sizeUsd > (p.quote_liquidity_usd ?? 0) * MAX_SHARE_OF_QUOTE) no.push(`$${sizeUsd} is too large for $${p.quote_liquidity_usd} of quote liquidity`);
  return { ok: no.length === 0, reasons: no, score: s.score, priceUsd: p.usd };
}

// Live alerts for open positions: tax changes and liquidity removals.
export function watchPositions(tokens, onAlert) {
  const ws = new WebSocket(`wss://api.crius.sh/v1/robinhood/stream?api_key=${KEY}`);
  let idle;
  const touch = () => {
    clearTimeout(idle);
    idle = setTimeout(() => ws.close(), 45_000);
  };
  ws.onopen = () => {
    touch();
    ws.send(JSON.stringify({ op: "subscribe", channels: tokens.flatMap((t) => [`tax:${t}`, `lp:${t}`]) }));
  };
  ws.onmessage = (e) => {
    touch();
    const m = JSON.parse(e.data);
    if (m.data?.removed) return;
    if (m.ch.startsWith("tax:")) onAlert({ token: m.data.token, kind: "tax", text: `${m.data.side} tax ${m.data.from}% → ${m.data.to}%` });
    if (m.ch.startsWith("lp:") && m.data.type === "remove_liquidity") {
      onAlert({ token: m.ch.slice(3), kind: "lp", text: `liquidity removed from ${m.data.pool} by ${m.data.provider}` });
    }
  };
  ws.onclose = () => {
    clearTimeout(idle);
    setTimeout(() => watchPositions(tokens, onAlert), 2000 + Math.random() * 1000);
  };
  ws.onerror = () => ws.close();
}

// Example: check before buying $200 of a token, then watch it.
const token = "0x124597e2d8bbe472825c4918a36de246ed0c92f7";
const verdict = await preTradeCheck(token, 200);
console.log(verdict.ok ? "OK to buy" : `skip: ${verdict.reasons.join("; ")}`);
if (verdict.ok && KEY) watchPositions([token], (a) => console.log("ALERT", a));
```

Run against the MJDQ token above, it prints `skip: flag lp_single_wallet; $200 is too large for $1897.69 of quote liquidity` (the quote side is half of the $3,795.38 pool). Either rule alone keeps the bot out; against the honeypot it stops at `can't sell: simulated sell failed`.

What a check can't see

These checks cover what is on chain: the contract, the taxes paid, the liquidity and who bought the launch. A token can pass every one and still fall because its holders sell. Treat a pass as “no trap found”, and size positions accordingly.

## Frequently asked questions

**Is the realized tax enough to know a token can be sold?**

No. Realized tax describes trades that already happened. A contract can stop sells later, and the honeypot sample below shows 0% realized tax on a token whose sell simulation now reverts. Gate on `honeypot.is_honeypot` and `risk` as well as on `tax`.

**How fresh is the security check my bot reads?**

Realized taxes update with every block; contract checks and the sell simulation are cached per token. `meta.block` tells you the block the answer reflects. On Starter and above, `?fresh=1` re-runs the simulation on demand (20 credits, key with the `simulate` scope) and `amount_usd` sets its size.

**What does a pre-trade check cost?**

Security and price are 1 credit each, so 2 credits per token checked; without a key both work at 2 requests per second. Optional deeper checks: liquidity and locks 5 credits (Free plan), bundles and snipers 10 (Starter), a fresh simulation 20 (Starter).

**How do I know when a token I hold changes its tax?**

Subscribe to `tax:<token>` on the [WebSocket stream](https://docs.crius.sh/reference/stream/). When the realized buy or sell tax moves by a whole percent, you get `side`, `from` and `to` (percent) and can exit before the next trade pays it.

## Related

[Use case **Trading bots** What a Robinhood Chain trading bot needs from the Crius API: new launches, live prices, pools and safety checks before every buy, with credit costs. Read](https://docs.crius.sh/use-cases/trading-bots/) [Guide **Detect a honeypot** Check whether a Robinhood Chain token can be sold before you buy it. One API call simulates a buy and a sell and checks real trades; a real honeypot example shows the evidence. Read](https://docs.crius.sh/guides/detect-honeypot/) [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 **Check liquidity locks** Find out whether a Robinhood Chain token's liquidity is locked, burned or held by wallets that can pull it, pool by pool, with the locker and unlock date. Real examples from Pons tokens. Read](https://docs.crius.sh/guides/check-liquidity-locked/) [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/) [Concept **Token taxes** How Crius measures buy, sell and transfer taxes on Robinhood Chain tokens from real trades and from a simulated buy and sell, how the two are combined, and how tax changes are tracked. Read](https://docs.crius.sh/concepts/taxes/)
