--- name: rh777 version: 0.1.0 description: Pay for things on Robinhood Chain in USDG with one signature. Servers answer 402 with a price; you sign; rh777 settles on-chain and hands back a receipt. No gas, no bridging, no account. homepage: https://rh777.metamuse.lol --- # rh777 rh777 is a payment rail for programs. A server that wants to be paid answers your request with status `402` and a price in USDG. You sign a transfer for exactly that amount to exactly that merchant, retry the request with the signature attached, and the server settles it on Robinhood Chain (chain id 4663) before it answers. You never pay gas. The merchant gets the USDG and a signed receipt in the same round trip. Facilitator: `https://api.metamuse.lol/rh777` · Explorer: `https://explorer.metamuse.lol` (every settlement, verified against the chain) · Network: `eip155:4663` · Asset: USDG `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` (6 decimals) ## Before your first payment (once) Your wallet must let Permit2 move your USDG. One transaction, once, from the wallet that will pay: ``` USDG.approve(0x000000000022D473030F116dDEE9F6B43aC78BA3, amount) ``` Approve only what you are willing to spend over time. That allowance is your hard ceiling: no signature can move more than it, whatever a server asks for. Your human can set it, raise it or zero it whenever they like. ## Paying 1. Request the resource. If it costs something you get `402` and a header `PAYMENT-REQUIRED` holding base64 JSON. Inside, `accepts[]` lists what the server takes. Pick the entry with `network: "eip155:4663"` and the USDG asset. It carries `amount` (base units), `payTo`, `maxTimeoutSeconds`, `spender` and `permit2`. 2. Build the transfer and sign it with your wallet (EIP-712, domain `Permit2`, chain 4663, verifying contract = `permit2`): ``` PermitWitnessTransferFrom { permitted: { token: USDG, amount }, // exactly the price spender: 0x402085c248EeA27D92E8b30b2C58ed07f9E20001, // the witness proxy: it can only pay `witness.to` nonce: random 256-bit, never reused, deadline: now + maxTimeoutSeconds, witness: { to: payTo, validAfter: now - 30 } } ``` 3. Retry the same request with header `PAYMENT-SIGNATURE` = base64 of ```json { "rh777": 1, "accepted": , "payload": { "signature": "0x…", "authorization": { "permitted": {...}, "from": "", "spender": "0x4020…0001", "nonce": "…", "deadline": "…", "witness": { "to": "", "validAfter": "…" } } } } ``` 4. A `200` comes back with the resource and a `PAYMENT-RESPONSE` header: base64 JSON receipt with `transaction`, `payer`, `payTo`, `amount`, `nonce`, `settledAt` and `attestation` (an rh777 signature over the receipt hash, so anyone can check it later without asking us). Reference payer in TypeScript (viem only): `https://metamuse.lol/rh777/client.ts`. A wrapped `fetch` that does steps 1 to 4 for you: `payingFetch(wallet, account, { maxUsdg: "0.05" })`. ## What keeps you safe - The signature names the merchant. The proxy contract on chain refuses to send anywhere else, including to rh777 itself. - The signature names the exact amount. Not "up to", exactly. - Every nonce is single use on Permit2. A replayed signature settles nothing. - `deadline` and `validAfter` bound the window; a stale signature is worthless. - Your Permit2 allowance is the ceiling above everything else. - If you run on a MetaMuse account, your human's policy hook also counts the allowance you set against your daily budget. ## Being paid (for servers and muses that sell) Mount the paywall on a route. Price in USDG, `payTo` is your address: ```ts app.get('/quote', paywall({ price: '0.01', payTo: '0xYourAddress' }), handler) ``` The paywall verifies before your handler runs and settles before the response leaves, so a handler only ever sees paid requests. Settlement is idempotent per payer nonce: a retried request returns the same receipt instead of paying twice. Facilitator endpoints, if you run your own server elsewhere: - `GET /rh777/supported` — what rh777 settles and the relayer address that signs receipts - `POST /rh777/verify` `{ payment, requirement }` → `{ isValid, payer, invalidReason }` (read-only) - `POST /rh777/settle` same body, header `x-rh777-key: ` → receipt - `GET /rh777/receipt/:payer/:nonce` → the stored receipt and its hash - `GET /rh777/health` — relayer gas, chain height, settlements so far Merchant keys are issued per `payTo` address; settlement spends relayer gas, so it is not open. ## Try it in a minute `GET https://api.metamuse.lol/rh777/demo/quote` costs 0.01 USDG and returns a live META quote (Robinhood bid/ask and the Chainlink price on chain). Unpaid, it answers 402 with the challenge above. Paid, it answers in about a second with the receipt in `PAYMENT-RESPONSE`. ## Getting paid (merchants) Any address on Robinhood Chain can receive rh777 payments. To settle them you need a key bound to that address: 1. `GET /rh777/merchants/message?payTo=0x…&name=my-api` → the text to sign and a timestamp. 2. `personal_sign` that text with the payTo wallet. 3. `POST /rh777/merchants { payTo, name, timestamp, signature }` → `{ key }`, shown once. A new registration for the same address retires the previous key. Then mount the paywall (reference: `https://rh777.metamuse.lol/paywall.ts`, Hono, HTTP only) or do the three steps yourself: answer `402` with `PAYMENT-REQUIRED`, on retry `POST /rh777/verify` (no key) then `POST /rh777/settle` with `x-rh777-key`, and return the receipt in `PAYMENT-RESPONSE`. `GET /rh777/merchants/me` with the key shows what you have received. Humans: `https://rh777.metamuse.lol/merchant/`.