Multi-Chain Web3 Engine

EffectStream

Build multi-chain dApps without the bridges

A Web3 engine for dApps, games & autonomous worlds
EVM · Midnight · Cardano · Bitcoin · Celestia · Avail · NEAR

What we'll cover

  • 1. Why multi-chain dApps
  • 2. How EffectStream works
  • 3. Demos in the wild
  • 4. Live: launch an EVM + Midnight template
  • 5. Tools, links, try it yourself

Open source · TypeScript · one command to run a full local multi-chain stack

Part 1

Why multi-chain dApps?

Context, and the problem everyone keeps hitting

The problem with "pick one chain"

  • Your users & liquidity are spread across many chains — pick one and you cut off the rest.
  • The usual fix is bridging assets over… and bridges are the #1 hack target in crypto — it's hard to do right.
  • No single chain has it all — some are slow, some expensive, some lack the assets, or the features your app needs.
  • Every chain has its own VM, wallets, tooling → supporting another chain means a rewrite.

What people actually want

Reach users
on every chain
+ Use each chain's
strengths
+ No bridging
No custody risk
  • EVM — deep markets & existing tokens  ·  Midnight — privacy / ZK
  • Celestia — cheap data availability  ·  Cardano — native assets

A multi-chain dApp = one app that reads from many chains and folds them into one consistent state.

Part 2

How EffectStream manages it

The short tech version

The core model

Many chains
EVM · Midnight · …
Sync layer
normalize blocks
State machine
your TS logic
Indexed state
SQL / API

Read from many chains → fold into one deterministic state machine → query the result.

It's a sovereign rollup: inputs are ordered on-chain (data availability), your logic runs in your node, the resulting state is queryable.

Three pieces

Sync

Per-chain fetchers (viem for EVM, UTXORpc for Cardano, Midnight SDK, Bitcoin, Celestia…) poll finalized blocks and normalize them into one common format.

State machine

You write a typed grammar of commands + one handler each, in TypeScript. The runtime routes each input and commits SQL atomically per block.

Batcher

Users sign inputs and POST them over HTTP. The batcher packs many into one on-chain tx. Storage-first — survives crashes.

The payoff: non-custodial

  • All real interactions land on the chains, not inside your node.
  • Users keep full custody of their L1 assets the whole time.
  • Even if your app gets hacked, users' L1 assets are not at risk.

Plus: complex logic runs in TypeScript (not Solidity), so game state, physics, and rich rules are finally practical.

The shape of it

Chains · ordering + data availability
EVMMidnightCardano BitcoinCelestiaAvailNEAR
primitives watch the events you care about
SyncNormalize every chain → one deterministic order
State machineYour TypeScript logic — same inputs, same state, every node
Database + APIQueryable application state
↳ Batcher: users sign inputs → bundled into one on-chain tx → back to the top
Part 3

Demos in the wild

Real apps & templates, working today

Game · multichain · Arbitrum + Midnight

Safe Solver

Same logic over Arbitrum and Midnight blocks · deterministic randomness per block · play it live ▶

Proof at scale · Arbitrum + Cardano

Tarochi

A fully on-chain autonomous game — the volume proof: over 1M+ transactions, gas subsidized · 4-layer rollup stack + Cardano DEX · built in GameMaker.

Dev environment · EVM + Cardano

EVM-Cardano Explorer

A full local EVM + Cardano dev env from one command — Hardhat + YACI DevKit + Dolos. Mint NFTs, send ADA, one unified feed — minutes, not the days a Cardano indexer sync usually takes.

Part 4 · Live

Launch an EVM + Midnight app

From git clone to a running cross-chain dApp

What we're building

On EVM

An ERC-721 NFT. Public ownership, standard Transfer events.

On Midnight

A private property added via a ZK circuit — only the owner can run it; the result is published for the app to read.

One database unifies both chains. Public token + private metadata, no bridge.

The whole launch

git clone https://github.com/effectstream/effectstream.git
cd effectstream/templates/evm-midnight-v2

bun i          # install dependencies

bun run dev    # 🚀 compiles contracts AND boots the entire local stack

open http://localhost:10599    # 👀 the running dApp in your browser

One command — bun run dev — compiles the contracts and orchestrates everything below.

It launches everything for you — in order

The orchestrator runs the whole dependency graph from that one command:

🗄️ Database ⛓️ Chains
Hardhat · Midnight node, indexer, proof server
🔨 Compile
EVM + Compact
🚀 Deploy
contracts
📜 Your custom scripts 🖥️ Dev tools + frontend

 waits until every dependency is ready 

then starts the EffectStream node ⚡ Sync service  ·  State machine  ·  API

You declare this graph once in config — no manual wiring, no "start these 8 terminals."

The demo flow

  1. Open localhost:10599 → block heights from both chains ticking live.
  2. Mint an ERC-721 on the EVM side.
  3. Watch the sync node index it in ~a second — it appears in the app.
  4. Run the Midnight ZK circuit to attach a private property.
  5. See the property show up — one record, two chains.
  6. Optional: hit localhost:9999/api/erc721 → raw JSON.
Fallback

The running app

EVM + Midnight dApp running locally

Live local boot — block height ticking, EVM ↔ Midnight wallet demo, one merged token view.

Part 5

More tools & how to try it

The toolbox · talking to chains

Chains

Full sync for EVM, Midnight, Cardano, Bitcoin, Celestia, Avail, NEAR. Add one by declaring it in your config.

Primitives

Typed event watchers — ERC-20 / ERC-721, Midnight contract state, Bitcoin & Cardano addresses. You declare what to track.

Batcher

Users sign inputs → bundled into one on-chain tx. Storage-first & crash-safe — and it can pay gas for your users (next slide).

