The agent12
Tip market
Anyone who spots a risky address on Arc can tell CompliR, stake a few cents, and get paid in USDC the moment the tip verifies. Bad tips lose the stake. Verified tips become evidence (COMMUNITY_TIP_VERIFIED, 15 points) in every verdict issued afterwards, so the oracle buys intelligence as well as selling verdicts.
The stake is the x402 payment
POST /api/v1/tips # x402 stake 0.05 USDC, settled FIRST · same-origin browser → unstaked tip (no stake)
{ "subject": "0x…", "category": "sanctions|mixer|scam|poisoning|stolen_funds|other",
"claim": "10–2000 chars", "evidenceUrls": ["https://…"] /* ≤ 5 */, "evidenceTxs": ["0x…64hex"] /* ≤ 10 */ }
→ 201 { tip, demo, note, next } X-CompliR-Tip-Id: tip_…
GET /api/v1/tips # free · { config, totals, leaderboard[10], items[50], time } · submitters anonymised as tipster-xxxxxx
GET /api/v1/tips/:id # free · { tip }- Settled first.
POST /api/v1/tipsis wrapped withsettleFirst: true: the 0.05 USDC stake settles before the tip is created, the payer becomes the submitter and the settle tx isstakeTx. If the handler then fails, x402 auto-refunds. - Grace. An API tip whose stake does not show up in
paymentswithin 600 s (TIPS_STAKE_GRACE_SECONDS) is dropped: REJECTED, ledgerDROP, nothing slashed. - Unstaked tips. The /tips page (same-origin) and deployments with
X402_DISABLED=1accept unstaked tips markeddemo: true/ submitteranonymous; a verified bounty is recorded against the daily cap but nothing is sent.
Verification matrix
Every 15 minutes (cron) or 5 minutes (worker/tips.ts) the tick re-screens the subject through the real pipeline (clientId: tips, RESCREEN, no on-chain write) and checks the evidence. No model is involved.
| Check | Strong | Weak |
|---|---|---|
| Evidence tx hash | receipt exists on Arc and touches the subject (from / to / log emitter / indexed topic) | receipt exists but does not touch the subject |
| Evidence URL | host is ofac.treasury.gov, sanctionssearch.ofac.treas.gov, opensanctions.org, europa.eu, gov.uk or a subdomain | any other http(s) URL |
| Re-screen tier | Corroboration | Decision |
|---|---|---|
| HIGH | any | VERIFIED |
| MEDIUM | ≥ 1 strong | VERIFIED |
| LOW | none at all | REJECTED → SLASHED when a stake was paid |
| anything else | MEDIUM alone, LOW + something, re-screen failed | NEEDS_REVIEW |
A human can settle NEEDS_REVIEW with POST /api/internal/tips { "review": "tip_…", "decision": "VERIFIED" | "REJECTED" }. The submitter only ever sees tier, score, reason codes, the re-screen decision id and the corroboration result, never the evidence bundle or another client's data.
Bounty math
bounty = TIP_BOUNTY_USDC (0.25) × category × reputation (6 dp)
category: sanctions 2.0 · poisoning 1.5 · mixer, scam, stolen_funds, other 1.0
reputation: Laplace-smoothed (verified + 1) / (verified + rejected + 2) per submitter
new 0.5 → ×0.75 · 3 verified / 0 rejected 0.8 → ×0.90 · perfect record 1.0 → ×1.00
// new sanctions tip 0.375 USDC · perfect tipster's sanctions tip 0.5 USDC · new "other" tip 0.1875 USDC
daily cap TIPS_DAILY_CAP_USDC (5): a VERIFIED tip beyond it stays VERIFIED and is paid on a later tickPayout rails
- 1 · circle
- Circle Developer-Controlled revenue wallet, transferUsdc({ role: "revenue" }), app-side spending policy, Gas Station-sponsored when a mainnet policy is active. Needs CIRCLE_API_KEY + CIRCLE_ENTITY_SECRET.
- 2 · local
- viem ERC-20 transfer on the USDC interface from TIPS_PAYOUT_PRIVATE_KEY.
- 3 · dry-run
- nothing leaves the process (payoutTx null, payoutMode dry-run). The default without credentials, and the mode today.
Every step is a hash-chained TIP entry (SUBMIT, VERIFY, PAY, SLASH, REVIEW, DROP) on /ledger, with the submitter anonymised. Public statuses: SUBMITTED → VERIFYING → VERIFIED → PAID, or REJECTED (no stake) / SLASHED (stake kept), or NEEDS_REVIEW. Verified tips feed tipEvidenceFor(address) for 180 days.