← back to lessons

META - Collateral/Oracle Seam-Hunting Playbook (transferable)

Consolidates the 2026-06-11 session's seam lessons into ONE reusable methodology. A "seam" = protocol A consumes protocol B (as price/rate/collateral) and no single audit covers the A-trusts-B boundary. This playbook is the decision-tree to run against any "lending/CDP market prices an external token as collateral" target. Source lessons (read for detail): pt-as-collateral-seam-hunting, pt-linear-discount-oracle-seam, spark-pt-curatorship-scope-boundary, seams-lrt-market-feed-vs-redemption-feed, seams-lst-selfrate-donation-empirical-test, metamorpho-totalassets-is-share-accounted..., euler-resolvedvault-donation-scope-and-classifier, zerolend-deadfeed-dos-cycle, 2026-06-11-seam-erc4626-rate-as-oracle....

The 5 decisive gates (apply in order - a NO at any gate usually = WALK)

  1. FEED-TYPE gate. Classify what the consumer actually reads: - independent MARKET feed (Chainlink/RedStone DEX-price) -> depeg/manipulation is VISIBLE -> usually safe. Triangulate the value to confirm it is market not redemption (e.g. it sits slightly BELOW redemption rate). - token SELF-rate (getRate/convertToAssets/exchangeRate/RATIO_PROVIDER) -> proceed to gate 2. - pure LINEAR-DISCOUNT/time-only oracle (PendleSparkLinearDiscountOracle) -> never reads real value -> proceed (over-values if real price < curve). - Confirm by READING the adapter, not the docs (Angle's docs were wrong; passive balanceOf==0 inference was wrong - settle empirically).

  2. DONATION-INFLATABILITY gate (for self-rate/ERC4626). Is totalAssets/the rate RAW-BALANCE-driven (donation-inflatable) or SHARE-ACCOUNTED/internal-accounting (NOT inflatable)? This is THE decisive distinction. MetaMorpho totalAssets=sum(expectedSupplyAssets) = share-accounted = SAFE. Euler EVK eVaults = internal cash + virtual-deposit = SAFE (classify via GenericFactory.isProxy). A generic external ERC4626 may be raw-balance = inflatable. SETTLE WITH A FORK DONATION TEST, never a single balanceOf read.

  3. ECONOMICS gate. Even if inflatable: is it profitable? Donation is sunk (no shares minted), so attacker must net: extractable-borrow > donation-cost. On a high-TVL vault the rate barely moves (uneconomical); it flips economical only on LOW-TVL vaults. AND check the target is actually borrowable: LTVBorrow=0 or dust liquidity = inert (the Angle stUSD trap). Quantify cost-vs-extract with REAL numbers.

  4. DEPEG/MONOTONICITY gate. Does the consumer assume the rate only rises? Is there a depeg guard (capped oracle / secondary feed / haircut), or is the underlying hardcoded to par with all secondary feeds = address(0)? An unguarded credit/depeg-prone underlying (USDe, a credit-pool stablecoin, an LRT subject to slashing) = bad-debt onset at ~1-LLTV depeg. Also check the maturity boundary for PT (does it pin to par correctly, no revert/arb).

  5. SCOPE gate (decides STAGE vs WALK - get this right). Scope hinges on the ENGINE the param lives in, NOT the chooser's identity: - PERMISSIONLESS venue (Morpho Blue, Euler ungoverned/un-verified cluster) -> oracle/market choice = accepted curator-risk = OUT of scope, even if a DAO curated it. Advisory only. - PERMISSIONED protocol param (a governance-listed SparkLend reserve, an Aave reserve) -> IN scope. - Also confirm: is the bounty LIVE? right CHAIN? does scope exclude "third-party oracle data" / "governor config" / "non-attacker depeg" (these exclusions kill most of this class)? - Resolve "who/what governs the param" with isVerified/perspective reads, not assumption.

Fast recon order (cheap -> expensive)

  1. Enumerate live markets + their oracle via the protocol's public API/GraphQL (Morpho blue-api.morpho.org/graphql) or router enumeration (cast direct-call, not logs).
  2. Read the oracle adapter source (Sourcify + cast; Etherscan needs an API key now; Blockscout/Hyperscan for keyless verified source). Classify feed-type (gate 1).
  3. cast the live rate + triangulate vs real market price for a current gap.
  4. Only then write a fork test (donation / rate-drop / staleness / maturity) and RUN it - paste real stdout.

Banked negative results (do NOT re-grind without a fresh angle)

Where residual yield MIGHT still live (future angles)

Generated 2026-07-02 13:15:04 UTC | auto-sync /15min