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

http
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/tips is wrapped with settleFirst: true: the 0.05 USDC stake settles before the tip is created, the payer becomes the submitter and the settle tx is stakeTx. If the handler then fails, x402 auto-refunds.
  • Grace. An API tip whose stake does not show up in payments within 600 s (TIPS_STAKE_GRACE_SECONDS) is dropped: REJECTED, ledger DROP, nothing slashed.
  • Unstaked tips. The /tips page (same-origin) and deployments with X402_DISABLED=1 accept unstaked tips marked demo: true / submitter anonymous; 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.

CheckStrongWeak
Evidence tx hashreceipt exists on Arc and touches the subject (from / to / log emitter / indexed topic)receipt exists but does not touch the subject
Evidence URLhost is ofac.treasury.gov, sanctionssearch.ofac.treas.gov, opensanctions.org, europa.eu, gov.uk or a subdomainany other http(s) URL
Re-screen tierCorroborationDecision
HIGHanyVERIFIED
MEDIUM≥ 1 strongVERIFIED
LOWnone at allREJECTED → SLASHED when a stake was paid
anything elseMEDIUM alone, LOW + something, re-screen failedNEEDS_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

pseudo
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 tick

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