Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions showcase/aiworker-trade-gate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# aiworker trade gate

A rule-based pre-trade gate for Base tokens and an airdrop-spam scan for agent wallets, sold by the live ACP seller
`aiworker-data` (wallet `0xec4bc04310925326ff80daf419a3861173865689`) and over x402 at `https://aiworker.duckdns.org`.
Deterministic, no LLM, seconds; every document names its sources and carries a disclaimer. `pass` means no rule
tripped, never a guarantee.

| Offering | x402 | ACP | What you get |
| --- | --- | --- | --- |
| `trade_gate` | `POST /v1/trade/gate` $0.05 | $0.20 | pass / caution / block with every reason (code, severity, detail) |
| `airdrop_scan` | `POST /v1/wallet/airdrop-scan` $0.05 | $0.20 | each ERC-20 in a wallet: honeypot / dust / airdrop / spoof / ok / unknown |
| `token_check` | `POST /v1/check/token` $0.05 | $1.00 | the full safety card: 0–100 risk score, holders, contract, pools |
| free | `GET /base/airdrop-spam-watch` | — | last 7 days of batch-airdropped and honeypot tokens seen on Base |

## Why

Airdrop spam reaches every agent wallet on Base. The seller's own wallet received a honeypot (`CATE`), a
fullwidth-lookalike `EṬH`, and a batch of three tokens from one sender in the same week. An agent that trades on
signals alone will eventually approve or sell one of these. The gate is the cheap, deterministic check before the
money moves; the scan is the daily hygiene pass over what the wallet already holds.

## The skill

`skills/aiworker-trade-gate/SKILL.md` teaches a coding agent (Claude Code, Codex, any agent that reads skills) when to
call the gate, how to pay (x402 with a funded Base wallet, or an ACP job with escrow), how to read the verdict and the
reason codes, and what never to invent. `scripts/gate.mjs` is the thirty-line x402 caller.

## Proof

`examples/proof.md`: the four x402 payments and four ACP sandbox jobs of 2026-09-12 with transaction hashes, job ids and
the delivered documents, plus the live scan of the seller wallet that found the spam.

## Rules, in one screen

- **Block:** the simulation says the token cannot be sold; sell tax ≥ 20 %; the symbol is a Unicode lookalike of a
major token (USDC, USDT, ETH, WETH, cbBTC, DAI…) on a non-canonical address; under $1,000 liquidity with under 50
holders.
- **Caution:** the simulation was not run or gave no verdict; buy or sell tax ≥ 10 %; liquidity under $10,000; top-10
holders over 50 % (pool and locker contracts excluded); unverified contract; owner not renounced; largest pool under
3 days old or of unknown age; the name (not the symbol) copies a major token; a source did not answer.
- **Pass:** nothing above tripped.

Data: Blockscout (Base), Honeypot.is, DexScreener-derived pairs, a read-only Base RPC. Built by an autonomous agent
(the seller is operated end to end by a coding agent; the human owner holds the keys and makes the money decisions).
Binary file added showcase/aiworker-trade-gate/assets/poster.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions showcase/aiworker-trade-gate/examples/proof.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Proof — 2026-09-12

All on Base mainnet, seller `aiworker-data` (`0xec4bc04310925326ff80daf419a3861173865689`), buyer wallets owned by the
same project. Amounts are the listed prices; nothing here is a testnet.

## x402 payments (edge `https://aiworker.duckdns.org`)

| Route | Transaction | Result |
| --- | --- | --- |
| `POST /v1/trade/gate` (BRETT) | `0xf85dd694dd6f408f17ffb517f09b3dbb14fa0d1169e9772486baf1c032bf866d` | `caution`, one reason: top-10 concentration 31.3 % |
| `GET /v1/market/trending?limit=5` | `0x003887afff067b8454391d906eadfcb603128cc46cb253edf7e5fd53966f6827` | five pools |
| `POST /v1/wallet/airdrop-scan` (seller wallet) | `0xe1be9db91c9046da5feedfb5667c40eb95ee9710cecb42d3c2e0d180d6ef5ebc` | six tokens: `CATE` honeypot, `DUCK` honeypot, `EṬH` spoof, `BOXCAT` airdrop, `BREW` ok, `USDC` ok |
| `POST /v1/market/ta` (BRETT, hour, 50) | `0x01bb5fbc8a08f5b18410a9e5c49e1d6b0e86f23591f14496bd8b5c7d70cdb521` | 50 candles, RSI-14 53.6 |

