Skip to content

Indexing fixture requirements

Fixtures should prove decoder and reducer behavior with raw logs, expected state transitions, fallback reads, and explicit block identity.

Fixture envelope

Every generated group uses this envelope:

{
  "schemaVersion": "kuru-indexer-fixture/v1",
  "abiSchema": "S1",
  "id": "spot-lifecycle",
  "addresses": {},
  "scenarios": [
    {
      "id": "spot-placement",
      "covers": ["spot.placement"],
      "initialState": {},
      "reducer": {"operations": [], "expectedFinalState": {}},
      "receipt": {"logs": [], "blockPinnedCalls": []},
      "fallbackReads": []
    }
  ]
}

Each log retains emitter, topics/data, decoded values, raw packed bytes, and record order. Each scenario retains transaction input and block identity plus deterministic pre-state, ordered projection operations, final state, fallbacks, and block-pinned calls. Addresses are explicit documentation aliases. Do not substitute them for deployment configuration.

Required scenario coverage

The fixture suite should cover the scenarios below with exact assertions and expected reducer state.

Discovery, ownership, and versions

Scenario Required assertions
Deploy Spot market Proxy initialization logs precede Engine/AccountCore/Router discovery; numeric config recovered from calldata/getters.
Deploy active Perp market Engine registration precedes proxy and AccountCore route; no Router route-replacement event.
Deploy paused Perp market MarketStateUpdated occurs before AccountCore registration and Router discovery.
Add Perp Engine AccountCore PerpEngineAdded precedes Router event.
Replace/revoke Perp book AccountCore route event precedes Router route event; old/new intervals close/open exactly.
Upgrade Router/Engine/book Proxy Upgraded is decoder boundary; Router confirmation follows target migration logs.
Concurrent ownership requests Two candidates for one contract coexist under distinct (chainId,contract,pendingOwner) keys; request expiry is 48 hours for schema S1.
Cancel ownership request Delete only the caller/candidate row; another candidate survives; canceling a missing request is an idempotent event.
Direct ownership transfer Owner changes while every pending handover survives; calldata distinguishes it from completion.
Complete ownership handover Completion at timestamp == expiresAt succeeds; only the calldata-named candidate is consumed and another candidate survives.
Change authority/roles Each child pointer and ProtocolAuthority role changes independently.

Accounts, custody, fees, and referrals

Scenario Required assertions
First deposit Auto-registration, reserve snapshot, then Deposit activity; no double credit.
Withdrawal Reserve snapshot then Withdrawal; exact free balance.
Internal transfer No snapshots; apply from/to deltas once.
Signer authorize/revoke/expiry Permission snapshot/delete, auth epoch increment, silent expiry evaluation.
Subaccount creation AccountRegistered before SubaccountCreated; root edge and epoch.
Builder approve/revoke/claim Approval replacement, accrual deltas, claim reset/activity.
Spot/Perp fee and referral tiers Root scoping, activation/expiry, independent Spot and Perp policies.
Spot protocol fee Fee-collector snapshot with no dedicated Spot fee event.
Per-book Spot reserve Active-slot reserve sum equals makerLockedReserves; aggregate AccountCore reserve remains separate.
Perp fee Maker/taker attribution, aggregate protocol accrual, collector snapshot, optional builder accrual.
Eventless controls Successful pause and fee-collector calldata plus getter reconciliation.

Spot active book

Scenario Required assertions
Place bid/ask 36-byte live records; reserve snapshots precede packed update.
Same-price replacement New order ID and FIFO tail; old delete cannot remove replacement.
Multi-slot packed replace Record order follows operation order; zero-length payload is a no-op if supported by the current Spot entrypoint.
Explicit cancel/cancel-all Non-live records and exact reserve release.
Partial/full fill Trade updatedSize; full delete has no double subtraction.
Last-trade observation Final packed price converted to X8 and containing block timestamp; no-fill action leaves it unchanged.
Stale partial/dust Spot reports trade updatedSize=0 and may append a no-op delete describing the discarded visible residual; Perp can report a nonzero trade residual followed by its real delete. Hidden stale excess is not emitted.
minSizeAfterBlock Executable size changes only at threshold+1 without a log; Spot getter discrepancy documented.
Swap active-only Account snapshots, SpotSwap, TradesPacked, BookUpdatesPacked ordering.
Self-trade behavior Revert/no logs or documented self-cancel path, depending on entrypoint.
Maker/queue priming Audit events do not change economic L2/L3.

Spot passive and hooks

