Skip to content

feat(prices): add depeg monitoring for LRTs and stablecoins#197

Draft
spalen0 wants to merge 2 commits intomainfrom
peg
Draft

feat(prices): add depeg monitoring for LRTs and stablecoins#197
spalen0 wants to merge 2 commits intomainfrom
peg

Conversation

@spalen0
Copy link
Copy Markdown
Collaborator

@spalen0 spalen0 commented Mar 31, 2026

Summary

  • Add centralized prices/ module for depeg monitoring of LRTs and stablecoins
  • Use Redstone fundamental push oracles (LBTC, cUSD) where available — any depeg is CRITICAL
  • Fall back to DefiLlama market pricing for weETH, ezETH, rsETH, pufETH, osETH, rswETH, mETH and stablecoins (FDUSD, deUSD, USD0, USD0++, USDe) — 2%+ depeg is CRITICAL
  • Route all LRT alerts to single lrt protocol channel with token symbol identification
  • Document Tenderly alert coverage and oracle research findings in README

Oracle Research Findings

Asset Oracle Tenderly
LBTC Redstone push 0xb415...bc81 ✅ Covered
cUSD Redstone push 0x9a5a...434a ✅ Covered
weETH, ezETH, rsETH, pufETH Redstone off-chain only (pull model) Needs alert if push oracle deployed
osETH, rswETH, mETH No fundamental feed N/A — DefiLlama only

Closes #196

Test plan

  • Verify oracle reads return valid data for LBTC and cUSD
  • Verify DefiLlama prices are fetched and ratios computed correctly
  • Verify alerts fire when thresholds are breached
  • Add prices/main.py to appropriate GitHub Actions workflow
  • Configure TELEGRAM_BOT_TOKEN_LRT / TELEGRAM_CHAT_ID_LRT and TELEGRAM_BOT_TOKEN_STABLES / TELEGRAM_CHAT_ID_STABLES secrets

🤖 Generated with Claude Code

Add centralized depeg monitoring using Redstone fundamental oracles
where available (LBTC, cUSD) and DefiLlama market pricing as fallback
for weETH, ezETH, rsETH, pufETH, osETH, rswETH, mETH and stablecoins.

Oracle-based assets alert on any depeg (below 0.998).
DefiLlama-based assets alert on 2%+ depeg (below 0.98).
LRT alerts route to a single "lrt" channel with token symbol.

Closes #196

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread prices/main.py Outdated
STABLES_PROTOCOL = "stables"

# Oracle threshold: any meaningful depeg from fundamental oracle is critical
ORACLE_DEPEG_THRESHOLD = Decimal("0.998")
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README/Tenderly docs below say the cUSD alert threshold is 0.9998, but the implementation is using a shared 0.998 threshold for both LBTC and cUSD. On today's oracle read, cUSD was 0.99975473, which is below the documented Tenderly threshold but would not alert here. If cUSD is supposed to be treated as "any depeg is CRITICAL", this likely needs a per-asset threshold (or at least a stricter stable-specific oracle threshold).

Comment thread prices/main.py Outdated
continue

if asset.underlying == "ETH":
ratio = price / eth_price
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback LRT path is using price / ETH_price as the depeg ratio, but the README just above documents fundamental exchange rates around 1.07-1.09 ETH for weETH/ezETH/rsETH/pufETH. That means a real several-percent depeg from fundamental can still stay above 0.98 and never alert here. For example, weETH at 1.03 ETH would be ~5.5% below a 1.09 fundamental, but this code would treat it as healthy. This needs a per-asset fair-value baseline (or off-chain fundamental feed), not a flat 1 ETH reference.