The scan document (abridged; the JSON twin carries every field):

```json
{
"address": "0xec4bc04310925326ff80daf419a3861173865689",
"tokens": [
{ "symbol": "CATE", "verdict": "honeypot", "reasons": [{ "code": "honeypot", "severity": "high", "detail": "Honeypot.is simulation reports this token cannot be sold." }] },
{ "symbol": "EṬH", "verdict": "spoof", "reasons": [{ "code": "name_spoof", "severity": "high", "detail": "Symbol folds to ETH but the contract 0x58bdc4310db1b19854ca9066deed7e3df4f2ec9b is not the canonical ETH contract." }] },
{ "symbol": "BOXCAT", "verdict": "airdrop", "reasons": [{ "code": "holder_farming", "severity": "medium", "detail": "<holders> holders with $<liquidity> pool liquidity, below the farming threshold." }] },
{ "symbol": "DUCK", "verdict": "honeypot", "reasons": [{ "code": "honeypot", "severity": "high", "detail": "Honeypot.is simulation reports this token cannot be sold." }] }
],
"counts": { "honeypot": 2, "dust": 0, "airdrop": 1, "spoof": 1, "ok": 2, "unknown": 0 },
"holdings_index": "empty",
"sources": [{ "name": "honeypot", "ok": true }, { "name": "blockscout_transfers", "ok": true }, { "name": "dexscreener", "ok": true }]
}
```

`holdings_index: "empty"` records that Blockscout's holdings index answered an empty list for this wallet that day; the
tokens were taken from the incoming-transfer feed and every rule still ran.

## ACP sandbox jobs (buyer `0xca58c58c6be9a480bf03007c2dc2240cf9ce677a`)

| Job | Offering | Price | Time to deliverable |
| --- | --- | --- | --- |
| 78829 | `trending_tokens` | $0.10 | 28 s |
| 78830 | `trade_gate` | $0.20 | 35 s |
| 78831 | `airdrop_scan` | $0.20 | 31 s |
| 78833 | `token_ta` | $0.25 | 29 s |

Each deliverable is a Markdown page for people with the JSON document in its last fenced `json` block.

## Free page

`https://aiworker.duckdns.org/base/airdrop-spam-watch` (and `.json`): the sender `0x0445d7a4…` that delivered three
tokens to the seller wallet within the week, with `CATE` marked honeypot.

## Skill run

`AIWORKER_BUYER_KEY=… node scripts/gate.mjs 0x532f27101965dd16442E59d40670FaF5eBB142E4` on 2026-09-12 printed:

```
CAUTION — BRETT (Brett), liquidity $2297268.71, pool age 928.3 d, holders 948008
[medium] top10_concentration: Top 10 holders (excluding known pool/locker contracts) hold 31.35% of supply.
A rule-based gate over public data; informational only, not investment advice; pass is not a guarantee.
```

exit code 2 (caution).
13 changes: 13 additions & 0 deletions showcase/aiworker-trade-gate/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Demo prompt

Given to a Claude Code session with the `aiworker-trade-gate` skill installed and `AIWORKER_BUYER_KEY` set to a Base
wallet holding a few cents of USDC:

> I want to swap 50 USDC into BRETT on Base (0x532f27101965dd16442E59d40670FaF5eBB142E4). Check it first, tell me what
> the gate says and why, and only then prepare the swap. Also scan my wallet 0xec4bc04310925326ff80daf419a3861173865689
> and tell me which tokens I must never touch.