The toolbox · building your app

Sync

Reads the chains automatically and orders inputs deterministically — every node computes the same state.

State machine

A grammar of commands + one handler each, in TypeScript. SQL commits atomically per block.

API

Your indexed application state, queryable over HTTP — power any frontend.

Orchestrator

One command runs your whole local multi-chain stack. You declare the processes in your config — run only what your app needs.

@effectstream/wallets

One walletLogin() across MetaMask, Cardano CIP-30, Midnight, Mina, Polkadot, Algorand… polling hidden.

All TypeScript

No build step in dev — write your logic, run it, iterate.

Batcher · gasless UX

Sponsor your users' transactions

The batcher submits inputs on the user's behalf — your app holds the key and pays the gas. So you can offer Web2-style, gas-free UX:

Gasless onboarding

Users sign, you pay — no gas, no faucet, no bridge to get started.

Metered & tiered

Add a policy: subscription → 5 free tx/day, rate-limits, allowlists — enforced before submit.

Proven

Tarochi subsidized 1M+ tx this way — users never touched gas.

It's just custom batcher validation — see the batcher-validations template.

Give it a try

git clone https://github.com/effectstream/effectstream.git
cd effectstream/templates/evm-midnight-v2
bun i && bun run dev
  • Code — github.com/effectstream/effectstream
  • Docs — effectstream.github.io/docs
  • Blog — /docs/blog
  • Play — safesolver.midnight.fun

Templates to start from: minimal · evm-midnight-v2 · evm-cardano · chess-v2 · preorder

Thank you 🙏

Questions?

EffectStream — contact card

github.com/effectstream/effectstream  ·  effectstream.github.io/docs

Q&A

Topics we can dig into

How it works

Indexer impact · finality & slow settlement · batcher mechanics · "just a metadata standard?"

The template

Ready to clone? · common cross-chain pitfalls · private data ↔ EVM linkage

Capabilities

>2-chain swaps · how ordering / time works · wallets for partners

How it works

Do recent indexer issues affect our indexer?

  • The chain only moves forward when it can confirm blocks closed at or before the target time — otherwise it waits.
  • So a degraded upstream indexer makes sync pause and resume, never advance on bad data — state stays deterministic, nothing corrupts.
  • Sync reads from the chain's indexer/RPC and is decoupled from it; it catches up when the source recovers.
How it works

Sync times & slow finality (rollups settling for days)?

  • Each chain has a confirmationDepth — sync waits N blocks before treating a block as final (EVM ~12, BTC ~6, instant-finality 0).
  • A per-chain delaydepth × blockTime + buffer absorbs latency & reorg risk; slow/deep-settlement chains get a higher value.
  • The deterministic NTP "Main" clock ticks independently, so the app keeps a steady tick-rate regardless of any one chain's settlement speed.
How it works

Batcher — per chain, then sync? Not cross-network at once?

  • Correct. The batcher batches per chain / per adapter — independent queues, one bundled tx per chain — and the sync layer picks each up.
  • It is not doing a single atomic operation across multiple networks simultaneously.
  • Batch triggers: time / size / value / hybrid / custom. Confirmation: no-wait · wait-receipt · wait-effectstream-processed.
How it works

Is this mostly a metadata standard for publishing across networks?

  • No — it's a full execution + state model: read many chains → deterministic state machine → queryable state.
  • The metadata/NFT-projection standards (PRCs) are an optional feature, not the core.
The template

Ready for people to clone the Midnight-EVM work now?

  • Yes — early release but stable: only fixes are being applied, no API or structural changes.
  • You only need to clone if you want to add infra — otherwise just pull the @effectstream/* npm packages.
  • Docs: effectstream.github.io/docs
The template

Common issues devs hit with cross-chain apps?

  • Finality differences & reorgs — handled by per-chain confirmationDepth.
  • Different block times / ordering — handled by the NTP "Main" clock.
  • RPC reliability & rate limits — you still need an RPC, but you can slow query frequency to match your RPC's limits (per chain).
  • Per-ecosystem wallet & address formats — abstracted by typed primitives + the wallets package.
The template

How is the private data tied to the metadata on Ethereum?

  • Tied together in the L2 layer — a deterministic Postgres DB. Each EffectStream is a node; every node has the same deterministic database. No bridge.
  • You can mix & match any chain feature. Here we read the Midnight Ledger as if it were events — so you inherit Midnight's security.
  • Selective disclosure: we reveal only "Token XXX ↔ YYY on Midnight" — you could keep that secret instead.
Capabilities

Swaps across >2 chains at once (BTC ↔ ETH ↔ NIGHT)?

  • Yes. An action on A can trigger actions on both B and Coptimistically (parallel) or sequentially.
  • You decide the sequence. It's not a bridge by nature — but you can build one on top.
Capabilities

What determines transaction order? How is time managed across networks?

  • Reads are ordered & deterministic — events map onto a deterministic "Main" NTP clock by source block height + time, so every node reconstructs the same order.
  • Writes are best-effort — they happen whenever they're accepted; batchers retry, but still depend on external factors (gas prices, asset no longer available, bad tx).
Capabilities

What do the wallets mean for partners?

  • One walletLogin() across MetaMask/EVM, Cardano CIP-30, Midnight (Lace), Mina, Polkadot, Algorand, Avail. Users keep L1 custody — partners never hold funds.
  • Full sync + batcher + wallet on EVM, Midnight, Cardano, Avail, Bitcoin; others are wallet-connect / sign-only today.
  • Plus JS testing wallets (Midnight · EVM · Cardano) to drive features end-to-end — great for automated & AI-assisted build/test.