npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@steerprotocol/clamm-vm

v0.1.0

Published

Deterministic Uniswap v3 pool simulation for TypeScript.

Downloads

82

Readme

clamm-vm

In-memory Uniswap v3 pool simulation for TypeScript.

Package entry points

// Deterministic pool, token, tick, position, and swap simulation.
import { FeeAmount, Pool, createToken } from "@steerprotocol/clamm-vm";

// Synthetic backtests, actors, reports, market data, and visualizations.
import { createSyntheticBacktest, createStrategyActor } from "@steerprotocol/clamm-vm/simulation";

// Panoptic accounting, risk, and protocol simulation.
import { PanopticPoolVM } from "@steerprotocol/clamm-vm/panoptic";

The Pool object starts empty at a configured price. Users add and remove liquidity through pool methods, then swaps mutate price, current tick, active liquidity, tick fee-growth state, and LP fee accounting.

import { FeeAmount, Pool, createToken } from "@steerprotocol/clamm-vm";

const usdc = createToken(1, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 6, "USDC");
const weth = createToken(1, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH");

const pool = Pool.fromTick({
  tokenA: usdc,
  tokenB: weth,
  fee: FeeAmount.MEDIUM,
  tickCurrent: 0
});

const added = pool.addLiquidity({
  owner: "alice",
  tickLower: -600,
  tickUpper: 600,
  liquidity: 1_000_000n
});

const trade = await pool.swapExactIn({ tokenIn: pool.token0, amountIn: 1_000n });
const fees = pool.poke({ owner: "alice", tickLower: -600, tickUpper: 600 });
const collected = pool.collect({ owner: "alice", tickLower: -600, tickUpper: 600 });

console.log({
  required0: added.amount0.toString(),
  required1: added.amount1.toString(),
  amountOut: trade.amountOut.toString(),
  fees0: fees.tokensOwed0.toString(),
  collected0: collected.amount0.toString()
});

Scope

This package targets Uniswap v3-style deterministic pool behavior:

  • swap price/tick traversal
  • active liquidity changes while crossing ticks
  • LP fee growth globals
  • tick fee-growth-outside accounting
  • per-position fee snapshots and owed token accounting
  • burn and collect flows

It does not model block-time oracle observations, TWAP accumulators, seconds-per-liquidity, callbacks, token balances, or Uniswap v4 hooks/singleton behavior.

Synthetic Market GIFs

For longer synthetic runs, use the horizon builder. You describe calendar time, block time, liquidity health, activity, and candle interval; the simulator handles block timestamps, stacked intra-block trades, block summaries, candles, and GIF rendering. The liquidity-health model in the horizon builder creates a seeded ecology of persistent LP actors; health biases their persona mix, capital, range widths, placement drift, stale behavior, and rebalancing cadence instead of selecting one fixed liquidity chart shape.

import { createSyntheticBacktest, renderMarketGif } from "@steerprotocol/clamm-vm/simulation";

const backtest = createSyntheticBacktest({
  pool,
  seed: "two-month-demo",
  horizon: {
    start: "2026-01-01T00:00:00Z",
    duration: "60d",
    blockTime: "12s"
  },
  liquidity: {
    model: "liquidity-health",
    owner: "market-lps",
    health: 7,
    totalLiquidity: "7800000"
  },
  activity: {
    profile: "normal",
    avgTradesPerDay: 1200,
    avgVolumeToken1PerDay: "5000000"
  },
  candles: { interval: "1d" }
});

const result = await backtest.run();
const gif = renderMarketGif({
  blocks: result.blocks,
  candles: result.candles,
  priceView: "candles",
  width: 900,
  height: 540
});

Synthetic backtests can also run first-class single-pool strategies. Strategies return balance-enforced intents, so invalid swaps or LP changes are rejected by the strategy actor before they become market events. Reports use token1 as the default quote currency for NAV, PnL, drawdown, HODL comparison, and estimated IL.

import { analyzeBacktest, createStrategyActor, createSyntheticBacktest } from "@steerprotocol/clamm-vm/simulation";

const strategy = createStrategyActor({
  id: "range-lp",
  initialBalances: { token0: "5000000", token1: "5000000" },
  strategy: {
    initialize(ctx) {
      return [{
        type: "addLiquidity",
        tickLower: ctx.pool.tickCurrent - 600,
        tickUpper: ctx.pool.tickCurrent + 600,
        liquidity: "2500000"
      }];
    },
    onBlock() {
      return [];
    }
  }
});

const result = await createSyntheticBacktest({
  pool,
  seed: "strategy-demo",
  horizon: { start: "2026-01-01T00:00:00Z", duration: "14d", blockTime: "1m" },
  regimes: { initialRegime: "normal" },
  liquidity: { model: "liquidity-health", owner: "market-lps", health: 7, totalLiquidity: "7800000" },
  activity: { profile: "normal" },
  actors: [strategy],
  candles: { interval: "4h" },
  outputs: { recordActorSnapshots: true }
}).run();

const report = analyzeBacktest(result);

For repeatable Panoptic strategy runs, use the strategy runner. Strategy modules live in strategies/; the runner owns explicit market-source selection, market setup, report writing, and GIF rendering. Synthetic runs retain the existing liquidity ecology. Portable profiles calibrate that ecology without adding a per-run network dependency; optional one-block snapshots seed exact aggregate Pool depth. Historical runs replace the ecology, price process, flow, and fixed clock with one verified local tape or retained benchmark.

See Market Data And Strategy Operations for the complete import, observation, profile, snapshot, benchmark, generation, stress, strategy, cost-governance, comparison, and review workflow.

When no tape or calibration is selected, the runner keeps the existing synthetic actor ecology for compatibility and labels it exploratory. Its execution mechanics are configured independently: --synthetic-arbitrage selects bounded-actor, price-target, or disabled, while --organic-external-gap-bias-multiplier, --organic-external-return-bias-multiplier, and --organic-max-side-bias control synthetic flow response. These settings are recorded as marketExecution; they do not imply empirical marketFidelity.

npm run strategy -- list

Run the two included Panoptic strategy modules:

# Full gamma-scalp run with reports and panoptic.gif
npm run strategy -- panoptic-gamma-scalp

# Short-call smoke run with reports and panoptic.gif
npm run strategy -- panoptic-short-call --duration 1d --block-time 4h

Run any strategy module against an immutable local tape without RPC or subgraph access during execution:

npm run strategy -- path/to/strategy.mjs \
  --market-tape market-data/ethereum-usdc-weth-500/20000000-20010000

Create one deterministic native contiguous window from a larger tape and its source calibration:

npm run market-data:bootstrap -- \
  --tape market-data/pool/training \
  --calibration market-data/calibrations/pool-v1 \
  --output market-data/bootstrap/pool-window-1 \
  --seed pool-window-1 \
  --blocks 50400

The sampled tape derives its complete parent Pool state and custody by exact prefix replay. It preserves source block numbers, hashes, timestamps, prices, ticks, liquidity, action order, and baseline event volume. The schema records one source window and an empty splice-boundary list; multi-window splicing is rejected rather than silently rebasing state.

Generate a hypothetical market from an empirically ready calibration. The target price and liquidity are explicit; fee tier and token identities inherit the source pool unless --pool supplies another pool identity:

npm run market-data:generate -- \
  --calibration market-data/calibrations/pool-v1 \
  --output market-data/generated/pool-seed-1 \
  --seed pool-seed-1 \
  --blocks 50400 \
  --segment-length 256 \
  --initial-price 0.0005 \
  --liquidity 1000000000000000000 \
  --parent-block 20010000 \
  --parent-hash 0x0000000000000000000000000000000000000000000000000000000000000000 \
  --parent-timestamp 2026-01-01T00:00:00.000Z

The command writes an ordinary immutable tape plus market-frames.jsonl, one arbitrage decision per frame, envelope rows, and generation fidelity reports. The Pool still moves only through normal swaps and LP actions. A shared input envelope prevents organic and arbitrage-like flow from independently creating baseline volume.

Apply an ordered correlated stress composition to the same calibrated frame source before Pool execution:

npm run market-data:stress -- \
  --calibration market-data/calibrations/pool-v1 \
  --stress-config examples/market-stress/liquidity-crunch.json \
  --output market-data/stressed/liquidity-crunch-seed-1 \
  --seed pool-seed-1 \
  --blocks 50400 \
  --segment-length 256 \
  --initial-price 0.0005 \
  --liquidity 1000000000000000000 \
  --parent-block 20010000 \
  --parent-hash 0x0000000000000000000000000000000000000000000000000000000000000000 \
  --parent-timestamp 2026-01-01T00:00:00.000Z

The JSON file is required. It owns caller-labeled severity and an ordered list of inclusive frame windows. Supported operators are return-shock, volume-response, directional-imbalance, liquidity-withdrawal, lp-latency, and arbitrage-capacity. The complete transformed frame stream is preflighted before a Pool is created. Invalid volume, liquidity, delayed LP actions beyond the horizon, or arbitrage capacity beyond the shared envelope fail before execution. The command writes an immutable scripted-stress tape, exact envelope rows, and a distinct stress-fidelity report. It never assigns Pool price, tick, fee growth, or live liquidity directly.

Run a strategy directly from calibration by supplying the same generation inputs. The generated tape is materialized under the result folder and the strategy then uses the existing tape runner:

npm run strategy -- path/to/strategy.mjs \
  --market-calibration market-data/calibrations/pool-v1 \
  --market-generation-blocks 50400 \
  --market-generation-segment-length 256 \
  --market-generation-initial-price 0.0005 \
  --market-generation-liquidity 1000000000000000000 \
  --market-generation-seed strategy-market-1 \
  --output-mode metrics

Add one stress composition to that strategy run with --market-stress:

npm run strategy -- path/to/strategy.mjs \
  --market-calibration market-data/calibrations/pool-v1 \
  --market-generation-blocks 50400 \
  --market-generation-segment-length 256 \
  --market-generation-initial-price 0.0005 \
  --market-generation-liquidity 1000000000000000000 \
  --market-generation-seed strategy-market-1 \
  --market-stress examples/market-stress/liquidity-crunch.json \
  --output-mode metrics

Arbitrage capacity defaults to zero. Enabling it requires explicit finite raw token capital and supports explicit operational cost, reference latency, and cooldown inputs. Generated execution fidelity has no hidden tolerance defaults: all five --market-generation-fidelity-* limits must be supplied together before the market can be labeled decision-grade. Without them, transformation, source-sample, envelope, and exact-replay evidence still runs, while execution fidelity remains unassessed.

The CLI market reference overrides an optional strategy default. Strategy defaults resolve relative to the strategy module:

export default {
  market: {
    tape: "../market-data/pool/training",
    window: {
      calibration: "../market-data/calibrations/pool-v1",
      blocks: 50400,
      seed: "default-window"
    }
  },
  create(context) {
    // context includes tokens, initialPoolSnapshot, poolIdentity, and marketSource.
  }
};

A tape owns its block range, variable timestamps, initial Pool state and custody, liquidity, baseline flow, and price path. Synthetic-only clock, liquidity, volatility, activity, and arbitrage flags are rejected rather than silently ignored. Counterfactual limits remain caller supplied through --max-strategy-volume-bps, --max-strategy-active-liquidity-bps, --max-panoptic-active-liquidity-bps, --max-panoptic-maker-depth-bps, and --max-pool-tick-divergence. --market-calibration requires a complete market.generation config or matching --market-generation-* inputs; a bare calibration remains descriptive and fails explicitly. --market-window-calibration instead pairs a calibration with its exact source tape for native contiguous-window sampling.

Strategy modules can return a liquidity object to choose their own liquidity ecology profile. CLI flags such as --liquidity-health and --total-liquidity override that profile for one-off runs.

The gamma-scalp actor hedges the strategy portfolio's decision-grade, closeout-equivalent token0 exposure relative to its passive initial holdings. That exposure includes live wallet cash, Panoptic collateral, and the VM's rollback-safe immediate-close token vector. Normal hedges use a configurable tracking band and trade-size cap; after burning the option, the actor continues until the stricter terminal exposure tolerance is satisfied. It does not use an approximate Black-Scholes or sigmoid delta model.

Strategy swaps and Panoptic deposits use the same explicit finite wallets. A strategy module declares wallets and collateral deposits independently of its liquidity ecology:

return {
  funding: {
    wallets: {
      "my-strategy-actor": { token0: "50000000", token1: "51000000" },
      "market-maker": { token0: "100000000", token1: "100000000" }
    },
    panopticCollateral: [
      { wallet: "my-strategy-actor", account: "alice", token0: "50000000", token1: "50000000" },
      { wallet: "market-maker", account: "market-maker", token0: "100000000", token1: "100000000" }
    ]
  }
};

The runner separately funds liquidity ecology, organic flow, and arbitrage from recorded assumptions. Deposits debit the declared wallet into one collateral tracker per underlying token. Direct Uniswap actions and Panoptic settlement use the same capital ledger, so insufficient actions roll back and physical custody reconciles across wallets, collateral, and the shared Pool. The real PanopticCollateralSettlement uses live solvency, the Panoptic-owned oracle maintains historical risk ticks, and collateral interest accrues from the shared block clock. Dispatches update the oracle through their normal VM path; an optional --panoptic-oracle-keeper-steps actor can call pokeOracle explicitly. The simulation never mutates Panoptic observations automatically once per block.

Live blocks use an explicit default transaction order: market observation, liquidity maintenance, organic flow, pre-strategy arbitrage, strategy actions, then optional post-strategy arbitrage. A strategy module can return actorExecution and transactionPhaseOrder to place its actors or reorder those phases explicitly. Genesis actions use the preceding source block number, and the resolved clock plus transaction order are written to manifest.json. Within a phase, explicit priority wins and actor id is the stable tie-breaker; actor array position does not change execution order.

Each run writes a timestamped folder under backtest-results/<strategy-id>/ with:

  • manifest.json
  • run-receipt.json
  • validation.json
  • summary.json
  • final-panoptic-report.json
  • final-strategy-portfolio.json
  • capital.json
  • panoptic-market-depth.json
  • market-source.json
  • market-fidelity.json
  • research-summary.json
  • market-diagnostics.json
  • market-actions.jsonl
  • market-metrics.csv
  • portfolio-metrics.csv
  • hedge-trades.csv
  • candles.csv
  • sources/*.jsonl
  • panoptic.gif

Historical runs additionally write market-replay.json with exact source action/checkpoint reconciliation, baseline-volume conservation, endogenous participation, Pool divergence, and counterfactual-limit status. Generated runs also write generated-market-fidelity.json; their generated tape and source-owned generation reports live under generated-market/ for a single run or generated-markets/ for a matrix run. Stressed runs instead write stressed-market-fidelity.json; their tape and source-owned stress reports live under stressed-market/ for one run or stressed-markets/ for a matrix. Generated and stress readiness classes are not combined.

Debug mode additionally writes the retained event, block, candle, analysis, and full report files. Debug, sampled, and metrics modes use the same source-owned economic calculations, compact rows, source ledgers, final reports, validation, and GIF renderer. They differ only in retained event, block, actor, and debug report density. market-actions.jsonl is the compact outcome stream for every market action; successful Panoptic rows carry their receipt actionSequence and actionId.

The sources/ directory persists action receipts, contract events, accounting, premium, complete tracker-owned collateral event logs, collateral/risk/account/ closeout reports, strategy reports, and the liquidation source report. The validator checks source sequences and joins, capital and collateral custody, closeout and strategy NAV arithmetic, final compact-row consistency, and decision-grade readiness. A structurally valid run with unavailable sources is labeled non-decision-grade instead of silently publishing NAV.

manifest.json records the implementation and Panoptic reference commits, working-tree content hash including non-ignored untracked files, installed Uniswap package versions, capabilities, seeds, tokens, initial Pool state, liquidity, capital, clock, transaction order, execution assumptions, and resolved strategy parameters. It labels the configured GBM input as external volatility and records market-fidelity readiness independently from accounting readiness. run-receipt.json records timing, event/action/source row counts, failures, economics, artifact paths, and validation status.

capital.json contains initial and final wallets, Uniswap and Panoptic custody, attributed settlement rows, capacity rejections, and an exact token-conservation check. Historical baseline actions settle through an explicit signed external source boundary: Pool custody changes by the executed VM result without fabricating finite wallets for unknown historical participants. Strategy wallets and Panoptic collateral remain finite. panoptic-market-depth.json keeps external AMM liquidity, SFPM option liquidity, collateral depth/utilization, and remaining actor capital separate. research-summary.json records result-validation status, closeout NAV, exact economic PnL, the passive-hold benchmark bridge, turnover, drawdown, exposure, execution costs, and actor-level failure counts. Economic fields fail closed unless both canonical portfolio readiness and result validation are decision-grade. Drawdown and exposure use the complete compact per-block portfolio series in every output mode, independent of retained debug snapshots.

market-diagnostics.json is computed from the complete source-owned block stream. It reports configured external volatility separately from measured external and Pool realized volatility, volatility transmission, return beta/correlation, tracking error, Pool/reference gap percentiles, active-liquidity percentiles, base-versus-Panoptic active-liquidity ownership, and swap volume split across organic, arbitrage-like, strategy, other, and total flow. Synthetic runs remain explicitly labeled exploratory. Historical runs report exact replay or counterfactual readiness for the selected window independently from accounting readiness; exact replay does not claim that one window is broadly representative. Contiguous-bootstrap runs add market-bootstrap-fidelity.json. They are decision-grade for market fidelity only when the sampled window passes the source calibration's explicit criteria; missing criteria and insufficient samples remain unassessed or sample-limited. A single sampled window always retains representative: false. Producing a calibration artifact alone does not change the source used by a run.

Market terminology is deliberately attribution-based. For synthetic runs, baseline is organic plus arbitrage-like flow before strategy additions. For historical runs, baseline is ordered source-tape flow; unknown source traders are not classified as organic or arbitrage. organic means swaps executed in the organic-flow phase. arbitrage-like means swaps executed in a pre- or post-strategy arbitrage phase; it is a phase attribution, not a claim about an unknown trader's economics. strategy means swaps executed in the strategy phase, while hedge is the intent-labeled subset of strategy flow. Panoptic-owned active liquidity means active Pool positions using the canonical SFPM owner prefix; every other active position remains base-market liquidity.

Canonical historical market tapes support legacy uniswap-v3-market-tape/v1 artifacts and current uniswap-v3-market-tape/v2 imports. V2 uses a required hashed uniswap-v3-initial-pool-state/v4 parent snapshot, canonical blocks.jsonl, and optional checkpoints.jsonl. openMarketTape() parses the manifest first, streams every referenced file to verify schema, block ancestry, row counts, byte lengths, and SHA-256 hashes, and only then returns bounded-memory block/checkpoint iterators. The verified artifact is deep-frozen. writeMarketTape() validates while streaming and writes the manifest last, so a partial write cannot look ready. Local root-level market-data/ artifacts are ignored; small frozen fixtures live under test/fixtures/market-tapes/.

Build a local tape from a UTC range with subgraph-indexed events and an exact archive-RPC parent snapshot:

ETH_RPC_URL=https://... \
UNISWAP_V3_SUBGRAPH_URL=https://... npm run market-data:import -- \
  --chain-id 1 \
  --pool 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640 \
  --start-time 2026-07-01T00:00:00.000Z \
  --end-time 2026-07-08T00:00:00.000Z \
  --subgraph-url-env UNISWAP_V3_SUBGRAPH_URL \
  --market-id ethereum-usdc-weth-500 \
  --output market-data/ethereum-usdc-weth-500/2026-07-01_2026-07-08 \
  --checkpoint-cadence-blocks 300

RPC credentials remain build-time inputs and are not persisted. The importer pins finality and block hashes, reads the parent-block tick bitmap and exact tick depth directly, hydrates only position keys referenced during the selected forward window, proves executable swap flow from source outcomes, verifies pages again before atomic publication, and emits source-owned checkpoints. It does not scan Mint history from Pool creation or instantiate historical LP participants. Contract reads use bounded Multicall3 chunks with individual fallback, while swap transaction calldata is fetched only when outcome reconciliation needs it. Checkpoint cadence and block hashes are enforced at both write and open boundaries. Normal strategy execution then uses only the local artifact.

The committed test/fixtures/market-tapes/uniswap-v3-usdc-weth-first-swap/ fixture restores the mainnet USDC/WETH 0.05% Pool at block 12376890 and reproduces the first swap at block 12376891 exactly in raw integer amounts, sqrt ratio, tick, liquidity, and checkpoint state.

Historical execution uses MarketTapeBaselineActor plus its injected MarketTapeReplayCursor. The cursor drives the simulation with source block numbers, hashes, timestamps, and elapsed time; Uniswap and Panoptic therefore observe the same historical clock. Source actions run in strict transaction/log order in the dedicated baseline-market phase. Strategy actions run afterward in the explicit strategy phase and remain endogenous counterfactual flow.

MarketTapeBaselineActor.report() returns exact action/checkpoint reconciliation, baseline-volume conservation, source mismatch rows, strategy volume, direct LP and Panoptic active-liquidity participation, and Pool divergence. Counterfactual readiness requires caller-supplied limits; the VM does not choose market-impact limits on the strategy's behalf. Persist the report beside other outputs with FileBacktestOutputSink.writeMarketTapeReplayReport().

Build a deterministic calibration from any verified tape that passes exact historical replay:

npm run market-data:calibrate -- \
  --tape market-data/ethereum-usdc-weth-500/20000000-20010000 \
  --output market-data/calibrations/ethereum-usdc-weth-500-training

The command writes canonical calibration.json and block-bundles.jsonl files atomically. The artifact preserves source and pool identity, the parent close used for the first return, raw-unit marginals, signed flow, portable liquidity ratios, intraday rows, lag relationships, reference-gap response, sample readiness, derivation kinds, and file hashes. openMarketCalibration() streams and verifies both files and reconciles their source range, counts, volumes, liquidity, returns, realized volatility, and readiness.

An artifact is not empirically-ready without explicit acceptance criteria and a held-out tape for the same pool. A criteria file has this exact shape:

{
  "minimumTrainingBlocks": 1000,
  "minimumTrainingSwaps": 500,
  "minimumTrainingMints": 10,
  "minimumTrainingBurns": 10,
  "minimumHeldOutBlocks": 500,
  "minimumHeldOutSwaps": 250,
  "minimumHeldOutMints": 5,
  "minimumHeldOutBurns": 5,
  "maximumDistributionMeanDifferenceBps": 1000,
  "maximumDistributionP90DifferenceBps": 1500,
  "maximumCorrelationAbsoluteDifference": 0.25
}
npm run market-data:calibrate -- \
  --tape market-data/pool/training \
  --held-out-tape market-data/pool/held-out \
  --criteria market-data/pool/criteria.json \
  --output market-data/calibrations/pool-v1

Independent local reference prices are optional and are never inferred from swap direction. Their file bytes are hashed into the artifact:

{
  "sourceId": "independent-price-source",
  "prices": [
    { "blockNumber": 20000000, "price1Per0": 0.00042 }
  ]
}

Pass that file with --reference-prices; use --held-out-reference-prices for the held-out window. Missing criteria leaves the artifact source-complete, insufficient block/swap/mint/burn samples make it sample-limited, and only a complete held-out diagnostic pass makes it empirically-ready. Unsupported optional relationships remain labeled rather than synthesized.

Imported execution reserves baseline ownership: synthetic liquidity, organic flow, and pre/post-strategy arbitrage phases cannot be enabled implicitly. File outputs classify imported swaps as baseline, not as organic or arbitrage-like, because chain logs do not prove trader intent.

Swap logs and swap intent are intentionally separate. A Pool Swap event proves token deltas and post-swap state, but not exact-input versus exact-output caller intent. The tape only lowers a swap into a VM action when a source such as decoded transaction calldata supplies that intent; otherwise it emits a partial row with SwapIntentUnavailableFromPoolEvent instead of guessing.

The current decoder proves direct Pool calls and canonical Ethereum v3 SwapRouter single-pool calls. It also proves an exactInput multi-hop call when the imported Pool is the first hop. Unknown routers, multicalls, and later route hops remain partial. Nonzero protocol fees, unsupported Pool events, incomplete parent state, and ranges that begin before an initialized parent state fail closed instead of being approximated.

Use a matrix run to vary independent seeds, liquidity health, execution latency, strategy position size, and configured external-price-process volatility. Every matrix cell writes its own reports and GIF, while the parent folder receives exact raw-unit JSON and CSV summaries:

npm run strategy -- panoptic-gamma-scalp --seed-list seed-a,seed-b --liquidity-health-list 3,8 --strategy-latency-steps-list 0,1

Keep market entropy separate from strategy behavior by crossing market-source and strategy seeds explicitly. For historical bootstrap sources:

npm run strategy -- path/to/strategy.mjs \
  --market-tape market-data/pool/training \
  --market-window-calibration market-data/calibrations/pool-v1 \
  --market-window-blocks 50400 \
  --market-window-seed-list market-a,market-b,market-c \
  --seed-list strategy-a,strategy-b \
  --output-mode metrics

Each sampled tape is materialized once and reused across its strategy seeds. The parent JSON/CSV identifies the source tape, calibration, selected offset, and block range. It also reports duplicate-window concentration and pairwise source-block overlap; overlapping windows are labeled rather than counted as independent samples.

The same market-source seed dimension drives independent calibrated generated markets. The market-window-* spelling is retained for matrix compatibility, but generated outputs and summary dimensions are labeled generated-market:

npm run strategy -- path/to/strategy.mjs \
  --market-calibration market-data/calibrations/pool-v1 \
  --market-generation-blocks 50400 \
  --market-generation-segment-length 256 \
  --market-generation-initial-price 0.0005 \
  --market-generation-liquidity 1000000000000000000 \
  --market-window-seed-list generated-a,generated-b,generated-c \
  --seed-list strategy-a,strategy-b \
  --output-mode metrics

Cross explicit stress compositions as a separate matrix dimension. Every path is loaded and validated before execution; there is no implicit baseline or default stress cell:

npm run strategy -- path/to/strategy.mjs \
  --market-calibration market-data/calibrations/pool-v1 \
  --market-generation-blocks 50400 \
  --market-generation-segment-length 256 \
  --market-generation-initial-price 0.0005 \
  --market-generation-liquidity 1000000000000000000 \
  --market-stress-list examples/market-stress/liquidity-crunch.json,path/to/arb-outage.json \
  --market-window-seed-list generated-a,generated-b \
  --seed-list strategy-a,strategy-b \
  --output-mode metrics

The parent JSON and CSV include stress id, caller-owned severity, config hash, and aggregation class per cell. Results group by exact stress config hash, so historical, bootstrap, generated, and stressed readiness cannot be merged by accident.

Keep maker inventory fixed while testing whether gamma-scalp economics change with option-depth consumption and volatility:

npm run strategy -- panoptic-gamma-scalp --seed-list size-vol-a,size-vol-b --position-size-list 100000,250000,500000,1000000 --maker-position-size 2000000 --external-volatility-list 0.25,0.65,1 --liquidity-health 9 --duration 7d --block-time 1h --output-mode metrics --frame-count 36

The parent summary records excess value and explicit costs per million position units, premium paid, maker-depth consumption, and hedge execution cost versus both the pre-trade Pool price and the external reference. It also aggregates market transmission, liquidity, flow attribution, and market-fidelity readiness. The generic --volatility and --volatility-list spellings were removed after consumer migration. The runner returns a precise replacement message because these inputs configure only the synthetic external price process; use --external-volatility and --external-volatility-list.

The examples runner includes a file-writing demo:

npm run example -- market-gif

It writes examples/output/market.gif. The quick default uses a shorter horizon, but the same command supports a two-month daily-candle run:

npm run example -- market-gif --duration 60d --block-time 12s --candle 1d --activity normal --liquidity-health 7

To compare every liquidity-health level with the same synthetic market tape, run:

npm run example -- market-gif-health-sweep

That writes examples/output/market-health-01.gif through examples/output/market-health-10.gif. The sweep defaults are intentionally short (3d, 5m blocks, 1h candles) so all ten GIFs render quickly; pass the same flags as market-gif when you want a longer or denser diagnostic run.

Lower liquidity health scores bias the LP ecology toward sparse, thin, gappy, skewed, and stale participation. Higher scores bias it toward deeper, more continuous, more overlapping, and more actively maintained liquidity around the traded price. Activity profiles move from dead to panic by increasing trade pace, burstiness, whale probability, and daily volume.

To run the strategy analytics example:

npm run example -- strategy-backtest

Panoptic v2 VM

The Panoptic v2 simulator currently ships inside uniswap-vm as the src/panoptic public surface. That is intentional for now: the Panoptic VM depends on the same offline Pool state and routes CLAMM effects through UniswapVmPanopticAdapter. A separate panoptic-vm package can still be split later, but the current package keeps the contract-parity simulator and underlying pool VM versioned together.

Panoptic state stays outside Pool. PanopticPoolVM owns option positions, position balances, account hashes, settlement, collateral/risk hooks, and the Panoptic account reporting surface. The underlying pool remains the CLAMM book; all Panoptic liquidity effects pass through the adapter.

import {
  FeeAmount,
  PANOPTIC_V2_V3_REFERENCE_CONFIG,
  PanopticPoolVM,
  Pool,
  UniswapVmPanopticAdapter,
  addPanopticLeg,
  addPoolId,
  createPanopticPoolIdentity,
  panopticV2V3ReferenceRiskConfig,
  createToken
} from "@steerprotocol/clamm-vm/simulation";

const tokenA = createToken(1, "0x0000000000000000000000000000000000000001", 18, "A");
const tokenB = createToken(1, "0x0000000000000000000000000000000000000002", 18, "B");
const pool = Pool.fromTick({ tokenA, tokenB, fee: FeeAmount.MEDIUM, tickCurrent: 0 });
const identity = createPanopticPoolIdentity({
  poolPattern: 0x12345n,
  vegoid: PANOPTIC_V2_V3_REFERENCE_CONFIG.vegoid,
  tickSpacing: 60,
  minEnforcedTick: -887_220,
  maxEnforcedTick: 887_220
});

const panoptic = new PanopticPoolVM({
  marketId: "eth-usdc",
  poolId: identity.poolId,
  underlying: new UniswapVmPanopticAdapter(pool),
  settlement, // implement PanopticPoolSettlementPort or use PanopticCollateralSettlement
  risk: panopticV2V3ReferenceRiskConfig(),
  clock: { timestamp: 1_717_171_717, blockNumber: 42 }
});

const tokenId = addPanopticLeg(addPoolId(0n, identity.poolId), {
  index: 0,
  optionRatio: 1,
  asset: 0,
  isLong: 0,
  tokenType: 0,
  riskPartner: 0,
  strike: 600,
  width: 2
});

panoptic.openPosition({
  account: "alice",
  tokenId,
  positionSize: 1_000_000n,
  tickAndSpreadLimits: { tickLimitLow: -887_220, tickLimitHigh: 887_220, effectiveLiquidityLimit: 10_000 }
});

Panoptic reporting is fidelity-labeled. Level 2 state/risk fields are marked decision-grade only when they come from PanopticPoolVM, CollateralTracker, or RiskEngine read models. VM-owned checkpoint/rollback closeout reports can support decision-grade NAV only when the runtime declares its settlement, collateral, risk, oracle, and interest sources complete. Incomplete runtimes fail closed and retain realized/accounting value only as a secondary, non-decision-grade surface.

To run the Panoptic example:

npm run example -- panoptic-backtest

To render a Panoptic VM activity GIF:

npm run example -- panoptic-gif

To rerun the pinned long-straddle burn vectors against the sibling panoptic-v2-core checkout:

npm run test:panoptic-core-parity

The source-side command defaults to ../panoptic-v2-core, verifies the pinned core commit, and uses that checkout's Foundry RPC configuration. Set PANOPTIC_V2_CORE_PATH to select another checkout. The corresponding local VM comparison is part of the normal Vitest suite and does not require an RPC.

It writes examples/output/panoptic.gif. The renderer progressively joins source-owned market metrics, strategy portfolio rows, Panoptic snapshots, and actual strategy action outcomes. It shows decision-grade closeout NAV against an exact passive-hold benchmark, excess value, premium and fee attribution, hedge inventory, market flow, active liquidity, pool price, and the open-position structure. Open, close, hedge, and settlement actions retain their source timing; routine actions are sampled for frame timing while the action lane keeps their actual counts. The payoff curve remains explicitly diagnostic. If closeout NAV or the passive benchmark is not decision-grade, the renderer does not present the fallback accounting surface as NAV or PnL.