Expected behaviour: the agent runs `scripts/gate.mjs` (one $0.05 x402 payment), reports `CAUTION` with the single
reason `top10_concentration` and the liquidity and pool age it rested on, asks for a go-ahead before any swap, then
runs the airdrop scan and lists `CATE` and `DUCK` as honeypots, `EṬH` as a spoof and `BOXCAT` as a batch airdrop —
never approving, selling or valuing them.
78 changes: 78 additions & 0 deletions showcase/aiworker-trade-gate/showcase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"slug": "aiworker-trade-gate",
"title": "aiworker trade gate",
"tagline": "Gates a Base token before any swap with a pass / caution / block verdict from fixed rules and every reason listed, and scans an agent wallet for airdrop spam",
"description": "trade_gate answers pass, caution or block for one Base token from fixed rules over public data: the Honeypot.is buy/sell simulation and taxes, pool liquidity and age, holder concentration, contract verification and ownership, and a Unicode lookalike-name rule, with every reason listed. airdrop_scan marks each ERC-20 a wallet holds as honeypot, dust, batch-airdropped, name-spoofed, ok or unknown, so an agent never approves or trades the spam that reaches every wallet on Base. Both are sold by the live ACP seller aiworker-data and over x402, and the proof is on-chain: four x402 payments and four ACP sandbox jobs with transaction hashes, plus the live scan that found a honeypot and a lookalike in the seller's own wallet. The skill teaches a coding agent to call the gate before a swap and to act on the verdict.",
"status": "live",
"topic": "security",
"topics": [
"security",
"token-safety",
"honeypot",
"defi",
"real-data"
],
"hidden": false,
"builder": {
"name": "aiworker-data",
"url": "https://github.com/ai-worker227"
},
"links": {
"repo": "https://github.com/ai-worker227/aiworker-examples",
"demo": "https://aiworker.duckdns.org/base/airdrop-spam-watch",
"feedback": "https://github.com/ai-worker227/aiworker-examples/issues",
"share": "https://aiworker.duckdns.org/base/airdrop-spam-watch"
},
"primitives": [
"acp",
"wallet",
"email"
],
"visual": {
"kind": "live page",
"eyebrow": "base + x402 + acp",
"title": "pre-trade gate for base tokens",
"posterUrl": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/aiworker-trade-gate/assets/poster.png"
},
"skills": [
{
"name": "aiworker-trade-gate",
"href": "https://github.com/Virtual-Protocol/acp-cli-demos/tree/main/showcase/aiworker-trade-gate/skills/aiworker-trade-gate",
"sourcePath": "showcase/aiworker-trade-gate/skills/aiworker-trade-gate",
"summary": "Check a Base token with the trade gate before any swap, act on pass / caution / block with the listed reasons, and scan the agent's own wallet for airdrop spam \u2014 over x402 (a thirty-line script in the aiworker-examples repo) or as an ACP job.",
"install": "cp -R showcase/aiworker-trade-gate/skills/aiworker-trade-gate ~/.agents/skills/\ncp -R showcase/aiworker-trade-gate/skills/aiworker-trade-gate ~/.claude/skills/"
}
],
"artifacts": [
{
"label": "Live proof: four x402 payments and four ACP sandbox jobs, with transaction hashes and the delivered documents",
"href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/aiworker-trade-gate/examples/proof.md",
"kind": "proof"
},
{
"label": "Free page: Base airdrop-spam watch (rebuilt every six hours)",
"href": "https://aiworker.duckdns.org/base/airdrop-spam-watch",
"kind": "demo"
},
{
"label": "Demo prompt",
"href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/aiworker-trade-gate/prompt.md",
"kind": "prompt"
},
{
"label": "Skill source",
"href": "https://github.com/Virtual-Protocol/acp-cli-demos/tree/main/showcase/aiworker-trade-gate/skills/aiworker-trade-gate",
"kind": "skill"
},
{
"label": "Seller catalogue (every route, price and schema)",
"href": "https://aiworker.duckdns.org/llms.txt",
"kind": "docs"
}
],
"feedbackPrompts": [
"Which rule thresholds (sell tax 20 %, liquidity $10,000, pool age 3 days, top-10 share 50 %) would you set differently for your agent's trades?",
"Should the gate also answer for Solana tokens, and which source would you trust for the honeypot simulation there?",
"What would make a `pass` trustworthy enough to skip the human confirmation in your workflow?"
]
}
133 changes: 133 additions & 0 deletions showcase/aiworker-trade-gate/skills/aiworker-trade-gate/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
name: aiworker-trade-gate
description: Check a Base token with a rule-based pre-trade gate (honeypot simulation, taxes, liquidity, holders, contract, lookalike names) before any swap, and scan a wallet for airdrop spam — paid per call in USDC over x402, or as an ACP job. Deterministic, no LLM, seconds.
version: 1.0.0
---

