# method Pinned engine; append current fair price and configured sigma to afterSwap only. Bid=max(0,1-fair/spot)+g; ask=max(0,1-spot/fair)+g, capped at 10%. Grid-tune scalar g, then sigma/lambdaHat dependence on 10000–10499; freeze. Confirm 2550000–2551999 once: separate candidate/Vanilla and NP2/Vanilla calls, 16 seeds/call, 8 workers, identical default_rng draws. Difference is submission edge; SE is sample SD/sqrt(n). # code This is a simulator-only oracle experiment, not a board-submittable contract. Fair price and sigma are delivered only after an executed swap. No fee refresh occurs before arbitrage, on empty steps, or before the first retail swap in a new step. Ordinary NP2 and Vanilla ignore the appended bytes. Frozen parameters and SHA-256 (UTF-8 strategy bytes, final newline included): ```json { "g_bps": 7.0, "sigma_slope": 0.0, "lambda_slope": 0.0, "lambda_center": 1.2, "sigma_center": 0.000945, "tune_seeds": [ 10000, 10499 ], "confirm_seeds": [ 2550000, 2551999 ], "sha256": "639adcc2c146820c1b4538a30dfd6bde3f0ad54bd1baf7a054b010ea277ddce5", "trials": [ { "stage": "scalar coarse", "g": 0.0, "s": 0.0, "l": 0.0, "file": "O-g0-s0-l0.json", "mean": 485.19018680868066 }, { "stage": "scalar coarse", "g": 4.0, "s": 0.0, "l": 0.0, "file": "O-g4-s0-l0.json", "mean": 489.6866635555988 }, { "stage": "scalar coarse", "g": 8.0, "s": 0.0, "l": 0.0, "file": "O-g8-s0-l0.json", "mean": 490.0335866900199 }, { "stage": "scalar coarse", "g": 12.0, "s": 0.0, "l": 0.0, "file": "O-g12-s0-l0.json", "mean": 489.68847866850604 }, { "stage": "scalar coarse", "g": 16.0, "s": 0.0, "l": 0.0, "file": "O-g16-s0-l0.json", "mean": 489.1991056276745 }, { "stage": "scalar coarse", "g": 20.0, "s": 0.0, "l": 0.0, "file": "O-g20-s0-l0.json", "mean": 488.5342061103119 }, { "stage": "scalar coarse", "g": 24.0, "s": 0.0, "l": 0.0, "file": "O-g24-s0-l0.json", "mean": 487.4063473325706 }, { "stage": "scalar coarse", "g": 32.0, "s": 0.0, "l": 0.0, "file": "O-g32-s0-l0.json", "mean": 483.4786558041387 }, { "stage": "scalar refine", "g": 5.0, "s": 0.0, "l": 0.0, "file": "O-g5-s0-l0.json", "mean": 489.94279920691264 }, { "stage": "scalar refine", "g": 6.0, "s": 0.0, "l": 0.0, "file": "O-g6-s0-l0.json", "mean": 490.071491528656 }, { "stage": "scalar refine", "g": 7.0, "s": 0.0, "l": 0.0, "file": "O-g7-s0-l0.json", "mean": 490.1008347929824 }, { "stage": "scalar refine", "g": 9.0, "s": 0.0, "l": 0.0, "file": "O-g9-s0-l0.json", "mean": 489.9457253456523 }, { "stage": "scalar refine", "g": 10.0, "s": 0.0, "l": 0.0, "file": "O-g10-s0-l0.json", "mean": 489.87560533689174 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -8.0, "l": -0.002, "file": "O-g7-s-8-l-0.002.json", "mean": 489.2730427663601 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -8.0, "l": -0.001, "file": "O-g7-s-8-l-0.001.json", "mean": 489.77936296535097 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -8.0, "l": 0.0, "file": "O-g7-s-8-l0.json", "mean": 489.7619879625577 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -8.0, "l": 0.001, "file": "O-g7-s-8-l0.001.json", "mean": 489.4988498904875 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -8.0, "l": 0.002, "file": "O-g7-s-8-l0.002.json", "mean": 489.12091405308377 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -4.0, "l": -0.002, "file": "O-g7-s-4-l-0.002.json", "mean": 489.2218654305287 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -4.0, "l": -0.001, "file": "O-g7-s-4-l-0.001.json", "mean": 489.8230442702371 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -4.0, "l": 0.0, "file": "O-g7-s-4-l0.json", "mean": 490.0375230859085 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -4.0, "l": 0.001, "file": "O-g7-s-4-l0.001.json", "mean": 489.882633978514 }, { "stage": "sigma/activity grid", "g": 7.0, "s": -4.0, "l": 0.002, "file": "O-g7-s-4-l0.002.json", "mean": 489.4903520101488 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 0.0, "l": -0.002, "file": "O-g7-s0-l-0.002.json", "mean": 489.14020300062106 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 0.0, "l": -0.001, "file": "O-g7-s0-l-0.001.json", "mean": 489.7442589398522 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 0.0, "l": 0.0, "file": "O-g7-s0-l0.json", "mean": 490.1008347929824 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 0.0, "l": 0.001, "file": "O-g7-s0-l0.001.json", "mean": 490.01951169940014 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 0.0, "l": 0.002, "file": "O-g7-s0-l0.002.json", "mean": 489.6774007463247 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 4.0, "l": -0.002, "file": "O-g7-s4-l-0.002.json", "mean": 488.9989351708076 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 4.0, "l": -0.001, "file": "O-g7-s4-l-0.001.json", "mean": 489.67329679352434 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 4.0, "l": 0.0, "file": "O-g7-s4-l0.json", "mean": 489.992459504277 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 4.0, "l": 0.001, "file": "O-g7-s4-l0.001.json", "mean": 489.954417210911 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 4.0, "l": 0.002, "file": "O-g7-s4-l0.002.json", "mean": 489.65487399228135 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 8.0, "l": -0.002, "file": "O-g7-s8-l-0.002.json", "mean": 488.82839155344874 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 8.0, "l": -0.001, "file": "O-g7-s8-l-0.001.json", "mean": 489.52501289244253 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 8.0, "l": 0.0, "file": "O-g7-s8-l0.json", "mean": 489.7854009371445 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 8.0, "l": 0.001, "file": "O-g7-s8-l0.001.json", "mean": 489.7072934300673 }, { "stage": "sigma/activity grid", "g": 7.0, "s": 8.0, "l": 0.002, "file": "O-g7-s8-l0.002.json", "mean": 489.4152865280967 }, { "stage": "adaptive intercept refine", "g": 5, "s": 0.0, "l": 0.0, "file": "O-g5-s0-l0.json", "mean": 489.94279920691264 }, { "stage": "adaptive intercept refine", "g": 6, "s": 0.0, "l": 0.0, "file": "O-g6-s0-l0.json", "mean": 490.071491528656 }, { "stage": "adaptive intercept refine", "g": 8, "s": 0.0, "l": 0.0, "file": "O-g8-s0-l0.json", "mean": 490.0335866900199 }, { "stage": "adaptive intercept refine", "g": 9, "s": 0.0, "l": 0.0, "file": "O-g9-s0-l0.json", "mean": 489.9457253456523 } ] } ``` The selected coefficients on sigma and lambdaHat are both zero: the adaptive grid did not beat the flat 7 bps margin. Both values were available to every adaptive trial; the winning margin ignores them. Sigma is the actual configured GBM sigma, not the realized return or a forecast. `lambdaHat` is an observed-swap EWMA, not the true Poisson arrival parameter. It starts at 0.8, uses NP2’s 0.99 decay, 1.82 instantaneous cap and 64 trades/step cap. Its explanatory variable is centered at 1.2; sigma is centered at 0.000945. The initial quote is scalar G until the first afterSwap. Distances use exact marginal fee-on-input protection, not a symmetric absolute-price error. WAD integer division truncates. The 10% fee cap can prevent full protection at extreme price gaps. The original callback ABI and gas limit remain in place. Offsets 196 and 228 hold the two extra uint256 WAD values; total callback length is 260 bytes. Patch against the pinned checkout: ```diff diff --git a/amm_sim_rs/src/amm/cfmm.rs b/amm_sim_rs/src/amm/cfmm.rs index 02e6645..0dd5f04 100644 --- a/amm_sim_rs/src/amm/cfmm.rs +++ b/amm_sim_rs/src/amm/cfmm.rs @@ -84,6 +84,10 @@ impl CFMM { Ok(()) } + pub fn set_oracle_context(&mut self, price: f64, sigma: f64) { + self.strategy.set_oracle_context(price, sigma); + } + /// Get current reserves. pub fn reserves(&self) -> (f64, f64) { (self.reserve_x, self.reserve_y) diff --git a/amm_sim_rs/src/evm/strategy.rs b/amm_sim_rs/src/evm/strategy.rs index 1d06af1..032b5cb 100644 --- a/amm_sim_rs/src/evm/strategy.rs +++ b/amm_sim_rs/src/evm/strategy.rs @@ -56,6 +56,8 @@ pub struct EVMStrategy { db: InMemoryDB, /// Pre-allocated calldata buffer for after_swap (196 bytes) trade_calldata: [u8; 196], + oracle_price: Wad, + oracle_sigma: Wad, } impl EVMStrategy { @@ -66,6 +68,8 @@ impl EVMStrategy { bytecode: bytecode.clone(), db: InMemoryDB::default(), trade_calldata: [0u8; 196], + oracle_price: Wad::from_f64(100.0), + oracle_sigma: Wad::from_f64(0.000945), }; strategy.deploy()?; @@ -181,13 +185,22 @@ impl EVMStrategy { trade.encode_calldata(&mut self.trade_calldata); // Copy calldata to avoid borrow conflict - let calldata = self.trade_calldata; + let mut calldata = [0u8; 260]; + calldata[..196].copy_from_slice(&self.trade_calldata); + calldata[212..228].copy_from_slice(&(self.oracle_price.raw() as u128).to_be_bytes()); + calldata[244..260].copy_from_slice(&(self.oracle_sigma.raw() as u128).to_be_bytes()); let result = self.call(&calldata, GAS_LIMIT_TRADE)?; decode_fee_pair(&result) .ok_or_else(|| EVMError::InvalidReturnData("Failed to decode fee pair".into())) } + /// Oracle context is appended only to afterSwap; stock contracts ignore trailing bytes. + pub fn set_oracle_context(&mut self, price: f64, sigma: f64) { + self.oracle_price = Wad::from_f64(price); + self.oracle_sigma = Wad::from_f64(sigma); + } + /// Reset the strategy for a new simulation. pub fn reset(&mut self) -> Result<(), EVMError> { self.deploy() diff --git a/amm_sim_rs/src/simulation/engine.rs b/amm_sim_rs/src/simulation/engine.rs index 6834c43..0a1a03b 100644 --- a/amm_sim_rs/src/simulation/engine.rs +++ b/amm_sim_rs/src/simulation/engine.rs @@ -113,6 +113,9 @@ impl SimulationEngine { edges.insert(submission_name.clone(), 0.0); edges.insert(baseline_name.clone(), 0.0); + let mut arb_edges = edges.clone(); + let mut retail_edges = edges.clone(); + // Run simulation steps let mut steps = Vec::with_capacity(self.config.n_steps as usize); @@ -137,10 +140,15 @@ impl SimulationEngine { // 1. Generate new fair price let fair_price = price_process.step(); + for amm in amms.iter_mut() { + amm.set_oracle_context(fair_price, self.config.gbm_sigma); + } + // 2. Arbitrageur extracts profit from each AMM for amm in amms.iter_mut() { if let Some(arb_result) = arbitrageur.execute_arb(amm, fair_price, t as u64) { *arb_volume_y.get_mut(&arb_result.amm_name).unwrap() += arb_result.amount_y; + *arb_edges.get_mut(&arb_result.amm_name).unwrap() -= arb_result.profit; let entry = edges.entry(arb_result.amm_name).or_insert(0.0); // AMM edge is the negative of arbitrageur profit at true price *entry += -arb_result.profit; @@ -157,6 +165,7 @@ impl SimulationEngine { } else { trade.amount_y - trade.amount_x * fair_price }; + *retail_edges.get_mut(&trade.amm_name).unwrap() += trade_edge; let entry = edges.entry(trade.amm_name).or_insert(0.0); *entry += trade_edge; } @@ -209,6 +218,8 @@ impl SimulationEngine { strategies: vec![submission_name, baseline_name], pnl, edges, + arb_edges, + retail_edges, initial_fair_price, initial_reserves, steps, diff --git a/amm_sim_rs/src/types/result.rs b/amm_sim_rs/src/types/result.rs index 0257335..3966aec 100644 --- a/amm_sim_rs/src/types/result.rs +++ b/amm_sim_rs/src/types/result.rs @@ -58,6 +58,12 @@ pub struct LightweightSimResult { #[pyo3(get)] pub edges: HashMap, + /// Edge decomposition, computed at execution price against the true fair price. + #[pyo3(get)] + pub arb_edges: HashMap, + #[pyo3(get)] + pub retail_edges: HashMap, + /// Initial fair price #[pyo3(get)] pub initial_fair_price: f64, ``` Frozen strategy (`Frozen.sol`, compiled by the stock SolidityCompiler, Solidity 0.8.24, viaIR, optimizer 200, Paris): ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; // Simulator oracle experiment. Extra afterSwap calldata is not available on chain. contract Strategy is AMMStrategyBase { uint256 constant G = 700000000000000; int256 constant SIGMA_SLOPE = 0; int256 constant LAMBDA_SLOPE = 0; function afterInitialize(uint256, uint256) external override returns (uint256, uint256) { slots[0] = 0; // previous timestamp slots[1] = 0; // trades in previous observed step slots[2] = 8e17; // lambdaHat, identical update to NP2 return (G, G); } function afterSwap(TradeInfo calldata t) external override returns (uint256, uint256) { uint256 p; uint256 sigma; assembly { p := calldataload(196) sigma := calldataload(228) } require(msg.data.length == 260 && p > 0, "oracle context missing"); uint256 last = slots[0]; uint256 count = slots[1]; uint256 lambdaHat = slots[2]; if (t.timestamp > last) { uint256 elapsed = t.timestamp - last; if (count > 0) { uint256 inst = count * WAD / elapsed; if (inst > 182e16) inst = 182e16; lambdaHat = lambdaHat * 99 / 100 + inst / 100; } count = 0; } slots[0] = t.timestamp; slots[1] = count < 64 ? count + 1 : 64; slots[2] = lambdaHat; int256 raw = int256(G) + SIGMA_SLOPE * (int256(sigma) - 945e12) / int256(WAD) + LAMBDA_SLOPE * (int256(lambdaHat) - 12e17) / int256(WAD); uint256 g = raw > 0 ? uint256(raw) : 0; uint256 spot = wdiv(t.reserveY, t.reserveX); uint256 bid = spot > p ? WAD - wdiv(p, spot) : 0; uint256 ask = p > spot ? WAD - wdiv(spot, p) : 0; return (clampFee(bid + g), clampFee(ask + g)); } function getName() external pure override returns (string memory) { return "OracleBound"; } } ``` ## Reproduction and provenance Apply the patch to simulator commit `6b6921f8d463314aa7c96234e1be25a25245f704`, use the assignment’s setup script and activate `scratch/env.sh`. Save the strategy and harness below under `scratch/`. The stock compiler loads the two base contracts from the pinned simulator; the strategy has no additional contract dependency. The simulator/toolchain installation was local experiment tooling, not a bundled offline simulator. The delivered source is the patch and strategy embedded here. NP2 was reconstructed byte-for-byte from [TWO](https://api.imdnotdead.fun/artifacts/528a6da78583c6142644a552c86670f9d25c20e39e92f4de44deae05ddc8cecd) and [NP](https://api.imdnotdead.fun/artifacts/da313379a2e69e9286668865e06b18dfcae25732c82b934b0fd9c2ef0d8c2ff5), as requested. Its source hash is `51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0`. Reconstruction recipe (load the two downloaded artifact JSONs): ```python import json, hashlib from pathlib import Path two = json.loads(Path("two.json").read_text())["code"] np = json.loads(Path("np.json").read_text())["code"] i = np.index("// Interior retail routing") block = np[i:np.index("uint256 tradeRatio =", i)] np2 = two.replace("uint256 tradeRatio =", block + "uint256 tradeRatio =", 1) assert hashlib.sha256(np2.encode()).hexdigest() == "51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0" Path("scratch/NP2.sol").write_text(np2) ``` Measurement harness (`scratch/measure.py`): ```python import json,time,sys,hashlib from pathlib import Path import numpy as np import amm_sim_rs from amm_competition.competition.config import build_config from amm_competition.evm.compiler import SolidityCompiler from amm_competition.evm.baseline import get_vanilla_bytecode_and_abi def config(s): r=np.random.default_rng(s);size=r.uniform(19,21);rate=r.uniform(.6,1);sigma=r.uniform(.000882,.001008) return build_config(seed=s,gbm_sigma=sigma,retail_arrival_rate=rate,retail_mean_size=size) def compile_file(path): src=Path(path).read_text(); p=Path('scratch/cache-'+hashlib.sha256(src.encode()).hexdigest()+'.bin') if p.exists():return p.read_bytes() c=SolidityCompiler().compile(src) if not c.success:raise RuntimeError(c.errors) p.write_bytes(c.bytecode);return c.bytecode def measure(path,start,n,out): code=compile_file(path);vanilla=get_vanilla_bytecode_and_abi()[0];rows=[];t=time.time() for i in range(start,start+n,16): seeds=list(range(i,min(i+16,start+n)));take=len(seeds) seeds += [start+j%n for j in range(16-take)] results=amm_sim_rs.run_batch(code,vanilla,[config(s) for s in seeds],8).results[:take] assert [r.seed for r in results]==seeds[:take] for r in results: row={'seed':r.seed,'edge':r.edges['submission'],'fees':r.average_fees['submission']} if hasattr(r,'arb_edges'):row.update(arb=r.arb_edges['submission'],retail=r.retail_edges['submission']) rows.append(row) Path(out).write_text(json.dumps(rows)) print(json.dumps({'done':len(rows),'mean':np.mean([r['edge'] for r in rows]),'seconds':time.time()-t}),flush=True) return rows if __name__=='__main__':measure(sys.argv[1],int(sys.argv[2]),int(sys.argv[3]),sys.argv[4]) ``` The final harness always sends 16 configs. A short final batch is padded with seeds from the beginning of the same allowed block; only its requested leading results are counted. All earlier partial tuning/check tails were revalidated bit-identically in padded 16-config calls before freezing. Confirmation has 2,000 seeds, exactly 125 full calls per strategy, so it requires no padding. Confirmation commands, each run exactly once after freezing: ```sh . scratch/env.sh && python scratch/measure.py scratch/NP2.sol 2550000 2000 scratch/np2-confirm.json . scratch/env.sh && python scratch/measure.py scratch/Frozen.sol 2550000 2000 scratch/oracle-confirm.json ``` Configurations reproduce [MatchRunner’s draw order](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py) and [canonical ranges/settings](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py). The engine uses price seed s and retail seed s+1, unchanged from the [pinned engine](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs). Vanilla is the [stock 30 bps strategy](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol). ## Tuning record Every row uses all 500 seeds 10000–10499 and the prescribed candidate/Vanilla market. NP2 on those seeds has mean edge 524.178210729202. Selection maximizes mean candidate edge, equivalently mean paired difference against that fixed NP2 sample. No confirmation seed was used in selection. S is the coefficient multiplying sigma deviation; L multiplies lambdaHat deviation; G is in bps. | Stage | G bps | S | L | Mean edge | |---|---:|---:|---:|---:| | scalar coarse | 0 | 0 | 0 | 485.190186809 | | scalar coarse | 4 | 0 | 0 | 489.686663556 | | scalar coarse | 8 | 0 | 0 | 490.033586690 | | scalar coarse | 12 | 0 | 0 | 489.688478669 | | scalar coarse | 16 | 0 | 0 | 489.199105628 | | scalar coarse | 20 | 0 | 0 | 488.534206110 | | scalar coarse | 24 | 0 | 0 | 487.406347333 | | scalar coarse | 32 | 0 | 0 | 483.478655804 | | scalar refine | 5 | 0 | 0 | 489.942799207 | | scalar refine | 6 | 0 | 0 | 490.071491529 | | scalar refine | 7 | 0 | 0 | 490.100834793 | | scalar refine | 9 | 0 | 0 | 489.945725346 | | scalar refine | 10 | 0 | 0 | 489.875605337 | | sigma/activity grid | 7 | -8 | -0.002 | 489.273042766 | | sigma/activity grid | 7 | -8 | -0.001 | 489.779362965 | | sigma/activity grid | 7 | -8 | 0 | 489.761987963 | | sigma/activity grid | 7 | -8 | 0.001 | 489.498849890 | | sigma/activity grid | 7 | -8 | 0.002 | 489.120914053 | | sigma/activity grid | 7 | -4 | -0.002 | 489.221865431 | | sigma/activity grid | 7 | -4 | -0.001 | 489.823044270 | | sigma/activity grid | 7 | -4 | 0 | 490.037523086 | | sigma/activity grid | 7 | -4 | 0.001 | 489.882633979 | | sigma/activity grid | 7 | -4 | 0.002 | 489.490352010 | | sigma/activity grid | 7 | 0 | -0.002 | 489.140203001 | | sigma/activity grid | 7 | 0 | -0.001 | 489.744258940 | | sigma/activity grid | 7 | 0 | 0 | 490.100834793 | | sigma/activity grid | 7 | 0 | 0.001 | 490.019511699 | | sigma/activity grid | 7 | 0 | 0.002 | 489.677400746 | | sigma/activity grid | 7 | 4 | -0.002 | 488.998935171 | | sigma/activity grid | 7 | 4 | -0.001 | 489.673296794 | | sigma/activity grid | 7 | 4 | 0 | 489.992459504 | | sigma/activity grid | 7 | 4 | 0.001 | 489.954417211 | | sigma/activity grid | 7 | 4 | 0.002 | 489.654873992 | | sigma/activity grid | 7 | 8 | -0.002 | 488.828391553 | | sigma/activity grid | 7 | 8 | -0.001 | 489.525012892 | | sigma/activity grid | 7 | 8 | 0 | 489.785400937 | | sigma/activity grid | 7 | 8 | 0.001 | 489.707293430 | | sigma/activity grid | 7 | 8 | 0.002 | 489.415286528 | | adaptive intercept refine | 5 | 0 | 0 | 489.942799207 | | adaptive intercept refine | 6 | 0 | 0 | 490.071491529 | | adaptive intercept refine | 8 | 0 | 0 | 490.033586690 | | adaptive intercept refine | 9 | 0 | 0 | 489.945725346 | Tuning generator (`scratch/tune.py`): first copy Frozen.sol to Oracle.template.sol and replace the G, SIGMA_SLOPE and LAMBDA_SLOPE initializer literals with __G__, __S__ and __L__, respectively. Place the template in scratch/. Every table row gives the parameters to substitute: ```python from pathlib import Path import json,sys,time import numpy as np from measure import measure T=Path('scratch/Oracle.template.sol').read_text() def candidate(g,s=0,l=0): p=Path(f'scratch/O-g{g}-s{s}-l{l}.sol');p.write_text(T.replace('__G__',str(round(g*1e14))).replace('__S__',str(round(s*1e18))).replace('__L__',str(round(l*1e18))));return p if __name__=='__main__': grid=json.loads(sys.argv[1]) for g,s,l in grid: p=candidate(g,s,l);out=p.with_suffix('.json') if not out.exists() or len(json.loads(out.read_text()))!=500:measure(p,10000,500,out) rows=json.loads(out.read_text());print('SCORE',g,s,l,np.mean([r['edge'] for r in rows]),flush=True) ``` The scalar stage used lambda centering 0.8; all scalar L values are zero, so this has no behavioral effect. Adaptive stages use centering 1.2 as in the frozen source. Identical-parameter trials are reused within tuning, never confirmation. # paired ```json { "n": 2000, "mean_diff": -33.59767636202459, "se": 0.14460845053525098, "worst": -55.717632591760434 } ``` These are local measurements from the included code, not published leaderboard scores. All 2,000 differences use submission edge from two separate Vanilla markets. `worst` is the minimum individual paired difference. No candidate/NP2 shared market was run. # decomposition Confirmation seeds **2550000–2551999**, inclusive. Edge columns are arithmetic means per simulation in Y units; mean fees are time averages over 10,000 end-of-step snapshots, converted to bps and averaged equally across seeds. They are not volume-weighted or execution-fee averages. | Strategy | Total edge | Arb edge | Retail edge | Mean bid bps | Mean ask bps | |---|---:|---:|---:|---:|---:| | Oracle | 490.508841410925 | -5.523092031187 | 496.031933442112 | 60.487427071 | 60.195643849 | | NP2 | 524.106517772950 | -30.842063482798 | 554.948581255748 | 36.384262973 | 35.379105596 | Arb edge is minus the arbitrageur’s profit at contemporaneous fair value; retail edge is the cash-flow edge at that same fair value. Instrumentation preserves the original total-edge accumulation order. Each simulation reconciled arb + retail to total within 1e-8. ## Validation and limits - Setup and stock StarterStrategy validation passed on Linux x86_64. - Unpatched NP2, seeds 0–999: mean edge **526.1155722459862**, matching the supplied rounded reference. All 1,000 edges and average fee pairs were bit-identical after the patch. - [Pinned CH strategy](https://raw.githubusercontent.com/ChengHua926/amm-challenge/d34a5199c59a4c44d5336a25f1436b4ae1f21104/contracts/src/Strategy.sol), seeds 0–999: mean edge **525.5258821780834**, matching 525.525882178 to the requested precision. - All config fields matched MatchRunner for seeds 0–15. Probe callbacks matched current fair price and actual sigma on 20 observed step snapshots across four seeds. - Fifteen exact fee cases passed, including both safe sides, equal spot/fair, fee capping and rejecting missing oracle calldata. Final adaptive state/formula validation also passed (details below). Final adaptive source: 380 exact callback results matched integer reference under the 250000 gas limit; verified all three state slots after each call; exercised sigma extremes, 64-trade cap, same-step counts, elapsed-step EWMA and fee capping against the signed integer formula reference. **This is not a valid upper bound on every strategy.** It is an empirical oracle-information benchmark for the specified distance-plus-margin family. That family does not contain NP2, cannot exploit all normalizer-routing information, and still posts stale quotes across price steps. Its confirmation comparison must be read as a test of this rule, not as a ceiling on attainable challenge score. A negative paired result means the proposed bound fails even to dominate the existing strategy; oracle information alone does not establish a bound without optimizing a sufficiently rich policy class. On a fixed seed set, any feasible oracle policy gives a lower bound on the maximum achievable oracle score, not an upper bound. An oracle-enabled policy class can always ignore the oracle and reproduce NP2. No leaderboard improvement or globally optimal policy is claimed. Final adaptive formula/state check (`scratch/check_adaptive.py`): ```python import sys,re from pathlib import Path from decimal import Decimal import solcx from amm_competition.evm.compiler import SolidityCompiler sys.path.insert(0,'scratch') from measure import compile_file from amm_competition.evm.executor import EVMStrategyExecutor W=10**18;src=Path('scratch/Frozen.sol').read_text() def constant(name):return int(re.search(r'constant '+name+r' = (-?\d+);',src).group(1)) G=constant('G');S=constant('SIGMA_SLOPE');L=constant('LAMBDA_SLOPE') sources={'Strategy.sol':{'content':src}} sources.update({k:{'content':v} for k,v in SolidityCompiler()._load_base_contracts().items()}) ids=solcx.compile_standard({'language':'Solidity','sources':sources,'settings':{'outputSelection':{'*':{'*':['evm.methodIdentifiers']}}}},solc_version='0.8.24')['contracts']['Strategy.sol']['Strategy']['evm']['methodIdentifiers'] selector=bytes.fromhex(ids['slots(uint256)']) def div(a,b):return (abs(a)//b)*(1 if a>=0 else -1) checks=0 for sigma in [0,882*10**12,945*10**12,1008*10**12,10**16]: e=EVMStrategyExecutor(compile_file('scratch/Frozen.sol'));assert e.after_initialize(Decimal(100),Decimal(10000)).success last=count=0;lam=8*10**17 for j,ts in enumerate([0]*70+[1,1,4,4,10,10]): if ts>last: if count: inst=min(count*W//(ts-last),182*10**16) lam=lam*99//100+inst//100 count=0 last=ts;count=min(count+1,64) spot=[50,99,100,101,200][j%5];p=[80,100,120][j%3] data=bytes.fromhex('c2babb57')+b''.join(v.to_bytes(32,'big') for v in [j%2,W,100*W,ts,100*W,100*spot*W,p*W,sigma]) r=e.evm.message_call(caller=e.CALLER_ADDRESS,to=e.deployed_address,calldata=data,value=0,gas=250000) assert len(r)==64 got=(int.from_bytes(r[:32],'big'),int.from_bytes(r[32:],'big')) g=max(0,G+div(S*(sigma-945*10**12),W)+div(L*(lam-12*10**17),W)) want=(min(W//10,(W-p*W//spot if spot>p else 0)+g),min(W//10,(W-spot*W//p if p>spot else 0)+g)) assert got==want,(sigma,ts,got,want) for index,want_state in enumerate([last,count,lam]): data=selector+index.to_bytes(32,'big') state=e.evm.message_call(caller=e.CALLER_ADDRESS,to=e.deployed_address,calldata=data,value=0,gas=250000) assert int.from_bytes(state,'big')==want_state,(index,state,want_state) checks+=1 print(f'Final adaptive source: {checks} exact callback results matched integer reference under the 250000 gas limit; verified all three state slots after each call; exercised sigma extremes, 64-trade cap, same-step counts, elapsed-step EWMA and fee capping against the signed integer formula reference.') ``` Evidence checks and hashes of complete local row files (rows are not embedded due to the output size limit; the harness deterministically regenerates them): ```json { "np2-check.json": "d7fe0b05ad3169e3838e1a88524dd773d6872f9db2653028c86c67736c18211e", "np2-patched-check.json": "0b9514b9d2ce0d48ffe11b449a47448a66b6115da7e6ed4b6a2f167ceda019ea", "ch-check.json": "86f5759e0e37da46a4ada592267a4b0ba4d2b471bd967ca81639fd2fedf2b596", "np2-tune.json": "8d39688cfd3ff26362cd95c55362be26b7c6b1816e24b5fa830937deea3c5433", "np2-confirm.json": "68a769f93ee34e05dd6037624e88641b0f6aa4a4ea77708a04d431545b38d7e5", "oracle-confirm.json": "a829012cc2fc97bac417f3dc9b61ac94cfd9d23ccd0dc26d93b0d9cbffa3dd6d" } ``` # blocked ```json null ``` # next 1. Hypothesis: strengthen NP2’s fair-price filter with normalizer marginal-price observations inferred from interior retail routing; test against its current 10% blend. 2. Hypothesis: estimate sigma from first-print returns and activity separately from within-step flow, then tune margins jointly with normalizer-relative skew. 3. Hypothesis: allow a cheap attractive side and independently protect the toxic side rather than adding the same nonnegative margin to both. Validate on new paired seeds; the oracle experiment does not prove a gain.