Skip to content

ops(feeds): retire the cNGN feed signer; the mark alert retires itself with it - #77

Merged
robertleifke merged 1 commit into
mainfrom
ops/retire-cngn-feed-signer
Sep 22, 2026
Merged

robertleifke merged 1 commit into
mainfrom
ops/retire-cngn-feed-signer

Conversation

@robertleifke

Copy link
Copy Markdown
Contributor

Decision

Retire 0xc9f1ffDE…20fdc, the EOA that pushed prices into the cNGN spot feed 0x41512C6a. 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:

feed why it is dead
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:

  • totalPosition / totalLongPosition / totalShortPosition on the SEP16 future are all 0, under both the DFXM and the SRM
  • SEP16's manager 0xcE01f3D7…4d49 is allowedModules = false on Matching — 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

That last point is the load-bearing one: spot has been trading fine throughout.

The alert retires itself

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. 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:

zero OI          → exit 0, "no open interest … nothing to margin, mark alert n/a"
unreachable RPC  → exit 1, "OPEN INTEREST CHECK FAILED (cannot confirm the mark alert is safe to skip)"

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.service and numo-mark-alert-ssm.service are 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

…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>
@robertleifke
robertleifke merged commit d637796 into main Sep 22, 2026
2 checks passed
@robertleifke
robertleifke deleted the ops/retire-cngn-feed-signer branch September 22, 2026 21:56
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.

1 participant