Web Contracts is a transport-agnostic smart-contract system that runs verifiable agreements over plain web files instead of a global blockchain. It separates concerns into four layers: an immutable contract.json (rules in any language), a mutable state.json (a JCS-canonicalised, SHA-256 hash-chained sequence of states), a ledger.json (multi-currency balances), and a Trail that anchors the hash chain to Bitcoin via Block Trails for tamper evidence. Contracts declare effects (credit/debit/transfer) that an executor applies atomically; any verifier can replay the state chain from genesis, check the hashes, and confirm the Bitcoin anchoring, so cheating breaks the chain detectably. Identity is did:nostr and authentication is NIP-98 signed HTTP, which lets both humans (via NIP-07) and autonomous agents participate without global consensus or gas.
Architecture (four layers)
- contract.json — immutable rules; a transition function takes the current state and parameters and returns
{ state, effects }. Logic may be written in any language. - state.json — the mutable current value; every transition increments
seqand stores the SHA-256 hash of the prior state (JCS-canonicalised), forming an independently verifiable hash chain. - ledger.json — balances across currencies and identities. The contract never edits the ledger directly; it declares effects (
credit/debit/transfer) that the executor applies atomically. - Trail — a Block Trails log that anchors the hash chain to Bitcoin, giving tamper evidence without constant on-chain writes.
Verification model (“trust but verify”)
- Executor runs the contract and updates state/ledger/trail atomically.
- Client submits transitions and can simulate them locally first — this preview is Client-Side Validation in practice.
- Verifier replays the whole chain from genesis, validates every hash, and checks the Bitcoin anchoring; if the executor cheated, the chain breaks.
Validation — one schema, three gates
- The JSON layers are guarded by a single JSON Schema enforced at three points by one tiny zero-dependency validator that runs identically in browser and Node: a browser gate (the editor validates before writes), a deploy gate (
npm testpre-commit), and a CI gate (validate-cli.jsin the pipeline). Keeping one schema and one validator across all three gates keepscontract.json/state.jsonprovably well-formed everywhere they are written. (Pattern: melvincarvalho gist “One Schema, Three Gates”.)
Identity & access
- Parties are
did:nostr:<pubkey>(see did:nostr); requests authenticate with NIP-98 signed Nostr events in theAuthorizationheader, usable by humans (NIP-07 extensions like PodKey) and by autonomous agents. - HTTP conventions:
GET /contracts/{id}/state.json,POST /contracts/{id}/,GET /contracts/{id}/trail.json. Files are transport-agnostic — they can live in Solid pods, web servers, Git repos, or local directories.
Profiles
- amm.v1 — Automated Market Maker (constant product
x · y = k). - escrow.v1 — two-party escrow with arbiter.
- sale.v1 — fixed-price token sales; subscription.v1 — recurring payments.