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 seq and 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 test pre-commit), and a CI gate (validate-cli.js in the pipeline). Keeping one schema and one validator across all three gates keeps contract.json/state.json provably 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 the Authorization header, 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.

Provenance