Comment thread prices/main.py
# ---------------------------------------------------------------------------
DEFILLAMA_STABLES: list[DefiLlamaAsset] = [
DefiLlamaAsset("FDUSD", "ethereum:0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409", "USD", STABLES_PROTOCOL),
DefiLlamaAsset("deUSD", "ethereum:0x15700B564Ca08D9439C58cA5053166E8317aa138", "USD", STABLES_PROTOCOL),
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dry-ran getCurrentPrices() against this exact key on 2026-04-22 and DefiLlama did not return a coin entry for ethereum:0x15700B564Ca08D9439C58cA5053166E8317aa138. Because missing prices are only logged and skipped, the PR currently advertises deUSD coverage without any alerting path if the asset disappears from the response. We should either fix the key/data source or escalate when a configured asset has no price so coverage failures are visible.

@spalen0
Copy link
Copy Markdown
Collaborator Author

spalen0 commented Apr 22, 2026

Review summary from local validation:

Main findings are in the inline comments, but there are a few non-diff gaps that still block calling the test plan complete:

  • prices/main.py is not added to any scheduled workflow, so the new monitor never runs in GitHub Actions.
  • .github/workflows/_run-monitoring.yml does not export TELEGRAM_BOT_TOKEN_LRT, TELEGRAM_BOT_TOKEN_STABLES, or TELEGRAM_CHAT_ID_STABLES. As written, stable alerts cannot route in Actions, and lrt only works if it falls back to the default bot token.
  • .env.example was not updated with the new LRT / STABLES Telegram vars, even though CONTRIBUTING.md says new protocols should add them.
  • There are no automated tests covering prices/main.py yet.

What I validated locally on 2026-04-22:

  • env LOG_LEVEL=INFO uv run pytest tests/ -> 131 passed.
  • uv run ruff check . -> passed.
  • uv run ruff format --check . -> passed.
  • Live dry run against mainnet + DefiLlama (Telegram patched out):
    • oracle reads succeeded: LBTC=1.00372748, cUSD=0.99975473
    • DefiLlama returned prices for all configured assets except deUSD
    • current data would emit CRITICAL alerts for rsETH=0.8963 and USD0++=0.9561

So the code path executes, but the monitor is still missing workflow wiring, secret plumbing, and the correctness fixes called out inline before I’d treat the PR as ready.

@spalen0
Copy link
Copy Markdown
Collaborator Author

spalen0 commented Apr 22, 2026

Pushed 16a2d8e with fixes. Responses to each review point:

cUSD threshold — fixed. ORACLE_DEPEG_THRESHOLD was a shared constant; replaced with a per-asset threshold field so cUSD now trips at 0.9998 and LBTC stays at 0.998, matching the Tenderly alerts documented in the README. cUSD at 0.99975 would now alert.

LRT ratio vs flat 1 ETH — fixed. DefiLlamaAsset now has fair_value + per-asset threshold. For accruing LRTs (weETH/ezETH/rsETH/pufETH) fair_value is set to a conservative floor under the current Redstone fundamental (1.05–1.07). The check normalizes market_ratio / fair_value, so weETH at 1.04 ETH is caught even though 1.04 > 0.98. For LRTs with no documented fundamental (osETH/rswETH/mETH), fair_value stays at 1.0 as a catastrophic-depeg floor.

deUSD silent skip — fixed. Missing DefiLlama prices now fire one MEDIUM alert per channel ("DefiLlama returned no price for: deUSD — depeg coverage degraded"). Coverage failures are visible instead of silently logged.

Workflow wiring — fixed. Added prices/main.py to hourly.yml.

Telegram env vars — fixed with one pushback: TELEGRAM_CHAT_ID_LRT was already in _run-monitoring.yml (line 69). Added TELEGRAM_BOT_TOKEN_LRT, TELEGRAM_BOT_TOKEN_STABLES, and TELEGRAM_CHAT_ID_STABLES (the chat-id one was the real blocker since chat IDs have no DEFAULT fallback in telegram.py).

.env.example — updated with the four LRT/STABLES entries.

Extra call-out not in review: USD0++ is a ~4-year locked bond that legitimately trades at a discount; a flat 0.98 threshold would have alerted constantly (your dry-run caught it at 0.9561). Gave it a per-asset threshold=0.90 and documented the rationale in the README.

Automated tests — not added in this pass; the monitor is mostly declarative config + a DefiLlama/RPC call. Happy to add a small unit test covering the deviation math + missing-price alert if you'd like a follow-up.

Address PR review feedback:
- Oracle threshold is now per-asset; cUSD uses 0.9998 to match the
  documented Tenderly alert (was 0.998, so cUSD=0.99975 slipped through).
- DefiLlamaAsset now carries fair_value and threshold so accruing LRTs
  are checked against their accrued ETH rate instead of a flat 1:1 peg.
  USD0++ gets a looser 0.90 floor because it's a 4-year bond that
  legitimately trades at a discount.
- Missing DefiLlama prices now raise a MEDIUM alert (e.g. deUSD on the
  dry-run date) so coverage failures are visible.
- Wire prices/main.py into the hourly workflow and add
  TELEGRAM_BOT_TOKEN_LRT/STABLES plus TELEGRAM_CHAT_ID_STABLES to
  _run-monitoring.yml; update .env.example accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Depeg

1 participant