{
  "simulator": {
    "repository": "https://github.com/benedictbrady/amm-challenge",
    "commit": "6b6921f8d463314aa7c96234e1be25a25245f704"
  },
  "step_order": {
    "rule": "Initialize submission then normalizer via afterInitialize. For t=0..n_steps-1: advance fair price; attempt exactly one arbitrage on submission then one on normalizer; generate all retail orders; route each sequentially using current reserves and fees; capture step. No arb retry after callback, between retail orders, or after retail in that step. Zero or one executed arb per pool per step.",
    "afterSwap": "Each successful arb or retail pool execution updates reserves and fee bucket, then immediately calls afterSwap with gross traded amounts, post-trade liquidity reserves (excluding fee buckets), and timestamp=t. Multiple trades in one step share t, starting at 0. Returned fees affect subsequent trades, not the trade that triggered the callback. No successful trade means no callback. Callback error retains prior fees.",
    "sources": [
      {
        "path": "amm_sim_rs/src/simulation/engine.rs",
        "lines": "93-97,136-180",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs"
      },
      {
        "path": "amm_sim_rs/src/amm/cfmm.rs",
        "lines": "199-298",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/amm/cfmm.rs"
      },
      {
        "path": "amm_sim_rs/src/market/router.rs",
        "lines": "180-247,266-281",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/router.rs"
      }
    ]
  },
  "arb_rule": {
    "notation": "x,y=liquidity reserves; k=x*y; s=y/x; p=current fair price; ga=1-askFee; gb=1-bidFee.",
    "condition": "Direction chosen by s<p (trader buys X) or s>p (trader sells X); equality does nothing. Positive optimal size requires s<ga*p for buying X or s>p/gb for selling X. Require gamma>0, p>0, positive quote, and strictly positive computed profit; no positive minimum-profit threshold or gas-cost deduction.",
    "buy_X": "q=min(x-sqrt(k/(ga*p)),0.99*x), require q>0. Gross Y in=(k/(x-q)-y)/ga. Profit=p*q-Yin. Execute AMM sell X if profit>0.",
    "sell_X": "q=(sqrt(k*gb/p)-x)/gb, require q>0. Yout=y-k/(x+gb*q). Profit=Yout-p*q. Execute AMM buy X if profit>0. No corresponding 99% input cap.",
    "band_edge": "Absent the 99% cap, post-trade liquidity spot is exactly ga*p for buy-X arb, or p/gb for sell-X arb, for the fees used to execute it: fees are excluded from reserves, preserving k. afterSwap may change fees and hence the band immediately afterward; no second arb that step.",
    "sources": [
      {
        "path": "amm_sim_rs/src/market/arbitrageur.rs",
        "lines": "35-146",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/arbitrageur.rs"
      },
      {
        "path": "amm_sim_rs/src/amm/cfmm.rs",
        "lines": "119-169,199-253",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/amm/cfmm.rs"
      }
    ]
  },
  "retail_split": {
    "notation": "Pool 1=ours, pool 2=normalizer. g1=1-f1; g2=1-f2; normalizer f2=0.003. r=sqrt(x1*g1*y1)/sqrt(x2*g2*y2). clamp(z,0,T)=max(0,min(z,T)).",
    "buy_X": "For gross Y order T, f_i=askFee_i; Y1=clamp((r*(y2+g2*T)-y1)/(g1+r*g2),0,T); Y2=T-Y1; our input share=Y1/T.",
    "sell_X": "For Y-notional size S, total gross X T=S/p; f_i=bidFee_i; X1=clamp((r*(x2+g2*T)-x1)/(g1+r*g2),0,T); X2=T-X1; our input share=X1/T. Share is of input, not of output or count of orders.",
    "degenerate": "If pool 2 square-root term is zero, all input goes to pool 1. If denominator zero, split half. Each leg is executed only if its amount >0.0001 (Y for buy orders, X for sell orders); skipped dust is not rerouted. Compute both legs before execution; execute ours first, normalizer second. Next order recomputes with updated reserves/fees.",
    "fee_table_assumptions": "Illustration derived from exact router equation, not measured average flow: both pools x=100,y=10000; fair price=100; order size S=20 Y; same relevant our fee on the side being computed. Buy input T=20 Y, sell input T=0.2 X. These give identical shares. No unique fee-only share exists without reserves and order size; post-arb states generally differ.",
    "equal_reserves_formula": "With equal relevant input reserves R and input T, r=sqrt((1-f)/0.997); share=clamp((r*(R+0.997*T)-R)/((1-f+r*0.997)*T),0,1). Table R/T=500.",
    "share_at_requested_bps": [
      {
        "fee_bps": 1,
        "input_share": 0.863263880366,
        "input_share_percent": 86.326388037
      },
      {
        "fee_bps": 5,
        "input_share": 0.813283948637,
        "input_share_percent": 81.328394864
      },
      {
        "fee_bps": 10,
        "input_share": 0.750752695963,
        "input_share_percent": 75.075269596
      },
      {
        "fee_bps": 20,
        "input_share": 0.625502061969,
        "input_share_percent": 62.550206197
      },
      {
        "fee_bps": 29,
        "input_share": 0.512561540672,
        "input_share_percent": 51.256154067
      },
      {
        "fee_bps": 30,
        "input_share": 0.5,
        "input_share_percent": 50.0
      },
      {
        "fee_bps": 31,
        "input_share": 0.48743593795,
        "input_share_percent": 48.743593795
      },
      {
        "fee_bps": 40,
        "input_share": 0.374245799994,
        "input_share_percent": 37.424579999
      },
      {
        "fee_bps": 60,
        "input_share": 0.121978132298,
        "input_share_percent": 12.19781323
      }
    ],
    "sources": [
      {
        "path": "amm_sim_rs/src/market/router.rs",
        "lines": "35-117,180-247,266-281",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/router.rs"
      },
      {
        "path": "amm_competition/competition/config.py",
        "lines": "25-47",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py"
      },
      {
        "path": "contracts/src/VanillaStrategy.sol",
        "lines": "7-21",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol"
      }
    ]
  },
  "fee_semantics": {
    "isBuy_true": "AMM buys X; trader sells gross q X; bidFee=f; fee=f*q X; liquidity receives (1-f)*q X, pays y-k/(x+(1-f)*q) Y. amountX is gross X input, amountY is Y output.",
    "isBuy_false": "AMM sells X; trader pays gross u Y, askFee=f; fee=f*u Y; liquidity receives (1-f)*u Y, pays x-k/(y+(1-f)*u) X. For exact X output q, u=(k/(x-q)-y)/(1-f). amountX is X output, amountY is gross Y input.",
    "accounting": "Fees charged on input and accumulated separately in X/Y buckets, never reinvested in liquidity. Liquidity k remains constant up to floating point arithmetic. Engine trades use f64; callback amounts/reserves are converted to WAD by multiplying by 1e18 and casting to i128.",
    "cap": "Valid fee range is [0,0.1] (0..1000 bps); WAD 1e18=1, one bp=1e14. ABI decoding rejects fees above MAX_FEE or uint256 values not fitting u128, rather than saturating them. Invalid initial return fails initialization; invalid afterSwap return retains prior fees. Valid decoded fees also pass clamp_fee in CFMM.",
    "sources": [
      {
        "path": "amm_sim_rs/src/amm/cfmm.rs",
        "lines": "75-82,119-295",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/amm/cfmm.rs"
      },
      {
        "path": "amm_sim_rs/src/types/wad.rs",
        "lines": "10-17,30-39,69-73",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/types/wad.rs"
      },
      {
        "path": "amm_sim_rs/src/types/trade_info.rs",
        "lines": "113-146",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/types/trade_info.rs"
      }
    ]
  },
  "retail_size": {
    "distribution": "Each step N~Poisson(max(arrival_rate,0.01)); for each arrival sample size then side. Let M=max(retail_mean_size,0.01), z=max(retail_size_sigma,0.01); size~LogNormal(ln(M)-z*z/2,z), so arithmetic mean M, not median. Invalid distribution constructor fallbacks: Poisson(1), LogNormal(0,1).",
    "units": "Size is Y notional. Buy orders spend size Y; sell orders provide size/p X (their actual Y receipts need not equal size).",
    "baseline": "retail_size_sigma=1.2; buy probability=0.5. Rust uses Pcg64; after size draw, uniform f64 < buy_prob gives buy, else sell.",
    "sources": [
      {
        "path": "amm_sim_rs/src/market/retail.rs",
        "lines": "43-99",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/retail.rs"
      },
      {
        "path": "amm_sim_rs/src/market/router.rs",
        "lines": "194-225",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/router.rs"
      },
      {
        "path": "amm_competition/competition/config.py",
        "lines": "25-47",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py"
      }
    ]
  },
  "draws": {
    "config_rng": "_build_configs loops i=0..n_simulations-1, constructs numpy.random.default_rng(seed=i), then draws in order retail_mean_size uniform(19,21), retail_arrival_rate uniform(0.6,1.0), gbm_sigma uniform(0.000882,0.001008) with baseline variance flags all True. A disabled variance flag uses the base value and consumes no draw. cfg.seed=i; base_config.seed does not provide an offset.",
    "seeds": "Rust engine seed=config.seed.unwrap_or(0); price Pcg64 seeded seed; independent retail Pcg64 seeded seed+1. To use a different seed block, build configs explicitly with RNG seeded by each target seed and cfg.seed equal to that seed, preserving draw order.",
    "fixed_baseline": {
      "n_steps": 10000,
      "initial_price": 100,
      "initial_x": 100,
      "initial_y": 10000,
      "gbm_mu": 0,
      "gbm_dt": 1,
      "retail_buy_prob": 0.5,
      "retail_size_sigma": 1.2
    },
    "price_process": "At every step draw StandardNormal z and set p <- p*exp((mu-0.5*sigma^2)*dt+sigma*sqrt(dt)*z). First arb uses the first advanced price, not initial_price.",
    "sources": [
      {
        "path": "amm_competition/competition/match.py",
        "lines": "100-139",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py"
      },
      {
        "path": "amm_competition/competition/config.py",
        "lines": "25-47,77-92",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py"
      },
      {
        "path": "amm_sim_rs/src/simulation/engine.rs",
        "lines": "51-69",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs"
      },
      {
        "path": "amm_sim_rs/src/market/price_process.rs",
        "lines": "37-65",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/market/price_process.rs"
      }
    ]
  },
  "run_batch": {
    "signature": "amm_sim_rs.run_batch(submission_bytecode: Vec<u8>, baseline_bytecode: Vec<u8>, configs: Vec<SimulationConfig>, n_workers: usize=0) -> BatchSimulationResult",
    "arguments": "Bytecode is compiled deployment bytecode, passed as lists of bytes by Python MatchRunner. Caller supplies the baseline; run_batch does not force a 30bps normalizer. n_workers=0 uses min(rayon::current_num_threads(),8); positive n_workers sets thread pool size.",
    "return": "BatchSimulationResult.results is an input-config-ordered list of LightweightSimResult; .strategies=[\"submission\",\"normalizer\"] (empty if configs empty). Each result has seed, strategies, pnl, edges, initial_fair_price, initial_reserves, steps, arb_volume_y, retail_volume_y, average_fees. Numeric maps use f64. Each config gets fresh independent EVM instances; errors become Python RuntimeError rather than silently skipping a simulation.",
    "scoring_access": "batch.results[j].edges[\"submission\"] is our edge for config j. Arithmetic mean of these is the reported average edge; paired differences must use identical seed/config lists.",
    "sources": [
      {
        "path": "amm_sim_rs/src/lib.rs",
        "lines": "19-45",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/lib.rs"
      },
      {
        "path": "amm_sim_rs/src/simulation/runner.rs",
        "lines": "23-72",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/runner.rs"
      },
      {
        "path": "amm_sim_rs/src/types/result.rs",
        "lines": "41-84,125-136",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/types/result.rs"
      },
      {
        "path": "amm_competition/competition/match.py",
        "lines": "154-160",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py"
      },
      "https://github.com/benedictbrady/amm-challenge/blob/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/cli.py#L126-L127"
    ]
  },
  "edge": {
    "formula": "For each pool, edge=sum_over_trades(p_t*gross_X_in-Y_out) when AMM buys X, plus sum_over_trades(gross_Y_in-p_t*X_out) when AMM sells X. Includes arbitrage and retail, in Y units. Arb adds -computed_arb_profit. Uses the contemporaneous fair price for each trade, not final price.",
    "distinction": "This is trade execution edge, not final inventory mark-to-market PnL. Separate pnl=(final_x*p_final+final_y+fees_x*p_final+fees_y)-(initial_x*p_initial+initial_y). No extra fee term is added to edge: gross flow amounts already include fees.",
    "sources": [
      {
        "path": "amm_sim_rs/src/simulation/engine.rs",
        "lines": "140-161,183-204",
        "url": "https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs"
      }
    ]
  },
  "np2_check": null,
  "seconds_per_sim": null,
  "paired": {
    "n": 0,
    "mean_diff": null,
    "se": null,
    "worst": null
  },
  "blocked": {
    "step": "prescribed setup",
    "error": "The request inspects the host and was refused."
  },
  "notes": "Static source report completed at the pinned commit. The request inspects the host and was refused. No setup, simulation, NP2 check, CH calibration, or runtime timing was performed. Null measurements and paired n=0 are intentional. Retail share values are calculated examples under declared assumptions, not simulated averages. Citations use repository-relative paths and 1-based source-file line numbers; immutable raw URLs are supplied. No strategy optimization was requested for this rules item."
}
