About

Technical Architecture

Rails uses a multi-layer architecture to process and serve blockchain data efficiently and accurately. Two data paths run side by side — enriched event history and live chain state — and the API stitches them together.

System Components

1. Blockchain Indexer (Sieve)

Sieve — our in-house indexer — connects directly to Ethereum and Base and monitors every protocol's contracts in real-time.

  • ·Captures each protocol's own events — Trove and CDP operations, lending activity, spoke activity — across both chains
  • ·Processes each protocol's native event types — Supply, Borrow, Repay, Withdraw, Liquidation, TroveOperation, Redemption, and more — as they're emitted
  • ·Reads from Ethereum and Base through redundant RPC providers — a primary endpoint with automatic failover to a backup
  • ·Fetches oracle prices from Chainlink for accurate USD valuations
  • ·Routes events to the appropriate processing queues via RabbitMQ
  • ·Maintains real-time synchronization with blockchain state

2. Message Queue (RabbitMQ)

Manages event flow and ensures reliable processing of all blockchain events.

  • ·Separate queues for different event types
  • ·Guarantees event processing even during high load
  • ·Enables a decoupled, scalable architecture

3. Processors & Materialized Views

Enrich raw events and pre-compute the heavy joins so reads stay fast.

  • ·Attach USD values and protocol-specific context to each event
  • ·Write enriched history to Postgres
  • ·Materialized views pre-compute positions and timelines so the API serves them cheaply

4. Chain-State Refresher

Reads current balances and risk straight from each protocol's contracts, independent of the event history.

  • ·A background worker batches reads across positions via Multicall3 on a short refresh
  • ·Health factor, collateral factor, and live balances come from chain state, not inferred from events
  • ·Keeps positions opened through swap aggregators — which skip a protocol's standard events — accurate on screen

5. API & Frontend

Stitches both data paths together and renders the result.

  • ·An Express API joins enriched history with live chain state
  • ·The Next.js frontend renders timelines, positions, and event detail
  • ·Read-only throughout — no wallet connection, no account, no private keys

6. Vault Position Census

Vault positions are a set, not a stream: who holds a vault's shares is established by a daily census of the vault's own transfers rather than inferred from events as they pass.

  • ·A whole-history sweep of every Transfer a catalogued vault has emitted names each address that ever held its shares, so the set is complete rather than sampled from a floor
  • ·Each sweep is proven against the contract: the sum of every holder's balanceOf must equal totalSupply() at the sweep block, and a sweep that does not add up is refused and the previous census stands
  • ·Value is priced once, at the census block, through the vault's own convertToAssets and the chain's Aave V3 oracle, and each figure carries the oracle and the block it came from
  • ·Live figures on a card — shares, claim, share of the vault — are read from the contracts through Multicall3 per request, and the card states both blocks: the census's and the read's

Rails is open source. View on GitHub →