RWA data indexer for the Plume Network. Ingests on-chain capital flows and asset valuation from tokenized yield-bearing vaults, exposing them over a typed read API.
- Capital flows — async ingestion of ERC-4626
Deposit/Withdrawevents from a tokenized RWA vault. - Asset valuation — tracks
NAVUpdated(uint256,uint256)oracle emissions and computes real-time TVL / market cap in USD.
- FastAPI + Pydantic v2
- SQLModel over PostgreSQL, with an in-memory SQLite fallback for local/test
- web3.py
AsyncWeb3+AsyncHTTPProvider, fully async ingestion
Plume is an Arbitrum-Nitro L2 that settles to Ethereum L1. Two properties shape the indexer:
- Fast blocks. Plume produces blocks far faster than Ethereum's 12s slot, so
the ingestion cadence (
POLL_INTERVAL_SECS,LOG_CHUNK_SIZE, the readiness lag threshold) is tuned to a sub-second-to-few-second block time rather than inherited Ethereum defaults. Exact values are provisional pending live-RPC confirmation of block time andeth_getLogsrange caps. - L2 finality. The sequencer gives near-instant soft finality (the
latesthead), but a block is only reorg-proof once its batch posts and finalizes on L1, which lags by minutes. The indexer reads thefinalizedtag by default (configurable, plus a confirmation buffer) and persists block hashes per cursor for reorg detection. If an RPC doesn't serve a requested finality tag, head resolution degrades gracefully tolatest.
The POA/extraData middleware is enabled by default because Plume blocks carry a
non-32-byte extraData that web3.py's default block parsing rejects.
Every persisted row and cursor is stamped with chain_id (Plume mainnet
98866, testnet 98867), folded into the unique constraints and into every
NAV/flow lookup. A shared store can hold more than one network without
conflating identical (tx_hash, log_index) coordinates or leaking one chain's
data into another's valuation. On startup the configured chain_id is asserted
against the RPC's reported chain id, so a mismatched RPC_URL / CHAIN_ID pair
fails fast rather than silently indexing the wrong network.
git clone <repo> && cd theorem-plume
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,docs]"
cp .env.example .env # set RPC_URL, CHAIN_ID + contract addresses
Run without a Postgres DSN to fall back to in-memory SQLite.
src/theorem_plume/
config.py settings, dynamic db url resolution
logging.py structured json logging
exceptions.py error hierarchy
models/ sqlmodel tables
chain/ web3 provider, decoders, scrapers
services/ valuation (read-only, decoupled)
api/ fastapi routers
orchestration/ ingestion supervisor + lifespan
tests/
pytest -q # tests
ruff check . && ruff format . # lint + format
mkdocs serve # docs (local)
python scripts/dump_openapi.py # static openapi schema
MIT