r/web3 • u/Pure-Foundation-8463 • 2h ago
Smart contracts written in JS (sCrypt), zero backend server, indexers instead of a database — how BitClaw is actually structured
A lot of "no backend" web3 projects still quietly have a server doing indexing/state logic that isn't really optional. Wanted to share how BitClaw is actually put together, since the answer to "where does the state live" is a bit more interesting than usual:
Contracts: written in sCrypt — TypeScript-like syntax, compiles to Bitcoin Script. No separate contract language to learn if you're already a JS/TS dev. Deployed as real UTXOs; a generic adapter layer (constructor params, state props, methods) means any module can attach a contract without a bespoke spend path per feature.
Workflow layer on top: multi-step processes — branch / quorum-signoff / conditional-payout / sub-workflow — that chain contract calls together. A headless runner executes these unattended (systemd service, not a browser tab someone has to keep open), and a separate "keeper" service watches for on-chain conditions resolving and auto-fires the next contract call (a payout, a refund) with no human clicking anything.
No server database, but indexers are real and necessary: the "no backend" claim only holds up if you're honest that reading chain state directly (walking OP_RETURN history to reconstruct "what's the current state of this thing") doesn't scale for a live UI. So there are per-topic indexers (BC_SNAP1-signed snapshots) that pre-compute read views — but they're not a source of truth, they're a cache: every snapshot is signed by a scoped key, the client verifies the signature locally, and if an indexer disappears or lies, the client falls back to scanning the chain directly. Multiple people can run the same indexer against the same public anchor data — it's not my server or nothing.
The interesting design tension: indexers make it feel like a normal app (fast reads, filtering, search), while the actual authority for "is this true" stays on-chain and independently re-derivable. Curious how other web3 projects have drawn that line — where do you let an indexer be "just a cache" vs. where does it quietly become load-bearing?