Skip to content

paid-oracle

x402-style paid oracle bee — sells one price per USDC payment, verified on-chain

A minimal paid bee for hum. Listens for chi:"tool-call" with name: "quote", replies with an HTTP-402-style payment challenge, accepts retries carrying a transaction hash, verifies the payment on-chain, then returns the price.

Reference for hackathon participants (e.g. Agora / Arc / Canteen) who want to ship the simplest possible monetized agent running on hum.

Propensity

statefulnessrichnesswire shapehides
stateless (per-call)leanx402-over-tool-calleverything except hello/tool-call/tool-result/error

What it sells

Default: ETH-USD spot price from CoinGecko, repriced per call. Configurable via PAID_ORACLE_PRICE_URL. Anything you can fetch over HTTP with a single GET works.

Wire

counterparty ──── chi:tool-call { name:"quote", args:{ pair:"ETH/USDC" } } ───► paid-oracle
◄─── chi:error { code:402, x402:{ chain, pay_to, asset,
asset_kind:"erc20",
price_atomic, nonce, memo } }
(counterparty pays USDC on Base / Arc / configured chain. The transfer's
input data MUST contain the nonce bytes, so we can bind the payment
to this specific quote — single payment can't claim two quotes.)
──── chi:tool-call { name:"quote",
args:{ pair:"ETH/USDC" },
paymentProof:{ txHash:"0x…", nonce } } ───►
◄─── chi:tool-result { result:{ pair, px, source, expires_at_ms } }

Configure

envrequireddefaultwhat
PAID_ORACLE_PAY_TOyesyour EVM address — where USDC must land
PAID_ORACLE_RPCnohttps://rpc.testnet.arc.networkJSON-RPC endpoint
PAID_ORACLE_CHAINnoarc-testnethuman label echoed in challenges
PAID_ORACLE_PAY_KINDnonativenative for Arc (USDC = gas token); erc20 for Base / Eth mainnet
PAID_ORACLE_USDCno0x000… (native) / 0x833…2913 (erc20)ERC-20 contract address (only used when pay_kind=erc20)
PAID_ORACLE_DECIMALSno18 (native) / 6 (erc20)USDC decimals on this chain
PAID_ORACLE_PRICE_URLnoCoinGecko ETH/USDwhere to fetch the underlying
HUM_THRUM_SOCKno$XDG_RUNTIME_DIR/hum/thrum.sockhumd’s NDJSON socket

Quote is hardcoded at $0.05 (5 cents). The atomic amount scales with PAID_ORACLE_DECIMALS automatically — same $0.05 quote works whether USDC has 6 decimals (ERC-20 chains) or 18 (Arc native). Edit QUOTE_PRICE_CENTS in src/main.rs to change the price.

Arc note

USDC is the native gas token on Arc (and has 18 decimals there, not the 6 you’d expect from Ethereum/Base). Payment is a plain tx.value transfer; the ERC-20 contract address 0x3600…0000 exists for compatibility but day-to-day transfers go native. Default config matches this — no flags needed.

Run

Terminal window
# From the workspace root. Defaults to Arc testnet — just set your address:
PAID_ORACLE_PAY_TO=0xYourAddr cargo run -p paid-oracle
# Switch to Base mainnet (ERC-20 USDC):
PAID_ORACLE_PAY_TO=0xYourAddr \
PAID_ORACLE_RPC=https://mainnet.base.org \
PAID_ORACLE_CHAIN=base-mainnet \
PAID_ORACLE_PAY_KIND=erc20 \
PAID_ORACLE_USDC=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
PAID_ORACLE_DECIMALS=6 \
cargo run -p paid-oracle

The bee self-announces to the mesh as soon as it handshakes. Other humds in the ensemble discover it via:

let mut found = ensemble.nestling_discover("paid-oracle");
while let Some((humd_id, manifest)) = found.recv().await {
// dial them, ask for a quote, pay, settle
}

What it doesn’t do

  • No on-chain writes. Read-only RPC for eth_getTransactionByHash.
  • No LLM. Pure data resale. Plug in chi:"prompt" instead of chi:"tool-call" and you have paid-prompt — inference-for-pay.
  • No facilitator. Verifies the tx itself. Drop in x402 facilitator verification by POSTing the proof to a facilitator URL and trusting its signature.
  • No persistence. Restart loses the spent nonce set. A real deploy writes it to disk so payments can’t be replayed.
  • No KYC, no rate-limit, no auth beyond payment. The trust seam is “the chain confirmed payment to my address.” Layer your own policy on top.

Why x402 over hum tones

x402 was designed for HTTP. We re-use the semantics (402 challenge, retry with proof) but transport them over thrum’s chi:"error" / chi:"tool-call" pair. Same idea, no new protocol element required. A bee that already knew how to do chi:"tool-call" can become paid by adding one branch in its handler.

Status

Reference implementation. Bug reports + PRs welcome.

See also