All packages

morpho_blue_paulie_base

PaulieB14
v0.1.0/2 downloads/Repository

Package ref

morpho-blue-paulie-base@v0.1.0

Run package

CLI

Run db_out from the command line.

substreams run morpho-blue-paulie-base@v0.1.0 db_out -e base
Authenticate by running substreams auth or directly on thegraph.market (see docs).

README

Morpho Blue + MetaMorpho Substreams

Event-sourced market state, user positions and MetaMorpho vault balances for Morpho Blue on Ethereum mainnet, emitted as upsert SQL you can sink into your own database.

Substreams

What this is

StreamingFast already ships a Morpho Blue event decoder. This package does not fork it — it imports it and spends its modules on the layer that decoder does not have:

StreamingFast morpho-blue-substreamsthis package
Blue event tapemap_eventsimported, not reimplemented
Admin events (SetFee, SetFeeRecipient, EnableIrm, …)map_blue_admin + store_blue_config
Market params / totals✅ stores
Per-user positionsstore_positions
MetaMorpho vaults✅ factory + vault share tracking
SQL outputappend-only event tablesupsert current-state tables

Module graph

                        ┌─ store_market_params ─┐
morpho_sf:map_events ───┼─ store_market_totals ─┤
                        └─ store_positions ─────┤
                                 ▲              │
map_blue_admin ─→ store_fee_recipient           ├─→ db_out ─→ DatabaseChanges
              ├─→ store_market_fee ─────────────┤
              └─→ store_blue_config ────────────┤
                                                │
map_metamorpho_factory ─→ store_vaults ─┐       │
                                        ▼       │
                        map_metamorpho_events ──┤
                                 ├─→ store_vault_positions
                                 └─→ store_vault_totals

Correctness notes

Three things make event-sourced Morpho accounting easy to get wrong. All are handled here, and all are documented in docs/MORPHO_BLUE_ACCOUNTING.md.

  1. Events must be replayed in log order. The upstream Events message groups events by type. Iterating field-by-field can apply an AccrueInterest after a Supply that actually came later in the same transaction — on-chain, interest always accrues first. Every store here merge-sorts on log_index before applying anything.

  2. Fee shares are minted silently. AccrueInterest credits feeShares straight into the fee recipient's supply position and emits no Supply event (EventsLib says so explicitly). The upstream decoder does not decode SetFeeRecipient, so this package adds map_blue_admin and reads the recipient at the accrual's own ordinal — a SetFeeRecipient later in the same block must not be applied retroactively.

  3. Bad debt is socialized. On Liquidate with bad debt, the loss comes off totalBorrowAssets and totalSupplyAssets, and the borrower's remaining borrow shares are zeroed. Suppliers eat it.

Values are raw on-chain integers. Shares are not assets — convert with Morpho's virtual-share math (VIRTUAL_SHARES = 1e6, VIRTUAL_ASSETS = 1) against the matching market_states row.

Build and run

The upstream decoder is not published to the Substreams registry (it only exists as source in streamingfast/substreams-chain-modules), so a build of it is vendored at vendor/ to keep this package self-contained. make vendor regenerates it from source.

make build          # cargo build --target wasm32-unknown-unknown --release
make pack           # -> morpho-blue-paulie-v0.1.0.spkg
make stale          # guard: fails if the .wasm is older than src/

substreams run morpho-blue-paulie-v0.1.0.spkg db_out \
  -e mainnet.eth.streamingfast.io:443 --start-block 18883124 --stop-block +1000

substreams pack does not compile. It packages whatever .wasm sits at the manifest path, so always make build first — make stale catches it.

Sink the output with substreams-sink-sql against schema.sql. Numeric columns default to 0 because db_out emits only the columns that changed in a block.

Tables

tablekeyholds
marketsmarket_idthe 5-tuple: loan/collateral token, oracle, IRM, LLTV
market_statesmarket_idsupply/borrow assets and shares, collateral, fee
positions{market_id}:{user}supply_shares, borrow_shares, collateral
vaultsvault addressMetaMorpho name, symbol, asset, factory
vault_positions{vault}:{user}vault share balance
vault_statesvault addresstotal_shares (exact), net_deposited_assets
blue_configowner / irm:… / lltv:…protocol owner and enabled IRM/LLTV sets

Scope

In: Ethereum mainnet, Morpho Blue from block 18883124, MetaMorpho factories V1.1 (0x1897A899…) and V1 (0xA9c3D3a3…).

Not yet: USD prices, APYs and rewards (use the Morpho API — it already does these well); live health factors, which need an oracle price() read at 1e36 scale — positions + market_states + lltv + the oracle address are emitted so a consumer can join prices themselves; Vault V2; other chains (see below).

Note vault_states.net_deposited_assets is deposit principal, not AUM — a vault also earns interest in the underlying Blue markets, which emits no vault-level event. For true AUM, join the vault's own rows in positions.

Other chains

Morpho Blue is deployed at the same address on Base and elsewhere, but a Substreams package is pinned to one network:, and the vendored upstream decoder is mainnet-only. Base support means a second manifest plus a Base build of the decoder — same Rust crate, no handler changes. Tracked as follow-up.

Verification

Validated against mainnet at block 21,000,000 and at real vault-creation blocks: markets, positions and vault events decode and accumulate, and vault metadata matches the Morpho API exactly (e.g. MC.wM / "MEV Capital M^0 Vault" at block 20,873,628). Absolute totals across a full backfill are not yet verified — that needs a paid endpoint, since store backfill from block 18883124 exceeds the free tier's 10,000-block limit.

License

MIT

Modules

Execution graph

14 modules
store

store_blue_config

Protocol owner and the enabled IRM / LLTV sets (`owner`, `irm:{address}`, `lltv:{value}`). Append-only — Morpho has no disable.

from #13977148

Store value

string

Update policy

set

store

store_fee_recipient

Current protocol fee recipient, keyed `fee_recipient`. Written at the event's log index so consumers can resolve it at a precise ordinal.

from #13977148

Store value

string

Update policy

set

store

store_market_fee

Per-market fee in WAD, keyed `fee:{market_id}`.

from #13977148

Store value

string

Update policy

set

store

store_market_totals

Running supply/borrow assets and shares plus total collateral per market. Applies interest accrual and socialized bad debt in true log order.

from #13977148

Store value

bigint

Update policy

add

store

store_positions

Per-user supply shares, borrow shares and collateral, keyed `pos:{market_id}:{user}:{field}`. Credits the silent AccrueInterest fee-share mint to the fee recipient in effect at that ordinal.

from #13977148

Store value

bigint

Update policy

add

store

store_vault_positions

Per-user vault share balances from mint/burn/transfer, keyed `vpos:{vault}:{user}`.

from #13977148

Store value

bigint

Update policy

add

store

store_vault_totals

Vault share supply (exact) and net deposited assets (principal only — excludes interest earned in the underlying Blue markets).

from #13977148

Store value

bigint

Update policy

add

Show 1 dependency