ops(feeds): retire the cNGN feed signer; the mark alert retires itself with it - #77
Merged
Merged
Conversation
…f with it `0xc9f1ffDE…20fdc`, the EOA that pushed prices into the cNGN spot feed 0x41512C6a, ran out of gas on 2026-09-11 (0.0000017 ETH left, nonce 65,466) and is deliberately not being refunded. The mark keeper is a downstream casualty: it reads that feed, the read reverts BLF_DataTooOld(), and it fails closed rather than marking to a frozen price -- which is the correct behaviour. Nothing that trades depends on either feed this signer wrote to. Its last 100 transactions went to exactly two destinations, and both were abandoned on purpose before it died: 0x41512C6a cNGN spot spot moved to static feeds at the SRM cutover, 2026-09-10 0xDAe566ad market 1 USDC moved off in the market-1-inert batch, 2026-09-09, marginFactor 0 Read off chain rather than assumed, 2026-09-22: - totalPosition / totalLongPosition / totalShortPosition on the SEP16 future are all 0, under both the DFXM and the SRM. - The SEP16 manager 0xcE01f3D7…4d49 is allowedModules = false on Matching, so its accounts cannot settle whatever any feed says. - The static feeds answer (0xec4ad7B2 -> 743376685636834) while the live one reverts, and a real spot settlement landed 2026-09-20 (tx 0xb3df1d1d) with this feed already 9 days stale. The alert is retired as a CONDITION, not deleted and not a disabled timer. check_mark_staleness.py returns early when open interest is zero, in the same shape as its existing settled-series exit, and re-checks that premise on every run -- so the day anyone opens a position here it resumes by itself. A retirement that needs a human to remember to undo it is how a venue ends up with an unmonitored market. It will not infer "safe to skip" from a failure to check: if the open-interest read itself fails it alerts and exits 1. Both paths exercised against the live chain before this was written -- zero-OI exits 0 quietly, unreachable RPC exits 1 with OPEN INTEREST CHECK FAILED. Un-retiring is in the runbook: fund the signer (~0.01 ETH/month at ~1 update a minute) and restart the keeper, BEFORE re-pointing any market at a live feed. Not done from here: numo-mark-keeper.service and numo-mark-alert-ssm.service are still enabled on the ops box. The keeper is harmless (it fails closed every cycle) but both are now noise. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Decision
Retire
0xc9f1ffDE…20fdc, the EOA that pushed prices into the cNGN spot feed0x41512C6a. It ran out of gas on 2026-09-11 (0.0000017 ETH left, nonce 65,466) and is deliberately not being refunded.The mark keeper is a downstream casualty, not a second fault: it reads that feed, the read reverts
BLF_DataTooOld(), and it fails closed rather than marking to a frozen price — correct behaviour.Nothing that trades depends on it
The signer's last 100 transactions went to exactly two destinations, and both were abandoned on purpose before it died:
0x41512C6acNGN spot0xDAe566admarket 1 USDCmarginFactor 0Read off chain rather than assumed:
totalPosition/totalLongPosition/totalShortPositionon the SEP16 future are all 0, under both the DFXM and the SRM0xcE01f3D7…4d49isallowedModules = falseon Matching — its accounts cannot settle whatever any feed says0xec4ad7B2→ 743376685636834) while the live one reverts, and a real spot settlement landed 2026-09-20 (tx0xb3df1d1d) with this feed already 9 days staleThat last point is the load-bearing one: spot has been trading fine throughout.
The alert retires itself
check_mark_staleness.pyreturns early when open interest is zero — in the same shape as its existing settled-series exit — and re-checks that premise on every run. The day anyone opens a position on this future, the alert resumes on its own.That's deliberate. A retirement that depends on a human remembering to undo it is how a venue ends up with an unmonitored market, and this alert's whole purpose is that "if marks stop, the losing side of any open position stops being margined." With no position there is no losing side.
It will not infer "safe to skip" from a failure to check. If the open-interest read itself fails it alerts and exits 1. Both paths were exercised against the live chain before this was written:
Un-retiring
In the runbook: fund the signer (~0.01 ETH/month at ~1 update a minute; 0.05 ETH ≈ 5 months) and restart the keeper — before re-pointing any market at a live feed, not after.
Not done from here
numo-mark-keeper.serviceandnumo-mark-alert-ssm.serviceare still enabled on the ops box; I couldn't reach it (SSO lapsed). The keeper is harmless — it fails closed every cycle — but both are now noise in the journal and an RPC round trip a minute.🤖 Generated with Claude Code