Scenario Required assertions
Mint one-/two-sided band Mint event and band snapshot; shares/principal/checkpoints.
Batch mint clipped leg Zero-result leg produces no false position; accepted legs ordered.
Passive ask fill Account snapshots, band update, synthetic trade flags/slot/order ID, fee-growth quote.
Passive bid fill Conservative base conversion and base fee growth.
Mixed active/passive swap Match-order packed records and aggregate swap result.
Partial/full burn Band update precedes burn summary; position decrement/delete.
Fee-only claim Claim event with no band snapshot; checkpoint advances.
Hook set/config Hook pointer, gas limit, min notional reducers.
Hook replenish/requote Synchronous generated orders in same packed event, including same-taker consumption.
Hook failure Fail-open result: no hook state event and normal trade remains.
Example hook price push Orderbook TradesPacked/BookUpdatesPacked, then SlotSync, PriceAccepted/Requoted.

Perp normal flow

Scenario Required assertions
Cross/isolated activation Mode and slot/snapshot creation before exposure/fill.
Place/cancel/replace 40-byte records, maker fee PPS, exposure and reserve snapshots, final book events.
Partial/full fill Maker then taker PerpFillSettled; exact position/PnL/OI replay; packed records last.
Last price and cross order count Final fill updates Engine/orderbook last-price projections; cross insert/delete count matches getter.
Reduce-only fill Maker/taker flags, capacity exposure, no side-cross.
Position side flip Entry-quote rounding and long/short OI transition.
Funding update/settlement Signed accumulator, receiver floor/payer ceil, checkpoint/margin.
Implicit funding on fill Margin mutation and checkpoint without standalone funding-settled event.
Margin deposit/withdraw/move Audit delta plus snapshot, AccountCore free snapshot order.
Isolated-to-cross migration Slot, clear, both margins, migration summary; OI unchanged.
Cross-to-isolated migration Slot release, both margins, full isolated snapshot; OI unchanged.
Risk/status/price config Engine mutation before AccountCore request; getter fallback for omitted fields.
Health and thresholds Cross/isolated threshold structures and transfer requirements reconcile at one pinned state boundary.

Perp liquidation

Scenario Required assertions
Cross start, unrecovered Per-market book deletes before Engine exposure, final lock event.
Cross start, recovered recovered=true means no stored lock and no separate clear event.
Isolated start PerpIsolatedPositionUpdated sets the liquidating flag before forced BookUpdatesPacked; cancellation snapshots follow, and recovery clears the flag before PerpLiquidationStarted.
Partial reduction, still unhealthy Packed trades before Engine settlement; lock remains; AccountCore summary last.
Partial reduction, recovered Engine clear before AccountCore liquidation summary.
Permissionless clear Clear event only after health check; no fresh-price event assumption.
Cross takeover Per-market mode/slot transfer, margin transfer, namespace summary; OI unchanged.
Isolated takeover Target clear and destination full snapshot before margin/summary.
Hard-paused forced execution Expected revert/no logs for current implementation; forced cancellation remains testable.

Intents and example integration

Scenario Required assertions
Immediate replace/batch Orderbook records precede IntentExecuted; monotonic signer nonce.
Trigger create/cancel Full lifecycle and unordered nonce consumption from calldata/getter.
Trigger fire Orderbook records precede TriggerFired; report hash retained.
Trigger expiry-on-execute Only TriggerExpired; no orderbook mutation.
Failed trigger execution Entire status/order mutation reverts; no canonical logs.
Submitter/skew config Snapshot replacement.

Executable negative and replay-safety vectors

Replay-safety tests must define accepted controls and expected rejection or final state for every boundary below:

  • emitter registration selects Spot versus Perp before the shared BookUpdatesPacked topic is decoded;
  • empty or non-divisible 64/36/40-byte payloads, nonzero reserved fields, unsupported flags, and active maker slots >= 62 are rejected;
  • trade IDs are strictly increasing per book history;
  • a stale delete cannot remove a newer order ID and duplicate raw identities apply once;
  • a schema outside its exact implementation interval and an undiscovered emitter are rejected;
  • Spot and Perp dust apply their distinct trade/book-update sequences without double deletion;
  • the saved Perp placementMode, rather than the later Engine mode, controls cross-order-count deletion;
  • isolated-to-cross migration and cross takeover preserve every position-content field; and
  • an orphaned block's packed mutation, implementation upgrade, and getter evidence roll back in one journal before a same-height replacement branch is applied.

Validator requirements

The fixture validator must verify:

  1. ABI schema identity is consistent across every fixture in a run;
  2. every raw log matches its selected ABI and re-encodes to the declared topics/data;
  3. every transaction/getter signature and return shape matches its target reference ABI and its calldata/output re-encodes with the same ABI rules used by the indexer;
  4. packed widths, round-trip decoding, allowed flags, and user-slot range;
  5. ordered reducer operations produce the declared final state, including price/health arithmetic reconciliation for getter-only boundaries, including nested quote, margin, PnL, funding, cross-sum, and transfer-floor outputs;
  6. every required flow/projection has at least one scenario and selected critical event-order relationships hold; and
  7. eventless/log-incomplete examples declare calldata or block-pinned getter evidence.

Replay validation must additionally cover rejection, idempotence, inverse journals, getter invalidation, placement mode, product-specific dust, and position transfers.