npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@1delta/margin-fetcher

v0.0.218

Published

Multi-protocol lending data fetcher supporting Morpho Blue, Aave V2/V3, Compound V2/V3, Euler, Init, and Lista DAO. Provides public market data (rates, TVL, configs) and per-user position data (balances, shares, collateral) in a unified format.

Readme

@1delta/margin-fetcher

Multi-protocol lending data fetcher supporting Morpho Blue, Aave V2/V3, Compound V2/V3, Euler, Init, and Lista DAO. Provides public market data (rates, TVL, configs) and per-user position data (balances, shares, collateral) in a unified format.

How Morpho Blue Works

Protocol overview

Morpho Blue is an isolated-market lending protocol. Unlike pooled protocols (Aave, Compound) where all assets share a single pool, each Morpho market is a standalone pair defined by five parameters:

| Parameter | Description | |-----------|-------------| | loanToken | The asset that can be supplied and borrowed | | collateralToken | The asset deposited as collateral | | oracle | Price oracle for the pair | | irm | Interest Rate Model contract | | lltv | Liquidation Loan-To-Value ratio (18-decimal WAD) |

These five parameters are hashed into a uniqueKey (bytes32) that identifies the market on-chain.

Interest rate model

Morpho uses an adaptive curve IRM that adjusts rates based on utilization relative to a 90% target:

utilization = totalBorrowAssets / totalSupplyAssets

If utilization > 90%: rateAtTarget increases over time (via exponential adjustment)
If utilization < 90%: rateAtTarget decreases over time

borrowRate = curve(rateAtTarget, utilization)
supplyRate = borrowRate * utilization * (1 - fee)

The curve uses a steepness factor of 4x, meaning at full utilization the rate is 4x the rate-at-target. Rates are stored as per-second WAD values and compounded continuously.

Key constants:

  • Target utilization: 90%
  • Curve steepness: 4x
  • Min rate at target: ~0.1% APY
  • Max rate at target: ~200% APY
  • Adjustment speed: 50x/year (exponential)

Share-based accounting

Positions are tracked via shares rather than raw assets. This allows interest to accrue without storage updates per-user:

assets = shares * (totalAssets + 1) / (totalShares + VIRTUAL_SHARES)

Where VIRTUAL_SHARES = 1e6 prevents share inflation attacks.

Market data representation

Each Morpho market produces two entries in the normalized output:

  1. Loan entry — the borrowable asset

    • Has borrowingEnabled: true, collateralActive: false
    • Contains deposit/borrow APRs, total supply/debt, liquidity
    • Rewards (MORPHO token incentives) attached here
  2. Collateral entry — the collateral asset

    • Has borrowingEnabled: false, collateralActive: true
    • LTV factors derived from the market's lltv
    • No interest rates (collateral doesn't earn yield in Morpho)

Whitelisted vs unlisted markets

Morpho markets can be whitelisted (curated, visible in the Morpho UI) or unlisted (removed from curation). The includeUnlistedMorphoMarkets flag controls whether unlisted markets are fetched from the API. Unlisted markets are tagged with isListed: false on the MorphoMarket params.

Architecture

Data fetching strategy

The fetcher uses a hybrid approach that routes each lender to either an API or on-chain path:

getLenderPublicDataAll(chainId, lenders, ...)
├── lenderCanUseApi(lender, chainId)?
│   ├── YES → getLenderPublicDataViaApi()  →  Morpho GraphQL API
│   └── NO  → getLenderPublicData()        →  On-chain multicall via Morpho Lens
└── Promise.all([onChain, api]) → merged result

Morpho Blue uses the API on most chains. On-chain fallback is used for chains without API support (OP Mainnet, Soneium, Hemi, Berachain, Sei).

API path (GraphQL)

Fetches from https://blue-api.morpho.org/graphql:

fetchMorphoMarkets(chainId, includeUnlisted)
  → GraphQL query (paginated: 200/page, 2 pages for Ethereum mainnet)
  → GetMarketsResponse
  → convertMarketsToMorphoResponse()
  → { [marketId]: MorphoGeneralPublicResponse }

The API provides pre-computed APYs, USD values, and reward data. APY→APR conversion is applied during normalization.

On-chain path (Morpho Lens)

Uses a custom lens contract that returns compact binary-encoded market data:

buildMorphoCall(chainId)
  → multicall to MORPHO_LENS.getMarketDataCompact(morpho, marketHashes[])
  → chunks of 50 markets per call (calldata size limit)
  → raw bytes response

getMorphoMarketDataConverter()
  → decodeMarkets(bytes)           // 256-byte records → Market[]
  → MathLib.getBorrowApy(...)      // compute rates from rateAtTarget + utilization
  → MathLib.getSupplyApy(...)
  → { [marketId]: MorphoGeneralPublicResponse }

Binary encoding (256 bytes per market)

Offset  Size   Field
0       20     loanToken (address)
20      20     collateralToken (address)
40      20     oracle (address)
60      20     irm (address)
80      16     lltv (uint128)
96      32     price (uint256) — collateral/loan exchange rate in WAD
128     32     rateAtTarget (uint256) — per-second interest rate
160     16     totalSupplyAssets (uint128)
176     16     totalSupplyShares (uint128)
192     16     totalBorrowAssets (uint128)
208     16     totalBorrowShares (uint128)
224     16     lastUpdate (uint128) — timestamp
240     16     fee (uint128)

User data path

buildMorphoUserCallWithLens(chainId, account, lender, marketIds)
  → MORPHO_LENS.getUserDataCompact(marketHashes[], account, morpho)
  → chunks of 100 markets per call

decodePackedMorphoUserDataset(hex)
  → [uint16 count] + [130-byte records × count]
  → BalanceInfo[] { index, supplyShares, borrowShares, supplyAssets, borrowAssets, collateral }

getMorphoUserDataConverterWithLens()
  → map balances to market IDs via index
  → separate loan positions (supply/borrow) from collateral positions
  → format to UserData with USD values

File structure

src/lending/
├── public-data/
│   ├── fetchLenderAll.ts          # Hybrid router (API vs on-chain)
│   ├── fetchLender.ts             # On-chain multicall dispatcher
│   ├── fetchLenderExt.ts          # API dispatcher
│   └── morpho/
│       ├── fetchPublic.ts         # GraphQL query + fetch logic
│       ├── convertPublic.ts       # API response → normalized format
│       ├── publicCallBuild.ts     # Morpho Lens call builder
│       ├── getMarketsFromChain.ts # On-chain response → normalized format
│       └── utils/
│           ├── evmParser.ts       # Binary decoder (256-byte records)
│           ├── mathLib.ts         # WAD math, rate calculations
│           └── parsers.ts         # LTV parsing, number formatting
├── user-data/
│   └── morpho/
│       ├── userCallBuild.ts       # User position call builder
│       ├── decoder.ts             # User data binary decoder
│       ├── userCallParse.ts       # Balance → UserData conversion
│       ├── morphoLib.ts           # Share ↔ asset conversion
│       └── types.ts               # Parameter position enums
└── ...

src/types/lender/
└── morpho-types.ts                # GetMarketsResponse, MorphoMarket, MorphoGeneralPublicResponse

Lista DAO extension

Lista is a Morpho Blue fork with additional per-market fields. Uses a 357-byte binary record instead of 256:

| Extra field | Type | Description | |-------------|------|-------------| | minLoan | uint128 | Minimum loan amount | | hasWhitelist | bool | Whether the market has access control | | loanProvider | address | Yield source for loan token | | collateralProvider | address | Yield source for collateral | | broker | address | Authorized broker contract |

User data also includes per-market whitelist flags prepended before the balance records.