| name | defi-overview |
| description | One-pass crypto read - tracked-protocol positions and health plus macro context, with regime take, DeFi verdict, biggest movers, yields, fees, breadth, Fear & Greed, and prediction markets. |
| metadata | {"title":"DeFi Overview","category":"crypto","var":"","tags":["crypto","defi","macro","positions"],"mode":"write","requires":["COINGECKO_API_KEY?"],"commits":true,"permissions":["contents:write"],"capabilities":["external_api","sends_notifications"]} |
${var} — Scope selector. Empty → full combined overview (tracked-protocol positions + macro context). positions → positions facet only (all watched positions); positions:<label> → a single tracked position by label. macro → macro facet only. Any other value → treat as a chain or protocol focus (e.g. solana, aave, arbitrum) applied to the macro read; positions are filtered to that chain when applicable.
Read memory/MEMORY.md for context. Read the last 2 days of memory/logs/ to avoid repeating numbers, to diff position values over time, and to cite yesterday's figure when flagging today's change. Read memory/on-chain-watches.yml (tracked positions) and the existing memory/topics/market-context.md (prior macro snapshot) — both are inputs below.
Thesis
The original produced a table of numbers. This version produces a read of the market: one verdict line at the top, then only items that changed or matter, each with a one-line reason a reader should care. TVL alone is lagging and emission-subsidized — we pair it with fees/revenue (real fundamentals) and split yields into sustainable (apyBase) vs incentive-driven (apyReward) so readers stop chasing scam-tier APYs. On top of the market read this skill also (a) checks the operator's tracked-protocol positions for health/liquidation/yield-drift risk, and (b) refreshes the decision-ready macro context file that downstream skills (token-pick, narrative-tracker) consume — all in one pass.
Facets & var routing
The skill has two facets. ${var} selects which run and how to scope them:
- Empty → run both facets: Positions and Macro. This is the comprehensive default.
positions → Positions facet only, all watched positions.
positions:<label> → Positions facet only, restricted to the position whose label matches <label>.
macro → Macro facet only (DeFi market read + broad crypto context + market-context.md refresh).
- Any other value → Macro facet, run in focus mode:
- matches a chain name in
/v2/chains (case-insensitive) → chain focus: scope DEX volume, fees, and yields to that chain; keep a 2-line market header for context; filter positions (if the Positions facet also runs) to that chain.
- matches a protocol slug in
/protocols → protocol focus: pull /protocol/{slug}, /summary/fees/{slug}, /summary/dexs/{slug} if it is a DEX; compare against its chain and its 30-day self.
- matches neither → proceed as a full macro overview and note
var unresolved: ${var} in the footer.
When both facets run (empty var), send one combined notification (Take → position alerts if any → DeFi read → macro snapshot) and still write memory/topics/market-context.md.
FACET A — Positions (tracked-protocol health)
(Runs when ${var} is empty, positions, positions:<label>, or a chain focus. Skip entirely for macro.)
Position config
Watched contracts and positions live entirely in memory/on-chain-watches.yml — no protocols are hardcoded in this skill. If the file is missing or has no type: pool / type: position entries, log DEFI_MONITOR_NO_CONFIG for this facet and skip it cleanly (no notification — an empty config is not an error; the Macro facet still runs when applicable).
watches:
- label: My Wallet
address: "0x1234...abcd"
chain: ethereum
rpc_url: https://eth.llamarpc.com
type: wallet
threshold: 0.1
- label: Uniswap Pool
address: "0xabcd...5678"
chain: ethereum
rpc_url: https://eth.llamarpc.com
type: contract
Steps — Positions
A1. Query each DeFi position
For each DeFi position in memory/on-chain-watches.yml (type: pool or type: position), filtered by ${var} if a label (positions:<label>) or chain focus is set:
- Query the contract for current state using
eth_call:
curl -s -X POST "${rpc_url}" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"'"$address"'","data":"'"$calldata"'"},"latest"],"id":1}'
- For known protocols, query standard view functions:
- Liquidity pools:
totalSupply, reserves, current tick/price
- Lending:
supplyRate, borrowRate, utilization
- Staking: earned rewards, APR
A2. Compare against last logged values
Compare current values against the last logged values for each position (grep prior runs in memory/logs/).
A3. Flag anything noteworthy
- Yield rate change > 20%
- Pool TVL drop > 10%
- Position approaching liquidation
- Impermanent loss exceeding threshold
A4. Positions output
positions / positions:<label> run: notify via ./notify (under 4000 chars) only if at least one position produced a noteworthy flag; otherwise log DEFI_MONITOR_OK and end (no notification on a quiet run).
- Combined (empty var) run: the positions block is included in the single combined notification only when there is at least one flag; a quiet positions check contributes nothing to the message (but still logs its per-position values).
Positions block template:
*DeFi Monitor — ${today}*
*Pool/Protocol Label* (chain)
TVL: $X | APR: Y%
Your position: details
Change since last check: summary
FACET B — Macro (DeFi market read + crypto context)
(Runs when ${var} is empty, macro, or a chain/protocol focus. Skip entirely for positions / positions:<label>.)
Steps — Macro
B0. Load prior macro snapshot (for deltas + preserve-on-failure)
Read the existing memory/topics/market-context.md if present. Extract, for delta computation later:
- BTC price, ETH price, Total mcap, BTC dominance, Total TVL, Fear & Greed value, and the prior DEX 24h volume.
- The full Token Picks Made table (never truncate — you will rebuild the new file with this table intact).
If the file doesn't exist, treat all deltas as n/a on the first run.
B1. Fetch (public, no auth — use WebFetch if curl fails)
mkdir -p .tmp
curl -fsS "https://api.llama.fi/v2/chains" > .tmp/chains.json
curl -fsS "https://api.llama.fi/protocols" > .tmp/protocols.json
curl -fsS "https://api.llama.fi/overview/dexs?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true" > .tmp/dexs.json
curl -fsS "https://api.llama.fi/overview/fees?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true" > .tmp/fees.json
curl -fsS "https://stablecoins.llama.fi/stablecoins?includePrices=true" > .tmp/stables.json
curl -fsS "https://yields.llama.fi/pools" > .tmp/pools.json
CG_HDR=(); [ -n "${COINGECKO_API_KEY:+x}" ] && CG_HDR=(-H "x-cg-demo-api-key: {COINGECKO_API_KEY}")
./secretcurl -s "${CG_HDR[@]}" "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true&include_market_cap=true" > .tmp/cg_price.json
./secretcurl -s "${CG_HDR[@]}" "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=20&page=1&sparkline=false&price_change_percentage=24h,7d" > .tmp/cg_markets.json
./secretcurl -s "${CG_HDR[@]}" "https://api.coingecko.com/api/v3/global" > .tmp/cg_global.json
./secretcurl -s "${CG_HDR[@]}" "https://api.coingecko.com/api/v3/search/trending" > .tmp/cg_trending.json
curl -s "https://api.alternative.me/fng/?limit=2" > .tmp/fng.json
curl -s "https://gamma-api.polymarket.com/markets?closed=false&order=volume24hr&ascending=false&limit=10" > .tmp/poly_vol.json
curl -s "https://gamma-api.polymarket.com/markets?closed=false&order=liquidity&ascending=false&limit=10" > .tmp/poly_liq.json
For each endpoint, if curl fails or returns non-JSON, retry once with WebFetch against the same URL (for CoinGecko, WebFetch without the API-key header — free tiers work). Mark each source ok or fail and carry it into the footer / Source Status line. Never block the whole run on a single source.
Notes on fields:
/protocols and /v2/chains already include change_1d / change_7d / tvl — use these directly, do not diff manually. /overview/dexs and /overview/fees return total24h, total7d, change_1d, change_7d, change_1m, protocols[].
- If
${var} is a chain focus, additionally fetch /overview/dexs/{chain} and /overview/fees/{chain} and filter pools by chain == var.
- If
${var} is a protocol focus, additionally fetch /protocol/{slug}, /summary/fees/{slug}, and /summary/dexs/{slug} (if a DEX).
- From
/coins/markets compute breadth: how many of the top 20 are green on 24h vs 7d. Breadth is a regime signal — 18/20 green = risk-on, 4/20 green = risk-off.
B2. WebSearch — macro catalysts (2 queries only; noise is expensive)
Use the built-in WebSearch tool for exactly:
crypto market today ${today} macro catalyst
BTC ETF flows ${today} (institutional flow signal)
Keep only items that would change a trader's positioning today. Discard recap/explainer articles. Mark websearch=ok|fail.
B3. Compute the DeFi regime verdict (ONE line)
Score three dimensions from the last 24h:
tvl_d = overall TVL change_1d (sum across /v2/chains)
vol_d = DEX volume change_1d (from /overview/dexs)
stable_d = stablecoin supply change_1d (sum from /stablecoins)
Verdict rules (pick the first that matches):
- All three > +2% → Risk-on — capital flowing in across TVL, volume, and stables.
- Two of three < −2% → Risk-off — capital unwinding.
|tvl_d| < 1% AND |vol_d| < 5% → Sideways — no conviction; grind day.
- Otherwise → Mixed — describe the split in ≤12 words (e.g. "TVL drifting up on steady volume, stables flat").
B4. Compute the Market Take (the macro headline)
The Take is the core macro output — everything else is input to it.
Market Take format (exactly 3 lines):
Take: <regime> — <one-sentence why, citing 2 concrete numbers>.
Conviction: <high | medium | low> — <which signals agree; which disagree>.
Evidence: <one sentence naming the single strongest datum behind this call>.
Example:
Take: risk-on — BTC +3.1% 24h with 17/20 top-cap majors green.
Conviction: high — F&G, breadth, and 7d TVL all point up; only BTC dominance disagrees (flat).
Evidence: DEX 24h volume $7.8B, highest since March and +42% vs 7d avg.
Score the regime using these inputs:
- BTC 24h% (±2% threshold)
- Breadth (top-20 green count)
- Fear & Greed (today vs yesterday; buckets: 0-24 Extreme Fear, 25-49 Fear, 50-74 Greed, 75-100 Extreme Greed)
- BTC dominance 24h change (from
/global)
- TVL 7d delta (DeFiLlama)
- DEX volume vs the prior snapshot's DEX volume
Assign one regime label:
- risk-on — BTC up, breadth >14/20, F&G ≥55 and rising, TVL up 7d
- risk-off — BTC down, breadth <7/20, F&G ≤45 and falling
- rotation — BTC flat or dominance falling while breadth high (alts outperforming)
- chop — no single signal dominates; small moves, flat F&G
- capitulation / squeeze — only if BTC ±5%+ in 24h with F&G extreme
Also emit conviction in {high, medium, low} based on how many signals agree.
B5. Pick what goes in the DeFi read
Each section caps at 3 items. Drop any section whose best item fails its inclusion rule — don't pad.
- Top chains (3): rank by TVL; show
change_1d only if |change_1d| >= 1%, otherwise suppress the delta.
- Movers — chains (1 up, 1 down): filter
|change_1d| >= 5% AND tvl >= $500M. Require a ≤15-word "why" grounded in observed data (unlock, points program, bridge activity, depeg, exploit, launch). If you can't name a cause from data or memory, write "no obvious catalyst" — do not invent one.
- Movers — protocols (1 up, 1 down): filter
|change_1d| >= 10% AND tvl >= $100M. Same "why" rule.
- Fundamentals — fees leaders (top 3 by 24h fees from
/overview/fees): include change_1d in fees vs 7d average. Fees > TVL for real demand.