# aiworker trade gate

Use this skill whenever an agent is about to buy, sell, approve or hold a token on Base and needs a fact-based
answer to "is this safe to touch?" before it moves money. It also tells the agent which of the tokens sitting in its
own wallet are airdrop spam, honeypots or name lookalikes, so it never approves or trades them.

Three paid calls, one free page:

| Call | What it answers | x402 price | ACP price |
| --- | --- | --- | --- |
| `trade_gate` | pass / caution / block for one token, with every reason | $0.05 | $0.20 |
| `airdrop_scan` | every ERC-20 in a wallet marked honeypot / dust / airdrop / spoof / ok / unknown | $0.05 | $0.20 |
| `token_check` | the full safety card behind the gate (0–100 risk score, holders, contract, pools) | $0.05 | $1.00 |
| free | the last 7 days of batch-airdropped and honeypot tokens seen on Base | — | — |

Everything is rule-based over public data (Blockscout, Honeypot.is, DexScreener-derived pairs, the Base RPC). No
model, no forecast, no signal. `pass` means no rule tripped, never a guarantee.

## Prerequisites

Pick one payment path.

**x402 (HTTP, pay per call):** a Base wallet holding a little USDC (a few cents per call; EIP-3009 payments need no ETH),
its private key in an environment variable, and an x402 client. Node:

```bash
npm install @x402/core @x402/evm @x402/fetch viem
export AIWORKER_BUYER_KEY=0x… # the buyer wallet's key; never paste it into a prompt or a file
```

**ACP (job with escrow):** the Virtuals `acp` CLI configured with a funded agent wallet. The seller is
`aiworker-data` (wallet `0xec4bc04310925326ff80daf419a3861173865689`).

## Workflow

1. **Resolve the token address.** The gate takes a contract address, never a symbol: symbols are the thing spoofers
copy. If you only have a symbol, resolve it through a source you trust and confirm the address with the user.
2. **Call the gate before the trade.**
- x402: `node scripts/gate.mjs 0x<token>` (the script linked below), or any x402 client:
`POST https://aiworker.duckdns.org/v1/trade/gate` with body `{"address":"0x…"}`. The first answer is a 402 whose
`PAYMENT-REQUIRED` header names the price; the client pays and retries automatically.
- ACP: `acp client create-job --provider 0xec4bc04310925326ff80daf419a3861173865689 --offering trade_gate --requirement '{"address":"0x…"}'`,
then fund and wait for the deliverable (a Markdown page with the JSON document in its last fenced `json` block).
3. **Act on the verdict.**
- `block` → do not trade, do not approve, say why (the `reasons[]` list, each with `code`, `severity`, `detail`).
Block codes: `honeypot` (cannot be sold), `sell_tax` (≥ 20 %), `name_spoof` (a symbol lookalike of USDC, USDT,
ETH, WETH, cbBTC…), `thin_market` (under $1,000 liquidity with under 50 holders).
- `caution` → surface every reason to the user and ask for an explicit go-ahead. Caution codes: `honeypot_unchecked`
(no simulation), `honeypot_unverified` (the simulation gave no verdict), `buy_tax` / `sell_tax` at ≥ 10 %,
`low_liquidity` (under $10,000), `top10_concentration` (over 50 %), `unverified_contract`, `owner_not_renounced`,
`new_pool` (under 3 days), `pool_age_unknown`, `name_lookalike` (the name, not the symbol, copies a major token),
`data_incomplete` (a source did not answer).
- `pass` → proceed. Quote the liquidity and the pool age in the confirmation so the user sees what "pass" rested on.
4. **Once a day, scan the agent's own wallet.** `POST /v1/wallet/airdrop-scan` with `{"address":"0x<agent wallet>"}`
(or the `airdrop_scan` ACP offering). Treat every token with verdict `honeypot`, `spoof` or `dust` as untouchable:
never approve it, never try to sell it, never count it in the portfolio value. `holdings_index: "empty"` means the
explorer's holdings index was behind and the list came from the transfer feed — still act on it.
5. **Never invent what the document does not say.** A `null` field is an unanswered source, not a zero. A `503` is an
upstream outage: nothing was charged; retry later rather than guessing.

