Skip to content

TheBossMickael/scriptura

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Two-Tier Money

scriptura β€” from the French monnaie scripturale, "book money": money that exists as ledger entries in banks' books. This project puts those ledger entries on-chain.

An on-chain simulation of the two-tier monetary system: tokenized central bank money (wCBDC), tokenized commercial bank deposits (DEP-A / DEP-B), and a fiat-backed stablecoin (sEUR) whose reserves are those deposits β€” with atomic interbank settlement in central bank money, gasless EIP-712 payment intents, a Foundry invariant suite, and a role-based dashboard (client, bank operator, stablecoin issuer, central bank, observer).

Solidity Foundry Sepolia License

Status: V1 β€” feature-complete, deployed & Etherscan-verified on Sepolia, validated end-to-end on the live deployment. V2+ (crisis scenarios, lender of last resort, AMM, multi-chain) is designed but deliberately not built β€” see Roadmap.

Observer dashboard β€” monetary aggregates and bank health

The public observer dashboard β€” the whole system at a glance, readable without connecting a wallet: monetary aggregates (M0, M1 per bank, sEUR in circulation), each bank's health badge and reserve-ratio gauge, and StableCo's live proof of reserves.

What it demonstrates

  • The singleness of money. A euro at Bank A equals a euro at Bank B because every interbank transfer settles in central bank money: burn DEP-A β†’ move wCBDC β†’ mint DEP-B, in one transaction.
  • Fractional-reserve fragility. The soft constraint (ratio breach β†’ event, payments continue) is separated from the hard one (insufficient wCBDC β†’ revert): bank stress is gradual and observable β€” HEALTHY 🟒 / STRESSED 🟠 / ILLIQUID πŸ”΄.
  • TradFi β†’ stablecoin contagion. sEUR is 100% backed by deposits at Bank A: freeze the bank and redemptions break while sEUR keeps circulating (the USDC/SVB 2023 pattern).
  • Endogenous stablecoin supply. No admin mint exists; coverage β‰₯ 100% is a tested invariant and proof of reserves is a view call.
  • Intermediated vs permissionless money. DEP is registry-gated and freezable; sEUR moves gasless (EIP-3009) or wallet-direct, even when the infrastructure is down.

Live on Sepolia

All 9 instances deployed by one make deploy-sepolia, sources verified on Etherscan (chain id 11155111 β€” see deployments/sepolia.json):

Contract Address Role
CentralBank 0x2fa4…367C M0 issuance, bank allowlist, ratio threshold
wCBDC 0xF4dA…2D05 Central bank money (banks only)
Bank A 0x0B3C…B431 Reserves, client registry, freeze
DEP-A 0x41E3…Ff23 Bank A's tokenized deposits
Bank B 0x486C…977a Reserves, client registry, freeze
DEP-B 0xd666…14a9 Bank B's tokenized deposits
SettlementEngine 0x7838…5c06 EIP-712 intents, atomic settlement
StableCo 0x5c48…6D24 Reserve vault, sEUR mint/redeem
sEUR 0x4bC5…E797 Permissionless stablecoin + EIP-3009

Reference transactions from the end-to-end run on the live deployment:

Flow Tx
Interbank payment β€” wCBDC settles the exact amount 0x353d…bd9c
Cross-bank sEUR mint β€” burn DEP-B β†’ wCBDC Bβ†’A β†’ mint DEP-A to the vault β†’ mint sEUR, one tx 0x2479…6fb4
Cross-bank sEUR redeem β€” the composed mirror (Aβ†’B) 0x9efa…6dba
Gasless sEUR transfer (EIP-3009, relayer pays gas) 0x8634…e6d2

Engineering highlights

  • 7 monetary invariants fuzzed with Foundry invariant testing (fail_on_revert, production signing paths β€” real EIP-712 signatures, third-party submitter).
  • Gasless by signature, trustless by contract: a stateless relayer pays gas, the contracts re-verify everything; the engine is relay-agnostic, so censorship is operational, never contractual.
  • Three anti-replay nonce namespaces, deliberately not unified (sequential engine + sequential StableCo + random EIP-3009).
  • Composed cross-bank flows: a Bank B client minting sEUR moves value across all three monetary layers atomically, with coverage provably β‰₯ 100% at every step.
  • No database anywhere: the chain is the source of truth β€” the relayer re-derives its state at boot, the indexer is a rebuildable projection, the frontend stores nothing.

Architecture

              MetaMask (client keys: EIP-712/3009 signing Β· operator direct txs)
                                       β”‚
                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                       β”‚  Frontend β€” Vite + React/wagmi β”‚  :5173
                       β””β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”˜
             POST /intent β”‚            β”‚ GET /…     β”‚ live reads (viem)
             POST /faucet β”‚            β”‚            β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                β”‚ Relayer        β”‚  β”‚ Indexer     β”‚ β”‚
                β”‚ Fastify + viem β”‚  β”‚ Ponder+Hono β”‚ β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                    txs   β”‚            β”‚ eth_getLogsβ”‚
                          β–Ό            β”‚            β–Ό
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚        Chain (Anvil dev / Sepolia live) β€” source of truth β”‚
       β”‚   CentralBank──wCBDC    Bank A──DEP-A    Bank B──DEP-B    β”‚
       β”‚   SettlementEngine      StableCo──sEUR                    β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quickstart

Prerequisites: Foundry, Node.js β‰₯ 20, GNU Make, MetaMask.

git clone --recurse-submodules https://github.com/TheBossMickael/scriptura
cd scriptura
cp .env.example .env
(cd relayer  && npm install)
(cd indexer  && npm install)
(cd frontend && npm install)

See it live (Sepolia)

The committed deployment already carries real state and history β€” start there. The app is three services (relayer, indexer, front); against the live deployment you run two of them. Set VITE_CHAIN="sepolia" in .env, then:

