Repository navigation
feat(keepers): v2 expiry keeper, engine keeper instance, pager checks (#258) - #281
Merged
Merged
Conversation
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.
Part of #258: the rest of the v2 keepers after the forward publisher.
Based on #279 (
feat/v2-forward-publisher). It contains that PR's commit, so merge #279 first. Only the second commit (cfe8824) is new here.What changed
Expiry keeper v2 (
services/perp-feeds/src/expiry-keeper.ts, run byforward-mainwithFUTURE_VERSION=v2):coverPoolDeficiton v2 treats the pool as cash only. Net = the pool account's cash (the engine'saccId/cashAsset). A loser pays whatgetPendingVMsays it owes, in USDC. Losers are settled largest first while the cash is below -$1, at mostSETTLE_PER_TICKa tick. A deficit with no loser left alertsfuture-pool-deficit-strandedonce per episode, naming the base.BASE_ASSET_TYPE/assetMap/spot feed read. Every v2 series on an engine shares pool CI: cover infra/ and alert when main goes red #37, so each series' keeper sees the same cash and settles its own losers.forward-mainnow runs the pool cover and expiry keeper in v2 mode too (feat(perp-feeds): v2 forward publisher mode, per series (#258) #279 had skipped them).Engine keeper, second instance (
services/perp-keeper):PERPis optional. With none, nothing perp is read: cap, inherited perp,--settle-frozenrefuses.CNGN_SPOT_FEEDprices cNGN from the engine's spot feed instead of the perp index.FUTUREtakes a comma-separated list, one per series. Each cap is watched on its own (future-oi-cap-<address>)./healthaddsperp,futures,cngnSpotFeed.FUTURE,PERP, noCNGN_SPOT_FEED) reads as before.contracts/risk-core/scripts/ops/engine-keeper-v2.env+numo-engine-keeper-v2.service(not installed). Values: MANAGER v2, POOL_ACCOUNT 37, FUTURE cNGN-30NOV26, START_BLOCK 53164124, port 9466, own SSM key/numo/keeper/engine_v2_keeper_key, DRY_RUN=true.KEEPER_ACCOUNTis left blank: the account doesn't exist yet.Pager (
check_perp_pager.py):FUTURE_V2_ARTIFACTS(comma-separated, defaultdeployments/8453/MARGIN_ENGINE_V2.json; a missing artifact is skipped). Per series: one side's notional = contracts × contractSize × mark, plus margin rates and open/closed.future-pool-borrowing-v2andfuture-pool-deficit-stuck-v2use the same $1 / $250 / 75 min thresholds as v1, and each engine has its own deficit timer.sm-coveragenow sums what every future needs from the one SecurityModule: v1's fitted rule plussm_required_usd_linearper v2 series.ENGINE_V2_KEEPER_HEALTH_URLaddskeeper-unhealthy-v2/insolvent-account-v2(perp-pager.envhas it commented out).futureManagers(v1 and v2) forpropose_margin_engine_v2_batch.py's pager gate.Anvil/fork suites:
services/perp-feeds/src/expiry-v2.anvil.e2e.test.ts: a real fixing on the v2FutureAsset, for a cNGN and an EURC series.services/perp-keeper/src/engine-keeper-v2.anvil.test.ts: the live v2 engine on a Base fork, configured from the v2 env. The vault opens the cap, one contract trades, margin is raised, and the keeper starts the auction and bids from a v2 account.scripts/e2e-engine.shruns both engine suites.How tested
pnpm run checkclean.ANVIL_RPC_URL=http://127.0.0.1:8599 pnpm test: 159 tests, 159 pass, 0 fail. That includes the v1 and v2 forward/expiry anvil suites and the new v2 cash-pool unit tests, one of which uses an EURC series.pnpm run checkclean.pnpm test: 47 tests, 47 pass. These cover the v2 config (no PERP, CNGN_SPOT_FEED, FUTURE list with a placeholder EURC future) andreadHealthwith no perp.BASE_RPC_URL=… ./scripts/e2e-engine.sh(fork at head): 4/4 pass, v1 engine and v2 engine. On v2 the keeper started an auction on the account under maintenance and bid 29.88% from a v2 bid account.BASE_RPC_URL=… ./scripts/e2e.sh(perp stack deploy on a fork): 5/5 pass.check_perp_pager.py --self-test: ok.abi_selectors.py --self-test: ok (30 scripts, full forge build of risk-core and execution). Thepropose_margin_engine_v2_batch,propose_margin_engine_batchandpropose_perp_enable_batchself-tests: ok.futureManagers= [v1, v2].ExpiryKeeperv2 on a Base fork withfuture-feeds-v2-cngn-30nov26.env:coverPoolDeficit→ net 0, nothing settled;tick→ before-window.What's left / decisions
KEEPER_ACCOUNT), its EOA and SSM key, and its cash. The v2 batch's keeper gate wants about a full side's IM at the cap (~$2,790 at 0.000743).MAX_CNGN_INVENTORY(8,000,000) andMAX_EURC_INVENTORY(40,000) inengine-keeper-v2.envare copied from v1's. Revisit them, EURC's especially at theeurc-capstep.exchange-future-v2checkout, both v2 units in DRY_RUN first, andENGINE_V2_KEEPER_HEALTH_URLin/etc/numo/perp-pager.env. The pager readsMARGIN_ENGINE_V2.jsonby default as soon as its checkout includes this, which is what the v2 pager gate needs. Record each inOPS_BOX_CHANGES.md.baseSymbol: "EURC") added toFUTURE_V2_ARTIFACTS, its future added to the v2 engine keeper'sFUTURE, and afuture-feeds-v2-eurc-30nov26.envinstance. No code changes.sm-coveragesums the series' needs: conservative, since cNGN and EUR moves are not one step.