Skip to content

ops(risk-core): regenerate the cNGN spot vault batch against live supply - #27

Merged
robertleifke merged 2 commits into
mainfrom
ops/regenerate-cngn-spot-batch
Sep 9, 2026
Merged

ops(risk-core): regenerate the cNGN spot vault batch against live supply#27
robertleifke merged 2 commits into
mainfrom
ops/regenerate-cngn-spot-batch

Conversation

@robertleifke

Copy link
Copy Markdown
Contributor

The committed vault batch could not be signed — verify-cngn-spot-batch failed at action 9:

Error: artifact calldata differs from live-derived batch

Why

setTotalPositionCap is derived as 10% of live cNGN totalSupply() at generation time, not a constant. Supply moved between generation and now:

Supply 2026-09-05 ~2,048,537,784 cNGN
Supply 2026-09-08 2,989,279,206.73 cNGN
Committed cap 204,853,778.40 (6.85% of float)
Regenerated cap 298,927,920.67 (10%)

Exactly the drift the migration doc warns about: "cNGN supply moves, and a stale denominator is how a cap ends up being most of the float."

The blocker behind the blocker

Regeneration itself failed with BLF_DataTooOld(). The drift precondition reads the live cNGN feed to confirm the static price is within 5% of the inverted live rate — and both that feed (0x41512C…, 180s heartbeat) and the SRM stable feed (0xDAe566…) were reverting.

Root cause, found on-chain: the feed relayer 0xC9F1FfdEd29f7051538ad3a72729C3d07F920FDc ran out of gas on 2026-09-01 22:19:51 UTC at nonce 61,549, with 0.000002 ETH remaining. The publisher host was healthy the whole time; it simply couldn't pay. Funding it restarted publication within one heartbeat, and the feeds now read 1321.225569 and 1.0.

This was not only a migration blocker. DeliverableFXManager divides by that spot price on every adjustment, so no trade could settle for 6.8 days — and nothing surfaced it.

Verification

preconditions ok against live chain state
[0]..[10] ok
artifact matches live-derived batch
batch hash: 0x911288c57e4ea05fe01f257f928bd80b5e00fa4cd3bd9ff4129b96a43bb1b67f

forge test --match-path 'test/scripts/*' — 13 passed. GOLDEN_BATCH_HASH pins the action list, not the live-derived cap, so it needed no update.

Next

Signing is a vault action, not a code change: 11 separate transactions on an EOA vault, approved in order, non-atomic. After execution, subaccounts must be recreated under the SRM — SubAccounts has no changeManager, so DFXM accounts can never migrate. Escrow is currently empty, so there is nothing to move.

Operational follow-up worth its own issue: both the feed relayer and the executor are one unattended week from halting the venue, and the failure is silent. A balance alert on each would have caught this on 2026-09-01.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JN98Sjs2zHG8Z6jXkpHX7Q

robertleifke and others added 2 commits September 8, 2026 13:35
The committed artifact no longer matched the chain. verify-cngn-spot-batch
failed at action 9 with "artifact calldata differs from live-derived batch":
setTotalPositionCap is derived as 10% of live cNGN totalSupply at generation
time, and supply moved from ~2.049bn to ~2.989bn between 2026-09-05 and
2026-09-08. The committed cap of 204,853,778 cNGN had drifted from the
intended 10% to 6.85% of float.

New cap: 298,927,920.672506300000000000 cNGN.
Batch hash: 0x911288c57e4ea05fe01f257f928bd80b5e00fa4cd3bd9ff4129b96a43bb1b67f

Regeneration was itself blocked until today. The script reverted
BLF_DataTooOld() because the drift precondition reads the live cNGN feed to
check the static price is within 5% of the inverted live rate -- and both
that feed and the SRM stable feed had been stale since 2026-09-01 22:19 UTC,
when the feed relayer 0xC9F1FfdE ran out of gas at nonce 61549 with 0.000002
ETH left. Funding it restarted publication within one heartbeat.

That staleness was not only a migration blocker: DeliverableFXManager divides
by the spot price on every adjustment, so no trade could settle for 6.8 days.
Silent -- nothing surfaced it.

All 11 actions now verify against live chain state and the shape test still
passes: GOLDEN_BATCH_HASH pins the action list, not the live-derived cap.

Next step is signing, which is a vault action, not a code change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JN98Sjs2zHG8Z6jXkpHX7Q
EXPECTED_BATCH_HASH still pinned 0x7b7013f5, the hash from when the proposer
was written against an artifact whose cap was 10% of a smaller cNGN supply.
Regenerating the batch changed the hash to 0x911288c5, so --propose refused:

  batch hash changed; expected 0x7b7013f5...
  Something about the world moved. Re-read the diff before proposing anything.

Which is the pin doing its job. It is a second, independent gate after the
verifier: the verifier confirms the artifact matches live chain state, and
this asserts the batch is still the one a human already reviewed. Both have
to be satisfied, and regenerating deliberately breaks the second one.

The diff is the cap and nothing else -- 204,853,778 -> 298,927,920.672506300
cNGN, restoring the intended 10% of a supply that grew from ~2.049bn to
~2.989bn. Supply is unchanged since the regeneration, verified before
repinning, so nothing else moved underneath it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JN98Sjs2zHG8Z6jXkpHX7Q
@robertleifke
robertleifke merged commit 8e5eeb1 into main Sep 9, 2026
1 of 2 checks passed
@robertleifke
robertleifke deleted the ops/regenerate-cngn-spot-batch branch September 9, 2026 01:43
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