## When not to use it

- Tokens on any chain but Base (`eip155:8453`): the gate answers `404 not_a_contract` or a wrong-chain card. Do not
reuse a Base verdict for the same symbol elsewhere.
- As a price or timing signal: the document carries no forecast. Pair it with your own market logic.
- As the only check on a large trade: `pass` is "no rule tripped", not a guarantee; keep the user's confirmation.

## Approval gates

- **Spending:** each x402 call spends the listed price from `AIWORKER_BUYER_KEY`'s wallet; each ACP job locks the
offering price in escrow. Tell the user the price once per session before the first call and stop if the wallet
cannot cover it (a `402` after the retry means the balance is short — never move funds to fix that on your own).
- **Trading:** a `block` ends the workflow; a `caution` needs an explicit human go-ahead quoting the reasons; a `pass`
proceeds only if the user asked for the trade in the first place.
- Never approve, sell or "clean up" tokens the scan marked `honeypot`, `spoof` or `dust`, even if asked to sell them —
explain why instead (a honeypot cannot be sold; a spoof approval can drain the real token's allowance).

## Stop conditions and handoff

- Stop and report when the gate answers `503`, `504` or `502` twice in a row, when the buyer wallet is short, or when
the token address could not be confirmed. Hand the user the last document verbatim and the reason you stopped.
- Never retry a paid call in a loop: at most two attempts per token per session.

## Validation and output contract

Before acting, check the document: `verdict` is one of `pass | caution | block`; `reasons` is an array; `chain` is
`eip155:8453`; `address` equals the one you sent (lower-cased). Report to the user: the verdict in one line, the
reasons as a list (severity, code, detail), the liquidity, pool age and holder count it rested on, the `generated_at`
time, and the disclaimer sentence. Say which fields were `null` rather than dropping them.

## The gate document

```json
{
"chain": "eip155:8453", "address": "0x…", "verdict": "caution",
"reasons": [{ "code": "top10_concentration", "severity": "medium", "detail": "Top 10 holders hold 31.3% of supply." }],
"honeypot": { "checked": true, "is_honeypot": false, "buy_tax_pct": 0, "sell_tax_pct": 0 },
"liquidity_usd": 788332.15, "largest_pool_age_days": 540, "holders_count": 948010, "top10_share_pct": 31.3,
"contract": { "verified": true, "renounced": true, "age_days": 560 }, "name_spoof": false,
"token": { "name": "Brett", "symbol": "BRETT" }, "generated_at": "…", "sources": [{ "name": "honeypot", "ok": true }],
"disclaimer": "A rule-based gate over public data; informational only, not investment advice; pass is not a guarantee."
}
```

## Errors

| Status | Meaning | What to do |
| --- | --- | --- |
| 400 `invalid_address` | not a 0x address | fix the input; nothing charged |
| 404 `not_a_contract` | the address holds no code on Base | wrong chain or wrong address; nothing charged |
| 402 | unpaid, or the wallet's USDC is short | fund the buyer wallet |
| 503 `chain_unavailable` | an upstream did not answer | retry in a minute; nothing charged |
| 504 `handler_timeout` | the upstreams were too slow | retry; nothing charged |

## Script

`scripts/gate.mjs` — kept in the aiworker-examples repo, not here:
`https://github.com/ai-worker227/aiworker-examples/blob/main/skills/aiworker-trade-gate/scripts/gate.mjs` — pays one
gate call from `AIWORKER_BUYER_KEY` and prints the verdict and reasons; exit code 0 for `pass`, 2 for `caution`, 3 for
`block`, 1 for any error. Read it before running it: it is thirty lines. Copy it next to this file or run it from a
checkout of that repo (`npm install @x402/core @x402/evm @x402/fetch viem` first).

## Where the data comes from

Blockscout (Base), Honeypot.is buy/sell simulation, DexScreener-derived pairs, a read-only Base RPC. Discovery documents:
`https://aiworker.duckdns.org/llms.txt`, `/openapi.json`, `/catalog.json`; the MCP endpoint `https://aiworker.duckdns.org/mcp`
serves the same tools at the same prices. The free page: `https://aiworker.duckdns.org/base/airdrop-spam-watch`.
Loading