make front                    # dashboards on http://localhost:5173, live Sepolia data
CHAIN=sepolia make indexer    # history walls & lists (public RPC pool preconfigured)

That gives you every dashboard read-only on live on-chain data, plus direct sEUR transfers with your own gas. The third service β€” the relayer, which powers every gasless action β€” authenticates as the deployment's relayer EOA, whose key stays with the operator. For the full three-service experience: run everything locally (next section, five minutes), deploy your own Sepolia instance (make deploy-sepolia with your own keys/RPC regenerates deployments/sepolia.json), or open an issue to ask for a live run.

Run everything locally

The fully interactive stack β€” gasless payments, faucet onboarding, freezes. Nothing to configure: the .env you copied already contains everything for local (VITE_CHAIN="local" plus Anvil's well-known, pre-funded test keys for every role β€” no real value ever touches them). Anvil, bundled with Foundry, is the supported local chain: the genesis scripts key on its chain id (31337) and its pre-funded accounts. Four terminals:

make anvil            # 1 β€” local chain
make deploy-local     # 2 β€” deploy + seed the full genesis (run once), then:
make relayer          # 2 β€” gasless relayer on :3001
make indexer          # 3 β€” indexer + REST API on :42069
make front            # 4 β€” app on http://localhost:5173

All three services must be up for the full experience: the relayer powers every gasless action, the indexer powers the history sections. Point MetaMask at localhost:8545 (chain id 31337) and import a genesis client key from .env (e.g. alice1) β€” or connect any wallet and use Join.

Try it with your own wallet

The demo is designed so a visitor can act, not just watch: connect an unknown wallet and the observer view offers Join / get test euros β€” the relayer (holding a narrow on-chain FAUCET_ROLE: register + capped credit, one-shot per address, nothing else) onboards you as a bank client. From there everything runs gasless with your own signatures: pay intrabank/interbank, mint and redeem sEUR (including the cross-bank composed flow), transfer sEUR P2P. This needs the stack running (relayer + indexer + front) β€” the local setup above gives you exactly that.

Join the demo

Screenshots

Each dashboard is what the app resolves for the connected account's on-chain role β€” the shots below were taken connected as the actual client/operator accounts, on live Sepolia data. You don't need those keys to see the same screens: the "Explore as" dropdown (top of the app) lets anyone browse every view read-only.

Client β€” connected as a Bank A client: balances, the bank's live health (the panic signal), gasless payment, sEUR mint/redeem and both P2P paths β€” then the personal history.

Client β€” balances and action forms Client β€” personal payment and sEUR history

Central bank β€” connected as the central-bank operator: macro aggregates, per-bank monitors, allowlist and threshold controls, the ReserveRatioBreached alert wall (note the real breach at 9.66%) β€” and every interbank flow, including StableCo's composed settlements.

Central bank β€” macro dashboard and alert wall Central bank β€” interbank flows

Bank operator and StableCo β€” the live two-column balance sheet with its ratio gauge and freeze switch; the issuer's proof of reserves with its coverage badge.

Bank operator β€” balance sheet & ratio gauge StableCo β€” proof of reserves

Known limitations (documented, not hidden)

  • Indexer history lags ~30 s–2 min behind the head on Sepolia (public RPC pool, 15 s polling); live balances are direct RPC reads and stay instant.
  • Amount inputs parse commas as en-US thousands separators: 1,500 = 1500.
  • The relayer is a single point of failure β€” on purpose (real settlement systems have the same shape); mitigations and analysis in docs/threat-model.md.
  • Sequential nonces allow one in-flight action per client β€” the UI locks buttons until confirmation.
  • Testnet-grade key handling: throwaway keys in a gitignored .env; the production posture (encrypted keystore) is documented, not implemented.

Tests

155 Foundry tests (132 unit Β· 17 integration Β· 6 invariant properties, 128 runs Γ— depth 64, zero tolerated reverts) + 25 relayer and 25 frontend vitest suites β€” plus a full E2E user simulation, green against the live Sepolia deployment.

make test

Documentation

Doc What's inside
docs/monetary-design.md The "why": two-tier money, singleness, hard vs soft constraints, MiCA/RTGS/unified-ledger anchors
docs/architecture.md The "how": contracts, roles, flows, keys, RPC strategy β€” plus the phase-by-phase build history
docs/contracts.md Per-contract reference; EIP-712 domains; the invariants ↔ code ↔ tests map
docs/scenarios.md 12 numbered walk-throughs, each tied to its integration test and, where applicable, a live Sepolia tx
docs/threat-model.md Powers & blast radius, attack surfaces, the assumed SPOF
docs/frontend.md Role views, blocking UX, pre-simulation, chain pinning
docs/indexer.md Derived-store design, REST API β€” and the field note on RPC getLogs caps
docs/project.md The consolidated blueprint: actors, mechanisms, genesis, stack decisions, roadmap

Roadmap

V1 (this release) is the deliverable. The design leaves explicit hooks for:

  • V2 β€” crisis & liquidity: orchestrated bank-run / depeg / relayer-outage scenarios, interbank lending, refinancing + lender of last resort, SIWE-protected scenario controls.
  • V3 β€” markets & policy: an sEUR/DEP AMM (a real market price β†’ observable depeg), remunerated reserves, credit creation.
  • V4 β€” multi-chain: the L1 as settlement layer, one rollup per commercial bank, cross-chain settlement via HTLCs and intents.

License

MIT β€” Β© 2026 Mickael Osorio.

About

πŸ›οΈπŸ”— On-chain simulation of the two-tier monetary system: wholesale CBDC, tokenized bank deposits and a fiat-backed stablecoin, with atomic interbank settlement in central bank money. πŸ’Ά

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors