feat(morpho): group V1 governance alerts per vault; denominate V2 absolute caps - #337
Merged
Conversation
Extends the V2 per-vault grouping to the V1 governance monitor and moves the
shared machinery into protocols/morpho/_alerts.py, so both monitors buffer
findings into one VaultDiff and flush a single Telegram message per vault.
A vault queueing two new markets in the same multicall used to send two
near-identical messages that repeated the vault name and chain in each; it
now sends one with a header naming the vault once and a section per market.
Section bodies drop the "to vault X on CHAIN" suffix the header carries.
Two fixes the shared module picks up:
* A single section larger than one Telegram message (a batched multicall
submit renders one bullet per operation) now splits on line boundaries
instead of being handed to Telegram whole and truncated.
* V1 cache cursors are deferred like V2's, so a failed send is retried on the
next run rather than being recorded as alerted.
Absolute-cap decoding: every V2 cap limits the vault's own allocation, so it
is denominated in the vault's asset whatever id it is keyed by. The
collateralToken path had no asset to hand and printed the raw integer —
"cap 25000000000000" for what is 25.00M USDC. governance_v2 now reads
asset { symbol decimals } in the query it already issues and threads it into
decode_submit. type(uint128).max renders as "unlimited" rather than a
340-undecillion figure.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
spalen0
marked this pull request as draft
August 7, 2026 08:37
spalen0
marked this pull request as ready for review
August 7, 2026 08:44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #330, which grouped V2 governance alerts per vault. This does the same for the V1 monitor and fixes a cap-formatting bug reported from a live alert.
1. V1 governance alerts group per vault
A vault queueing two new markets in one multicall sent two near-identical messages, each repeating the vault name and chain:
Now three messages become two — grouping is per vault, so the two
Yearn OG USDCmarkets merge andOUSDstays its own message:The vault name and chain move to the header, so each section carries only what differs. Cap updates and market removals get the same treatment, and timelock/guardian changes join the same message at HIGH severity.
2. Shared grouping module
The machinery #330 added inside
governance_v2.pymoves toprotocols/morpho/_alerts.py(VaultDiff,send_vault_alerts, the splitter) so both monitors use one implementation. V2 behaviour is unchanged — its tests pass untouched apart from the import path.VaultDiff.defer()now takes any writer callable, since V1 records cursors throughwrite_last_executed_morpho_to_file(vault, market, type, ts)rather than V2'skey, valueform. V1 cursors are therefore deferred like V2's: a failed Telegram send is retried next run instead of being recorded as already alerted.The splitter also gained a case it did not handle: a single section larger than one Telegram message — a batched multicall submit renders one bullet per operation — now splits on line boundaries instead of being handed to Telegram whole and truncated.
3. Absolute caps are denominated in the vault's asset
Reported from a live alert:
Every V2 cap limits the vault's own allocation, so it is denominated in the vault's asset whatever id it is keyed by. The market path resolved decimals from market metadata; the
collateralTokenpath had no asset to hand and printed the raw integer.governance_v2now readsasset { symbol decimals }in the query it already issues and threads it intodecode_submit, so the same operation renders:Verified against the live pending configs on
Yearn OG USDC V2(BASE, USDC, 6 decimals):25000000000000 / 1e6 = 25.00M, matching the sibling market caps.type(uint128).max— Morpho's "no cap" sentinel, seen onSentora RLUSD Main— now renders asunlimitedinstead of a 340-undecillion figure.Tests
718 passed,ruff check/ruff formatclean. New coverage: V1 findings for one vault collapse into a single message with the vault named once; V1 cursors are deferred until after the send. Existing V1 tests moved to the buffered API.🤖 Generated with Claude Code