Docs

BeforeCoin gives an agent's trades and payments a check it can't skip. You call the API before acting, and the chain refuses anything that wasn't cleared.

Quickstart

Run the whole system on a throwaway local chain. It needs Foundry, Node 22 or newer, pnpm and Bun. It uses no real funds and no keys.

git clone --recursive https://github.com/sagarjethi/ethmumbai.git
cd ethmumbai
pnpm install
pnpm start

This starts the website, the dashboard, three verifiers and the API. In another terminal, run every attack:

pnpm demo

Clear a swap

POST /v1/clear/swap. Authenticate with Authorization: Bearer clr_…, or send no key and pay with x402. The server answers 402 with payment terms, and an x402 client pays and retries.

{
  "action": {
    "kind": "swap",
    "agentName": "alice.agents.clearance.eth",
    "account": "0xYourClearanceAccount",
    "pool": {
      "currency0": "0x…", "currency1": "0x…",
      "fee": 3000, "tickSpacing": 60, "hooks": "0xClearanceHook"
    },
    "zeroForOne": true,
    "amountIn": "100000000",
    "reason": "Optional. Treated as untrusted and never read by rules."
  }
}

When cleared, the response carries hookData. Pass it to your account's swapCleared:

account.swapCleared(pool, zeroForOne, amountIn, minOut, hookData)

A clearance lasts 90 seconds, works once, and only for the account it names. It also carries a minimum output, which the wallet enforces, so liquidity pulled after the check can't hurt the trade.

Exact-output swaps are always refused, because a hook can't bound their input before the swap runs.

Verdicts

VerdictMeaningWhat to do
ALLOWEnough verifiers signed the full amount.Send the swap with hookData.
REDUCEThey signed a smaller amount, in clearance.maxAmountIn.Send that amount or less.
HUMAN_REQUIREDIt's over the owner's limit.Send the owner to checkpoint.url.
BLOCKThere are no signatures. Each verifier's reasons are in evaluations.Don't retry. The chain will refuse it.

Missing or stale data always gives BLOCK, never a pass.

Owner approval

  1. Send the owner to checkpoint.url, which starts a fresh World ID login.
  2. Check progress at GET /v1/human/:id. It ends as approved, denied or expired.
  3. Call /v1/clear/swap again with the same action, plus "checkpointId".

Each verifier checks the approval's token itself. It only counts if it's from the owner, fresh, and for this exact action. It clears one trade.

Independent check

When a response has "attestationRequired": true, the hook also needs a finding on the ledger. Ask for it, then send the swap:

POST /v1/decisions/:id/attest

A Chainlink CRE workflow re-reads the owner's limits, confirms the quorum against the contract and re-quotes the market. It writes either an attestation or a refusal to ClearanceLedger. The first report stands. A scheduled run also picks up anything waiting at GET /v1/attestations/pending.

Clear a payment

The account's isValidSignature only accepts the agent key's signature plus verifier signatures over the exact EIP-3009 payment. To pay, your x402 signer calls POST /v1/clear/payment with the authorization and the agent key's signature, then appends the returned signatures to the agent's own. See apps/agent/src/agent.ts.

MCP server

apps/mcp lets an agent call BeforeCoin as a tool. It speaks stdio, and the client starts it for you. With pnpm start running, create a key in the dashboard's API keys tab, then use this config with absolute paths to your clone:

{
  "mcpServers": {
    "beforecoin": {
      "command": "/absolute/path/to/ethmumbai/node_modules/.bin/tsx",
      "args": ["/absolute/path/to/ethmumbai/apps/mcp/src/index.ts"],
      "env": {
        "CLEARANCE_API_URL": "https://your-api",
        "CLEARANCE_API_KEY": "clr_your_key"
      }
    }
  }
}

A client started from a desktop app may not find node on its PATH, so add a PATH entry to env if the server won't start.

ToolWhat it does
clearance_check_swapAsks verifiers to clear a swap. A BLOCK is a normal answer and not a tool error, so read verdict.
clearance_attestRequests the independent check when a clearance has attestationRequired.
clearance_get_proofReads a decision's signatures, reasons and evidence hashes.
clearance_check_tokenLists admin functions in a token's bytecode.
clearance_checkpoint_statusReads whether the owner has answered a checkpoint.

The server has no payment tool yet, so payments go through your x402 signer over REST.

Agent skill

skills/beforecoin tells an agent to get a check before every swap or payment, what each verdict means, how to submit the result to its wallet, and never to route around a refusal.

For Claude Code, copy it to one of the skill folders in Claude Code's docs:

mkdir -p ~/.claude/skills && cp -R skills/beforecoin ~/.claude/skills/   # all your projects
mkdir -p .claude/skills && cp -R skills/beforecoin .claude/skills/       # one project

For another agent, give it SKILL.md as instructions, and let it read references/ and run the script. It takes a swap as JSON, needs only Node, and reads CLEARANCE_API_URL and CLEARANCE_API_KEY:

node skills/beforecoin/scripts/check.ts swap.json

It exits 0 only for ALLOW, so a refusal or an error can't fall through to a swap. tests/skill.test.ts runs it against a throwaway stack. No model has been run with the skill loaded yet, so how well agents follow it is untested.

Public endpoints

EndpointReturns
GET /v1/proofs/:idA decision, its signatures, each verifier's reasons and evidence hash, and any attestation.
GET /v1/tokens/:address/checkAdmin functions found in a token's bytecode, following proxies.
GET /v1/track-recordVerdict counts and how often each verifier disagreed.
GET /v1/attestations/pendingClearances still waiting for an independent check.

Owner limits

Text records on the agent's ENS name. A missing or invalid record blocks every action.

RecordMeaning
clearance.accountThe one wallet this name may act for.
clearance.maxSizeUsdAbove this, the owner must approve.
clearance.humanCapUsdA hard cap, even with approval.
clearance.maxImpactBpsLargest price impact. Bigger trades are reduced.
clearance.requiredVerifiersSignatures needed. It can raise the contract's floor, not lower it.
clearance.allowedTokensComma-separated token addresses.
clearance.allowedPoolsComma-separated pool ids you trust. Others get refused, whatever price they show.
clearance.dailyPaymentUsdThe most the agent can pay in a day, across all payees.
clearance.maxPaymentUsdLargest single x402 payment.
clearance.allowedPayeesComma-separated payee addresses.
clearance.ownerSubThe owner's World ID subject, so only they can approve.

Errors

StatusMeaning
400The request body is invalid. issues says where.
401The API key is unknown or revoked.
402Payment is required. x402 clients handle this.
404This deployment doesn't know that agent.
429The key's monthly checks are used up, or you sent too many requests.

A refusal on the chain has a named reason, wrapped by the PoolManager: NoClearance, RouterNotAllowed, WrongAgent, WrongPool, WrongDirection, WrongChain, ClearanceExpired, ExactOutputNotClearable, AmountAboveClearance, NonceUsed, NoQuorum or NotAttested. The wallet adds PoolNotCleared, SpendCapExceeded, TooFewSignatures and NotAgent.

Contracts

ContractJob
ClearanceHookThe v4 hook that checks every swap in its pools.
ClearanceAccountThe agent's wallet, and the real enforcer.
VerifierSetCurrent verifiers and the quorum.
ClearanceLedgerFindings from the CRE workflow.
ClearanceRouterA small exact-input router that reports its real caller.