▶ Interactive 35-second demo — real recorded runs, reproducible from this repo.
One paste field, two questions, three ecosystems (EVM · Solana · TRON):
safe / warn / block, each check with its evidence.Python stdlib only. No pip install, no keys, no account. Everything runs on your machine.
git clone https://github.com/anthonygozzini/guardbot && cd guardbot
python3 guardd.py # open http://127.0.0.1:8403/view
GUARDBOT_WC_PROJECT_ID=<id> python3 guardd.py).From the CLI or as an agent tool:
python3 tokencheck.py bsc 0x<token> # is it a trap?
python3 approvals.py 0x<wallet> # what has it approved? (also T… / Solana base58)
python3 revoke.py bsc approval 0x<token> 0x<spender> 0x<wallet> # prove the revoke first
python3 mcp_server.py # MCP: check_token, check_approvals,
# simulate_revoke — the agent tools
In a container, the way a registry or a sandboxed client starts it (no dependencies to install):
docker build -t guardbot . && docker run -i --rm guardbot # MCP over stdio
eth_call gives a throwaway address native
coin and trades the token atomically against the live pool. Sell reverts → honeypot. Money
missing from the round trip → that is the tax.homoglyphs.py), so a ticker
that only renders as USDT fails for the disguise itself.block, each for its own reason; one of them is shown as PASSED by
honeypot.is.approve(spender, 0),
setApprovalForAll(op, false), Permit2.approve(token, spender, 0, 0). No transfer, no
arbitrary call, no path around it.tools/testnet_e2e.py, self-tested against the RFC 8032 reference vectors).| Chain | History | Verdict engine |
|---|---|---|
| Ethereum, Arbitrum, Polygon | full logs (free Etherscan tier) | buy/sell simulation |
| Base | full logs (Blockscout, keyless) | buy/sell simulation |
| Optimism | free-RPC log scan | buy/sell simulation (Velodrome) |
| BSC | probe (96.6% coverage) + automatic deep scan | buy/sell simulation |
| Solana | SPL delegates via RPC | mint/extension reading |
| TRON | TronScan + TronGrid | bytecode power scan |
~/.guardbot — private, never uploaded).approve is always a transaction the owner signed). Verified: matches
revoke.cash to the decimal on a wallet the probe alone missed.partial or probed on screen. Never silently dropped.python3 tools/refresh.py re-mines everything.python3 -m unittest discover -s tests # 51 offline tests, ~0.3s
GUARDBOT_LIVE=1 python3 -m unittest discover -s tests # + 19 live tests on real chains
Many are regressions for bugs that actually shipped here. The testnet signing proof is
python3 tools/testnet_e2e.py solana|tron — throwaway local key, zero value at risk.
| Env var | Effect |
|---|---|
GUARDBOT_PORT |
port (default 8403) |
GUARDBOT_HOST=0.0.0.0 |
expose on your LAN (phone in the same Wi-Fi); default loopback |
GUARDBOT_WC_PROJECT_ID |
enables WalletConnect (free id from cloud.reown.com) |
GUARDBOT_ETHERSCAN_KEY |
free; speeds up log history on eth/arbitrum/polygon |
GUARDBOT_SOLANA_RPC / GUARDBOT_TRON_NETWORK |
point at testnets (devnet / nile) |
GUARDBOT_DEV_SEED=1 |
serves /dev/seed, a testnet-only page to create test grants |
GUARDBOT_NO_CACHE=1 |
disable the local index |
The repo is free forever; humans never pay for safety. For a hosted deployment there is a real
x402 rail: unpaid calls get HTTP 402 with the price, an agent pays USDC through a facilitator
(/verify + /settle, replay-guarded), and the paid endpoint serves the same first-hand
engines. Missing facilitator → paid calls are rejected, never faked.
GUARDBOT_PRICE_USDC=0.01 GUARDBOT_NETWORK=base-sepolia \
GUARDBOT_FACILITATOR=<url> GUARDBOT_PAY_TO=0x<you> python3 guardd.py
tokencheck.py / solcheck.py / troncheck.py — the first-hand safety enginesapprovals.py — multi-chain approvals scanner (+ local index)revoke.py — the three revoking calls + on-chain simulationguardd.py — HTTP daemon and /view UI · mcp_server.py — agent toolshomoglyphs.py — lookalike-character folding · keccak.py — pure-Python keccak256tools/ — miners (mine_*.py), refresh.py, deepscan_bsc.py, testnet_e2e.pyGuardBot is scored, not trusted. benchmark/harness.py replays check_token over a fixed set of
tokens whose nature was established by someone else, and publishes every wrong answer by name.
Ground truth is never GuardBot’s own verdict: a trap is either an impostor proven by an
on-chain fact (symbol() claims a major ticker while the canonical contract lives at another
address) or a honeypot labeled by GoPlus on a recorded date; a blue chip is a canonical
contract whose tradability nobody disputes. A trap counts only while its pool is alive — a dead
trap is blocked by anyone, so it is listed, not scored.
Run of 2026-09-19 23:23 UTC, GuardBot 9068887, 29 tokens (benchmark/results.json has every row):
| count | |
|---|---|
| Live traps in the set | 5 |
| Detected (blocked with the trap demonstrated) | 5 — 100% |
| Missed (answered safe) | 0 |
| Dead traps (pool empty, excluded) | 3 |
| Blue chips in the set, across BSC · Ethereum · Arbitrum · Base · Polygon | 21 |
| Wrongly blocked | 0 — 0% |
| Wrongly warned | 0 |
What the harness has already paid for, on its first run: Ethereum USDT came back block, a
false honeypot on the most traded token there is. The cause was a stranger’s leftover 4 USDT
allowance from the shared Multicall3 contract to the Uniswap router, which Tether’s approve()
refuses to overwrite; the sell simulation now zeroes the allowance first. That is the point of
measuring: the number was wrong before anyone said so.
What the numbers do not say:
benchmark/hunt.py collects fresh
launches and labels them with both GoPlus and honeypot.is; only tokens both agree on, with a
live pool, are added. The set grows as they are found; the rate is re-measured every release.Reproduce: python3 benchmark/harness.py (adds --relabel to re-ask GoPlus whether each trap
still is one). Extend: python3 benchmark/hunt.py collect bsc today, … label tomorrow.
This is a safety signal on public data, not financial advice.
MIT — see LICENSE.
Anthony Gozzini — project page · anthonygozzini.github.io