Architecture

HoodETF is three cooperating layers on top of Robinhood Chain: contracts, a backend indexer + API, and a web app. Only the contracts hold funds or enforce rules; everything off-chain is convenience and presentation.

System overview

                          Robinhood Chain (chain id 4663)
   ┌───────────────────────────────────────────────────────────────┐
   │  Whitelist ──► BasketFactory ──clones──► Basket  Basket  Basket │
   │       │                                    ▲                     │
   │  OracleLib (Chainlink reads)               │ mint / redeem       │
   │                                   HoodZapRouter ─► HoodV4SwapAdapter ─► Uniswap v4
   └───────────────────────────────────────────────────────────────┘
              ▲ reads (logs, eth_call)                 ▲ tx
              │                                         │
   ┌──────────┴───────────┐                 ┌───────────┴───────────┐
   │  Backend (Node/Hono) │                 │   Web app (Next.js)   │
   │  indexer · NAV worker │◄── REST /v1 ──► │  app.hoodetf.org      │
   │  leaderboard · zapper │                 │  wallet + SIWE        │
   └──────────────────────┘                 └───────────────────────┘

Layer 1 — Smart contracts

The trust boundary. All value and rules live here.

  • Whitelist — governance-owned registry mapping each allowed token to its Chainlink feed, staleness limit, and decimals.
  • OracleLib — a library that reads a Chainlink feed with staleness + sequencer-uptime guards, returning stale=true instead of reverting.
  • Basket — the vault. Holds the constituent tokens, issues ERC-20 shares, and implements in-kind mint/redeem, zap-mint, fees, and NAV.
  • BasketFactory — clones, seeds, and initializes new baskets atomically, and registers them.
  • HoodZapRouter — atomic one-click buy/sell: pulls USDG, swaps through allowlisted venues, mints/redeems in one transaction.
  • HoodV4SwapAdapter — a plain-ERC20 swap venue that trades directly against Uniswap v4 (single-hop and USDG→ETH→token multi-hop).

Baskets are immutable once deployed: constituents and fees are fixed, and there is no function that lets anyone withdraw another holder's assets.

Layer 2 — Backend (indexer + API)

A Node/TypeScript service (Hono + viem + BullMQ + Postgres + Redis) that:

  • Indexes BasketCreated and mint/redeem events into Postgres.
  • Computes NAV on a schedule: reads each basket's on-chain balances and Chainlink prices, writes NAV snapshots, and refreshes per-constituent weights.
  • Ranks baskets by return over 24h / 7d / 30d / inception windows into Redis sorted sets (the leaderboard).
  • Builds zap quotes — splits a USDG amount across constituents by on-chain value, finds the best route per leg through the venue adapters, and returns a ready-to-submit router transaction.
  • Serves all of this to the web app over a private REST API.

The backend never holds funds or keys that can move a user's assets. If the backend is down, the app degrades (stale/less data) but the contracts keep working — in particular, redemption is entirely on-chain.

Layer 3 — Web app

A Next.js app served on three host-routed surfaces from one deployment:

  • hoodetf.org — marketing site.
  • app.hoodetf.org — the dapp: discover, basket detail, portfolio, create wizard, trade.
  • admin.hoodetf.org — operator dashboards (monitoring, whitelist, venues).

Wallet connection uses RainbowKit; authenticated features use Sign-In With Ethereum (SIWE). On-chain numeric amounts are represented as raw integer strings (see the wire-format note in Core concepts), which the client divides down for display.

Chain

Everything runs on Robinhood Chain, an Arbitrum-Orbit L2 with chain id 4663. The stablecoin used for one-click zaps is USDG (6 decimals). Deployed contract and token addresses are on the Deployed addresses page.