{
 "item": "calibration-and-harness",
 "batch": "e01-evaluator-check",
 "blocked": null,
 "no_board_claim": "Self-comparison on tuning seeds only. Nothing here is a board result or a confirmation; no seed >= 5000000 was used.",
 "code": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {AMMStrategyBase} from \"./AMMStrategyBase.sol\";\nimport {TradeInfo} from \"./IAMMStrategy.sol\";\n\ncontract Strategy is AMMStrategyBase {\n    uint256 constant ELAPSED_CAP = 8;\n    uint256 constant SIGNAL_THRESHOLD = WAD / 650;\n    uint256 constant DIR_DECAY = 750000000000000000;\n    uint256 constant ACT_DECAY = 530000000000000000;\n    uint256 constant SIZE_DECAY = 530000000000000000;\n    uint256 constant TOX_DECAY = 910000000000000000;\n    uint256 constant SIGMA_DECAY = 690000000000000000;\n    uint256 constant LAMBDA_DECAY = 990000000000000000;\n    uint256 constant SIZE_BLEND_DECAY = 828000000000000000;\n    uint256 constant TOX_BLEND_DECAY = 51000000000000000;\n    uint256 constant ACT_BLEND_DECAY = 985000000000000000;\n    uint256 constant PHAT_ALPHA = 270000000000000000;\n    uint256 constant PHAT_ALPHA_RETAIL = 60000000000000000;\n    uint256 constant PHAT_ALPHA_SAME = 120000000000000000;\n    uint256 constant REVERT_U = 0;\n    uint256 constant DIR_IMPACT_MULT = 4;\n    uint256 constant GATE_SIGMA_MULT = 7200000000000000000;\n    uint256 constant MIN_GATE = 30000000000000000;\n    uint256 constant TRADE_TOX_BOOST = 3500 * BPS;\n    uint256 constant STALE_ATTRACT_FRAC = 1050000000000000000;\n    uint256 constant RET_CAP = WAD / 35;\n    uint256 constant TOX_CAP = WAD / 5;\n    uint256 constant TRADE_RATIO_CAP = WAD / 5;\n    uint256 constant LAMBDA_CAP = 1820000000000000000;\n    uint256 constant STEP_COUNT_CAP = 64;\n    uint256 constant BASE_FEE = 4 * BPS;\n    uint256 constant SIGMA_COEF = 200000000000000000;\n    uint256 constant LAMBDA_COEF = 12 * BPS;\n    uint256 constant FLOW_SIZE_COEF = 4842 * BPS;\n    uint256 constant TOX_COEF = 300 * BPS;\n    uint256 constant TOX_QUAD_COEF = 15000 * BPS;\n    uint256 constant ACT_COEF = 91843 * BPS;\n    uint256 constant DIR_COEF = 20 * BPS;\n    uint256 constant DIR_TOX_COEF = 100 * BPS;\n    uint256 constant STALE_DIR_COEF = 6850 * BPS;\n    uint256 constant SIGMA_TOX_COEF = 500 * BPS;\n    uint256 constant TAIL_KNEE = 600 * BPS;\n    uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000;\n    uint256 constant TAIL_SLOPE_ATTRACT = 850000000000000000;\n\n    function afterInitialize(uint256 initialX, uint256 initialY) external override returns (uint256, uint256) {\n        slots[0] = BASE_FEE; slots[1] = BASE_FEE; slots[3] = WAD; \n        slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD;\n        slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000;\n        slots[13] = 902500000000; slots[14] = slots[5]; \n        return (BASE_FEE, BASE_FEE);\n    }\n\n    function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) {\n        uint256 prevBidFee = slots[0]; uint256 prevAskFee = slots[1]; uint256 lastTs = uint64(slots[2]);\n        uint256 dirState = slots[3]; uint256 actEma = slots[4]; uint256 pHat = slots[5];\n        uint256 sigmaHat = slots[6]; uint256 lambdaHat = slots[7]; uint256 sizeHat = slots[8];\n        uint256 toxEma = slots[9]; uint256 stepTradeCount = slots[10];\n\n        uint256 sigmaForFast = sigmaHat;\n        uint256 fastHat = slots[14];\n        uint256 uncertainty = slots[13];\n        uint256 silent = trade.timestamp > lastTs ? trade.timestamp - lastTs : 0;\n        bool isNewStep = trade.timestamp > lastTs;\n        if (isNewStep) {\n            uint256 elapsedRaw = trade.timestamp - lastTs;\n            uint256 elapsed = elapsedRaw > ELAPSED_CAP ? ELAPSED_CAP : elapsedRaw;\n            dirState = _decayCentered(dirState, DIR_DECAY, elapsed);\n            actEma = wmul(actEma, _powWad(ACT_DECAY, elapsed));\n            sizeHat = wmul(sizeHat, _powWad(SIZE_DECAY, elapsed));\n            toxEma = wmul(toxEma, _powWad(TOX_DECAY, elapsed));\n            if (stepTradeCount > 0 && elapsedRaw > 0) {\n                uint256 lambdaInst = (stepTradeCount * WAD) / elapsedRaw;\n                if (lambdaInst > LAMBDA_CAP) lambdaInst = LAMBDA_CAP;\n                lambdaHat = wmul(lambdaHat, LAMBDA_DECAY) + wmul(lambdaInst, WAD - LAMBDA_DECAY);\n            }\n            uncertainty += wmul(sigmaForFast, sigmaForFast) * elapsedRaw;\n            if (uncertainty > 100000000000000) uncertainty = 100000000000000;\n            stepTradeCount = 0;\n        }\n\n        bool firstInStep = stepTradeCount == 0;\n        uint256 spot = trade.reserveX > 0 ? wdiv(trade.reserveY, trade.reserveX) : pHat;\n        if (pHat == 0) pHat = spot;\n\n        uint256 feeUsed = trade.isBuy ? prevBidFee : prevAskFee;\n        uint256 gamma = feeUsed < WAD ? WAD - feeUsed : 0;\n        uint256 pImplied;\n        if (gamma == 0) { pImplied = spot; }\n        else { pImplied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma); }\n\n        // S: infer a no-trade interval center from the last post-trade spot.\n        uint256 silenceScale = WAD;\n        if (firstInStep && silent > 1) {\n            uint256 g = silent - 1;\n            if (g > 1) g = 1;\n            uint256 w = WAD - _powWad(800000000000000000, g);\n            uint256 s = slots[2] >> 64;\n            if (s == 0) s = pHat;\n            uint256 c = (wmul(s, WAD - prevBidFee) + wdiv(s, WAD - prevAskFee)) / 2;\n            if (c >= pHat) pHat += wmul(w, c - pHat);\n            else pHat -= wmul(w, pHat - c);\n            silenceScale = WAD - wmul(300000000000000000, w);\n        }\n\n        {\n            uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0;\n            uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL;\n            uint256 prePhat = pHat;\n            bool secondPrint = !firstInStep && stepTradeCount == 1;\n            bool sameDir = false; bool oppDir = false;\n            if (secondPrint) {\n                bool up2 = pImplied >= pHat;\n                uint256 d1 = slots[12];\n                if (d1 != 0) { sameDir = (d1 == 1) == up2; oppDir = !sameDir; }\n                if (sameDir) alpha = PHAT_ALPHA_SAME;\n            }\n            if (firstInStep) { slots[12] = pImplied >= pHat ? 1 : 2; }\n            uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT);\n            if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE;\n            alpha = wmul(alpha, silenceScale);\n            adaptiveGate = wmul(adaptiveGate, silenceScale);\n            if (ret <= adaptiveGate) { pHat = wmul(pHat, WAD - alpha) + wmul(pImplied, alpha); }\n            if (oppDir && REVERT_U > 0) {\n                uint256 pre = slots[11];\n                if (pre > pHat) pHat = pHat + wmul(pre - pHat, REVERT_U);\n                else pHat = pHat - wmul(pHat - pre, REVERT_U);\n            }\n            if (firstInStep) {\n                if (ret > RET_CAP) ret = RET_CAP;\n                sigmaHat = wmul(sigmaHat, SIGMA_DECAY) + wmul(ret, WAD - SIGMA_DECAY);\n            }\n        }\n\n        // Interior retail routing equalizes fee-adjusted marginal prices.\n        // Subsequent trades in a step cannot be the initial arbitrage trade.\n        if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) {\n            uint256 normalSpot = trade.isBuy\n                ? wdiv(wmul(spot, gamma), WAD - 30 * BPS)\n                : wdiv(wmul(spot, WAD - 30 * BPS), gamma);\n            pHat = wmul(pHat, 90 * WAD / 100) + wmul(normalSpot, 10 * WAD / 100);\n        }\n\n        {\n            uint256 ret = fastHat > 0 ? wdiv(absDiff(pImplied, fastHat), fastHat) : 0;\n            uint256 alpha;\n            if (firstInStep) {\n                uint256 processSigma = sigmaForFast;\n                uint256 obsVar = uncertainty + wmul(processSigma, processSigma);\n                uint256 probArb;\n                uint256 z2 = wdiv(wmul(ret, ret), obsVar);\n                uint256 density = _powWad(wdiv(WAD, WAD + z2 / 16), 8);\n                uint256 sigmaObs = _isqrt(obsVar * WAD);\n                uint256 odds = wmul(density, wdiv(6700000000000000, sigmaObs));\n                bool arbFlag = ret <= wmul(sigmaForFast, 1220000000000000000);\n                uint256 prior = arbFlag ? 650000000000000000 : 400000000000000000;\n                uint256 tr = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0;\n                if (tr > 3000000000000000) prior = wmul(prior, 6 * WAD / 10);\n                if (silent > 1) prior = wmul(prior, 8 * WAD / 10);\n                odds = wmul(odds, wdiv(prior, WAD - prior));\n                probArb = wdiv(odds, WAD + odds);\n                alpha = wmul(probArb, 600000000000000000) + wmul(WAD - probArb, 80000000000000000);\n                slots[15] = pImplied >= fastHat ? 1 : 2;\n                uncertainty = wmul(uncertainty, WAD - alpha);\n            } else {\n                if ((slots[15] == 1) == (pImplied >= fastHat)) alpha = PHAT_ALPHA_RETAIL;\n            }\n            uint256 gate = wmul(sigmaHat, GATE_SIGMA_MULT);\n            if (gate < MIN_GATE) gate = MIN_GATE;\n            if (ret <= gate) fastHat = wmul(fastHat, WAD - alpha) + wmul(pImplied, alpha);\n            slots[13] = uncertainty;\n        }\n\n        if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) {\n            uint256 normalObs = trade.isBuy\n                ? wdiv(wmul(spot, gamma), WAD - 30 * BPS)\n                : wdiv(wmul(spot, WAD - 30 * BPS), gamma);\n            if ((slots[15] == 1) == (normalObs >= fastHat)) {\n                fastHat = wmul(fastHat, 9 * WAD / 10) + wmul(normalObs, WAD / 10);\n            }\n        }\n        slots[14] = fastHat;\n        uint256 tradeRatio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0;\n        if (tradeRatio > TRADE_RATIO_CAP) tradeRatio = TRADE_RATIO_CAP;\n\n        if (tradeRatio > SIGNAL_THRESHOLD) {\n            uint256 push = tradeRatio * DIR_IMPACT_MULT;\n            if (push > WAD / 4) push = WAD / 4;\n            if (trade.isBuy) {\n                dirState = dirState + push;\n                if (dirState > 2 * WAD) dirState = 2 * WAD;\n            } else {\n                dirState = dirState > push ? dirState - push : 0;\n            }\n            actEma = wmul(actEma, ACT_BLEND_DECAY) + wmul(tradeRatio, WAD - ACT_BLEND_DECAY);\n            sizeHat = wmul(sizeHat, SIZE_BLEND_DECAY) + wmul(tradeRatio, WAD - SIZE_BLEND_DECAY);\n            if (sizeHat > WAD) sizeHat = WAD;\n        }\n\n        uint256 tox = pHat > 0 ? wdiv(absDiff(spot, pHat), pHat) : 0;\n        if (tox > TOX_CAP) tox = TOX_CAP;\n        toxEma = wmul(toxEma, TOX_BLEND_DECAY) + wmul(tox, WAD - TOX_BLEND_DECAY);\n        uint256 toxSignal = toxEma;\n\n        stepTradeCount = stepTradeCount + 1;\n        if (stepTradeCount > STEP_COUNT_CAP) stepTradeCount = STEP_COUNT_CAP;\n\n        uint256 flowSize = wmul(lambdaHat, sizeHat);\n        uint256 fBase = BASE_FEE + wmul(SIGMA_COEF, sigmaHat) + wmul(LAMBDA_COEF, lambdaHat) + wmul(FLOW_SIZE_COEF, flowSize);\n        uint256 fMid = fBase + wmul(TOX_COEF, toxSignal) + wmul(TOX_QUAD_COEF, wmul(toxSignal, toxSignal)) + wmul(ACT_COEF, actEma);\n        fMid = fMid + wmul(SIGMA_TOX_COEF, wmul(sigmaHat, toxSignal));\n\n        uint256 dirDev; bool sellPressure;\n        if (dirState >= WAD) { dirDev = dirState - WAD; sellPressure = true; }\n        else { dirDev = WAD - dirState; sellPressure = false; }\n\n        uint256 skew = wmul(DIR_COEF, dirDev) + wmul(DIR_TOX_COEF, wmul(dirDev, toxSignal));\n        uint256 bidFee; uint256 askFee;\n        if (sellPressure) {\n            bidFee = fMid + skew;\n            askFee = fMid > skew ? fMid - skew : 0;\n        } else {\n            askFee = fMid + skew;\n            bidFee = fMid > skew ? fMid - skew : 0;\n        }\n\n        {\n            uint256 staleHat = wmul(pHat, 700000000000000000) + wmul(fastHat, 300000000000000000);\n            uint256 staleTox = wdiv(absDiff(spot, staleHat), staleHat);\n            if (staleTox > TOX_CAP) staleTox = TOX_CAP;\n            uint256 staleShift = wmul(STALE_DIR_COEF, staleTox);\n            uint256 attractShift = wmul(staleShift, STALE_ATTRACT_FRAC);\n            if (spot >= staleHat) {\n                bidFee = bidFee + staleShift;\n                askFee = askFee > attractShift ? askFee - attractShift : 0;\n            } else {\n                askFee = askFee + staleShift;\n                bidFee = bidFee > attractShift ? bidFee - attractShift : 0;\n            }\n        }\n\n        {\n            bool tradeAligned = (trade.isBuy && spot >= pHat) || (!trade.isBuy && spot < pHat);\n            if (tradeAligned) {\n                uint256 tradeBoost = wmul(TRADE_TOX_BOOST, tradeRatio);\n                if (!firstInStep && tradeBoost > 16 * BPS) tradeBoost = 16 * BPS;\n                if (trade.isBuy) { bidFee = bidFee + tradeBoost; }\n                else { askFee = askFee + tradeBoost; }\n            }\n        }\n\n        if (sellPressure) {\n            bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_PROTECT));\n            askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_ATTRACT));\n        } else {\n            askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_PROTECT));\n            bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_ATTRACT));\n        }\n\n        if (firstInStep) {\n            if (askFee > bidFee && bidFee > 30 * BPS) bidFee = 30 * BPS;\n            else if (bidFee > askFee && askFee > 30 * BPS) askFee = 30 * BPS;\n        }\n\n        if (bidFee > askFee && askFee > 36 * BPS) askFee = 36 * BPS;\n        else if (askFee > bidFee && bidFee > 36 * BPS) bidFee = 36 * BPS;\n\n        slots[0] = bidFee; slots[1] = askFee; slots[2] = (spot << 64) | trade.timestamp;\n        slots[3] = dirState; slots[4] = actEma; slots[5] = pHat;\n        slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat;\n        slots[9] = toxEma; slots[10] = stepTradeCount;\n\n        return (bidFee, askFee);\n    }\n\n    function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) {\n        if (fee <= TAIL_KNEE) return fee;\n        return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope);\n    }\n\n    function _powWad(uint256 factor, uint256 exp) internal pure returns (uint256 result) {\n        result = WAD;\n        while (exp > 0) {\n            if (exp & 1 == 1) result = wmul(result, factor);\n            factor = wmul(factor, factor);\n            exp >>= 1;\n        }\n    }\n\n    function _decayCentered(uint256 centered, uint256 decayFactor, uint256 elapsed) internal pure returns (uint256) {\n        uint256 mul = _powWad(decayFactor, elapsed);\n        if (centered >= WAD) { return WAD + wmul(centered - WAD, mul); }\n        uint256 below = wmul(WAD - centered, mul);\n        return below < WAD ? WAD - below : 0;\n    }\n\n    // Floor square root: bit-length seed and seven Newton steps (all uint256).\n    function _isqrt(uint256 x) internal pure returns (uint256 r) {\n        if (x == 0) return 0;\n        unchecked {\n            uint256 y = x;\n            r = 1;\n            if (y >> 128 != 0) { y >>= 128; r <<= 64; }\n            if (y >> 64 != 0) { y >>= 64; r <<= 32; }\n            if (y >> 32 != 0) { y >>= 32; r <<= 16; }\n            if (y >> 16 != 0) { y >>= 16; r <<= 8; }\n            if (y >> 8 != 0) { y >>= 8; r <<= 4; }\n            if (y >> 4 != 0) { y >>= 4; r <<= 2; }\n            if (y >> 2 != 0) { r <<= 1; }\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            uint256 t = x / r;\n            return r < t ? r : t;\n        }\n    }\n\n    function getName() external pure override returns (string memory) { return \"no_cubic\"; }\n}\n",
 "sha256": "2eaafc7960e520b8a7fd322ec8afaff8fa677c730228a961efb509cc30b25719",
 "sha256_expected": "2eaafc7960e520b8a7fd322ec8afaff8fa677c730228a961efb509cc30b25719",
 "sha256_note": "sha256 of the UTF-8 'code' string from the artifact JSON (artifact file sha256 = c33720874aa1285e9dc766540b8a90410118a8e8b840d949ea0dcc211bdb27c1, matching its URL).",
 "calibration": {
  "strategy": "CH (ChengHua926/amm-challenge@d34a5199 contracts/src/Strategy.sol, file sha256 6dd68f77a70900319460215374143dbd5d924198450a46d9f5f91f6b1e3d35c3)",
  "seeds": [
   0,
   1000
  ],
  "n": 1000,
  "mean_edge": 525.5258821780834,
  "reference": 525.5258821780834,
  "residual": 0.0,
  "abs_error_ok_1e-6": true,
  "valid": true,
  "gas": {
   "max_ok": 151647,
   "oog": 0,
   "raw_totals": {
    "Baseline/afterInitialize": {
     "calls": 1000,
     "ok": 1000,
     "max_ok_gas": 21796,
     "sum_ok_gas": 21796000,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/afterSwap": {
     "calls": 10741746,
     "ok": 10741746,
     "max_ok_gas": 22592,
     "sum_ok_gas": 242365461576,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/getName": {
     "calls": 1000,
     "ok": 1000,
     "max_ok_gas": 21526,
     "sum_ok_gas": 21526000,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterInitialize": {
     "calls": 1000,
     "ok": 1000,
     "max_ok_gas": 185532,
     "sum_ok_gas": 185532000,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterSwap": {
     "calls": 10445223,
     "ok": 10445223,
     "max_ok_gas": 151647,
     "sum_ok_gas": 811927105393,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/getName": {
     "calls": 1000,
     "ok": 1000,
     "max_ok_gas": 21530,
     "sum_ok_gas": 21530000,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    }
   }
  },
  "seconds": 124.7,
  "chunk": 250
 },
 "paired": {
  "what": "STACK run A (1 chunk of 256) minus STACK run B (4 chunks of 64), seeds [10000,10256), tuning-only self-check",
  "n": 256,
  "mean_diff": 0.0,
  "se": 0.0,
  "sd": 0.0,
  "n_nonzero": 0,
  "worst": [
   {
    "seed": 10000,
    "diff": 0.0,
    "edge_a": 489.48996179664096,
    "edge_b": 489.48996179664096
   },
   {
    "seed": 10001,
    "diff": 0.0,
    "edge_a": 552.3971362057072,
    "edge_b": 552.3971362057072
   },
   {
    "seed": 10002,
    "diff": 0.0,
    "edge_a": 443.0561146234903,
    "edge_b": 443.0561146234903
   },
   {
    "seed": 10003,
    "diff": 0.0,
    "edge_a": 651.7615703992119,
    "edge_b": 651.7615703992119
   },
   {
    "seed": 10004,
    "diff": 0.0,
    "edge_a": 484.2497836681887,
    "edge_b": 484.2497836681887
   }
  ],
  "se_formula": "sd(paired diffs, ddof=1)/sqrt(n)"
 },
 "retail_edge_delta": {
  "mean": 0.0,
  "se": 0.0,
  "sd": 0.0
 },
 "arb_edge_delta": {
  "mean": 0.0,
  "se": 0.0,
  "sd": 0.0
 },
 "edge_reconciliation": {
  "max_abs(edge_diff - (arb_diff + retail_diff))": 0.0,
  "stack_abs_components_256": {
   "edge": {
    "mean": 523.2683436100853,
    "se": 6.0022367703383495
   },
   "arb_edge": {
    "mean": -28.12110155465501,
    "se": 1.644788358348502
   },
   "retail_edge": {
    "mean": 551.3894451647403,
    "se": 6.718302316731079
   }
  },
  "arb_volume_rebuilt_vs_reported": {
   "max_abs": 8.360799620277248e-05,
   "max_rel": 4.174892464576448e-09
  },
  "method": "The wheel's LightweightSimResult has no arb/retail edge fields (only edges, pnl, arb_volume_y, retail_volume_y, average_fees, steps). arb_edge is rebuilt per seed by re-running Arbitrageur.execute_arb (arbitrageur.rs) on the previous step's state: reserves from spot price and k=initial_x*initial_y (fees are bucketed so k is invariant up to float drift), fees = previous step's captured fees (step 0: STACK afterInitialize = (0.0004,0.0004)). retail_edge = edges['submission'] - arb_edge, so the two sum to the reported edge by construction; the independent check is that the rebuilt arb volume equals the reported arb_volume_y['submission']."
 },
 "determinism": {
  "per_seed_records_identical_A_vs_B": true,
  "mean_edge_A": 523.2683436100853,
  "mean_edge_B": 523.2683436100853,
  "gas_totals_identical_1x256_vs_4x64": true
 },
 "gas": {
  "STACK_run_A": {
   "max_ok": 211576,
   "oog": 0,
   "afterInitialize_max_ok": 220962,
   "raw_totals": {
    "Baseline/afterInitialize": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21796,
     "sum_ok_gas": 5579776,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/afterSwap": {
     "calls": 2749019,
     "ok": 2749019,
     "max_ok_gas": 22592,
     "sum_ok_gas": 62025990496,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/getName": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21526,
     "sum_ok_gas": 5510656,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterInitialize": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 220962,
     "sum_ok_gas": 56566272,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterSwap": {
     "calls": 2646095,
     "ok": 2646095,
     "max_ok_gas": 211576,
     "sum_ok_gas": 260444709544,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/getName": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21576,
     "sum_ok_gas": 5523456,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    }
   },
   "chunks": [
    {
     "seeds": [
      10000,
      10256
     ],
     "Submission/afterSwap": {
      "role": "Submission",
      "callback": "afterSwap",
      "calls": 2646095,
      "ok": 2646095,
      "max_ok_gas": 211576,
      "sum_ok_gas": 260444709544,
      "oog": 0,
      "revert": 0,
      "other_halt": 0,
      "tx_error": 0,
      "bad_return": 0
     }
    }
   ]
  },
  "STACK_run_B": {
   "max_ok": 211576,
   "oog": 0,
   "afterInitialize_max_ok": 220962,
   "raw_totals": {
    "Baseline/afterInitialize": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21796,
     "sum_ok_gas": 5579776,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/afterSwap": {
     "calls": 2749019,
     "ok": 2749019,
     "max_ok_gas": 22592,
     "sum_ok_gas": 62025990496,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Baseline/getName": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21526,
     "sum_ok_gas": 5510656,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterInitialize": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 220962,
     "sum_ok_gas": 56566272,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/afterSwap": {
     "calls": 2646095,
     "ok": 2646095,
     "max_ok_gas": 211576,
     "sum_ok_gas": 260444709544,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "Submission/getName": {
     "calls": 256,
     "ok": 256,
     "max_ok_gas": 21576,
     "sum_ok_gas": 5523456,
     "oog": 0,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    }
   },
   "chunks": [
    {
     "seeds": [
      10000,
      10064
     ],
     "Submission/afterSwap": {
      "role": "Submission",
      "callback": "afterSwap",
      "calls": 652958,
      "ok": 652958,
      "max_ok_gas": 211576,
      "sum_ok_gas": 64329331020,
      "oog": 0,
      "revert": 0,
      "other_halt": 0,
      "tx_error": 0,
      "bad_return": 0
     }
    },
    {
     "seeds": [
      10064,
      10128
     ],
     "Submission/afterSwap": {
      "role": "Submission",
      "callback": "afterSwap",
      "calls": 661337,
      "ok": 661337,
      "max_ok_gas": 209157,
      "sum_ok_gas": 65100381034,
      "oog": 0,
      "revert": 0,
      "other_halt": 0,
      "tx_error": 0,
      "bad_return": 0
     }
    },
    {
     "seeds": [
      10128,
      10192
     ],
     "Submission/afterSwap": {
      "role": "Submission",
      "callback": "afterSwap",
      "calls": 670029,
      "ok": 670029,
      "max_ok_gas": 209181,
      "sum_ok_gas": 65877609671,
      "oog": 0,
      "revert": 0,
      "other_halt": 0,
      "tx_error": 0,
      "bad_return": 0
     }
    },
    {
     "seeds": [
      10192,
      10256
     ],
     "Submission/afterSwap": {
      "role": "Submission",
      "callback": "afterSwap",
      "calls": 661771,
      "ok": 661771,
      "max_ok_gas": 211564,
      "sum_ok_gas": 65137387819,
      "oog": 0,
      "revert": 0,
      "other_halt": 0,
      "tx_error": 0,
      "bad_return": 0
     }
    }
   ]
  },
  "note": "max_ok = Submission/afterSwap max_ok_gas (limit 250000). Counters are reset with gas_stats_reset() before each run_batch chunk and snapshotted right after; chunk counts are summed and max_ok_gas taken as the max across chunks. Vanilla arm (Baseline role) also had 0 halts."
 },
 "negative_checks": {
  "oog_fixture": {
   "seeds": [
    10000,
    10016
   ],
   "chunk": 8,
   "result": {
    "valid": false,
    "Submission/afterSwap": {
     "oog": 18102,
     "revert": 0,
     "other_halt": 0,
     "tx_error": 0,
     "bad_return": 0
    },
    "per_chunk_oog": [
     8930,
     9172
    ],
    "afterSwap_max_ok": 22625,
    "mean_edge": null,
    "mean_edge_including_halted_run_not_a_score": 331.6740290718941
   },
   "paired_with_STACK": {
    "n": 0,
    "invalid": true,
    "reason": "halt in an arm; excluded from score metrics"
   },
   "note": "run_batch completes normally and returns edges for the halted run (cfmm.rs keeps the previous fees on afterSwap error), so the halt is only visible through gas_stats(). The harness marks the arm invalid, sets mean_edge null and refuses pairing (n=0)."
  },
  "gas_attribution_swap_seeds_10000_10004": {
   "STACK_first_arg": {
    "Submission_afterSwap_max": 182878,
    "Baseline_afterSwap_max": 22592
   },
   "STACK_second_arg_test_only": {
    "Submission_afterSwap_max": 22592,
    "Baseline_afterSwap_max": 182878
   },
   "gas_stats_after_reset": [],
   "conclusion": "role 'Submission' = run_batch first argument, 'Baseline' = second; edges key 'submission'/'normalizer' follow the same positions (engine.rs)."
  },
  "config_order": {
   "fields_compared_vs_MatchRunner._build_configs_seeds_0_999": 12000,
   "mismatches": 0,
   "seed10000_size_rate_sigma_order_matches": [
    true,
    true,
    true
   ],
   "sigma_first_order_would_match": false,
   "seed_plus_1_config_equal": false,
   "cfg_seed_10000": {
    "n_steps": 10000,
    "initial_price": 100.0,
    "initial_x": 100.0,
    "initial_y": 10000.0,
    "gbm_mu": 0.0,
    "gbm_sigma": 0.000954358735331156,
    "gbm_dt": 1.0,
    "retail_arrival_rate": 0.7694796610065723,
    "retail_mean_size": 20.033380804660926,
    "retail_size_sigma": 1.2,
    "retail_buy_prob": 0.5,
    "seed": 10000
   }
  },
  "decomposition_wrong_fee_timing": {
   "seeds": [
    10000,
    10001
   ],
   "correct_rel_err": [
    0.0,
    6.6e-15
   ],
   "wrong_timing_rel_err": [
    0.794,
    0.812
   ],
   "note": "Using the current step's fees instead of the previous step's breaks the arb-volume match, so the check discriminates."
  },
  "seed_order": "harness asserts result.seed == config seed for every result in every chunk (rayon into_par_iter().collect() preserves order); never tripped.",
  "seed_guard": "harness refuses hi > 5000000."
 },
 "validation_findings": [
  "Calibration: CH seeds 0..999 mean 525.5258821780834, residual 0.0 (exact float match).",
  "Determinism: two STACK runs on [10000,10256) with different chunking are bit-identical per seed (256/256 diffs exactly 0); paired n=256, mean_diff 0, se 0.",
  "DISCREPANCY/RISK (pinned source amm_sim_rs/src/amm/cfmm.rs update_fees): afterSwap errors (OOG, revert) are swallowed and the previous fees stay in force; result objects carry no halt flag. Halts must be read from gas_stats(); any harness that only reads edges would score a halting strategy silently.",
  "DISCREPANCY (not silently fixed): gas_stats()/gas_stats_reset() exist only in the 0.1.0.post1 wheel; the pinned Rust source at 6b6921f8 has no such functions (grep of amm_sim_rs/src finds none). Their behaviour was verified empirically (reset empties, attribution by argument position, chunk sums invariant, OOG fixture counted), not against source.",
  "gas_stats() is process-global (one table keyed by role/callback, not per batch or per seed). Per-arm/chunk isolation therefore requires reset before and snapshot after each run_batch, with no concurrent run_batch in the same process. Per-seed OOG attribution needs re-running a flagged chunk seed by seed.",
  "afterInitialize failure is not swallowed (engine.rs propagates with ?, run_batch raises RuntimeError), unlike afterSwap.",
  "STACK afterInitialize uses 220,962 gas (limit GAS_LIMIT_INIT 250,000), more than its afterSwap peak here (211,576 on these seeds). Brief's figure of a 214k afterSwap peak is from other seeds; consistent, not re-checked.",
  "Result fields have no arb/retail edge split; the split here is a rebuild from per-step data, verified against reported arb_volume_y (max rel err 4.2e-9 in batch, ~1e-15 in run_single).",
  "VanillaStrategy is compiled from the checkout by load_vanilla_strategy(); configs use BASELINE_SETTINGS/BASELINE_VARIANCE from amm_competition/competition/config.py (n_steps 10000, initial 100/100/10000, size U(19,21), rate U(0.6,1.0), sigma U(0.000882,0.001008)).",
  "Independent CH run via MatchRunner.run_match was not repeated (would duplicate the 2-minute run); equivalence rests on the 12,000-field config identity check plus identical run_batch call."
 ],
 "commands": [
  "git clone https://github.com/benedictbrady/amm-challenge && git checkout 6b6921f8d463314aa7c96234e1be25a25245f704",
  "sh scratch/setup.sh  (exact script from the brief; wheel sha256 aedb68280aca34c110968f00148387c95885207913fb2cf19a1ab4c5cfd6887a OK; 'StarterStrategy' validated successfully)",
  ". scratch/env.sh && python scratch/harness.py eval scratch/CH.sol 0 1000 scratch/out/ch.json --chunk 250",
  ". scratch/env.sh && python scratch/harness.py eval scratch/STACK.sol 10000 10256 scratch/out/stackA.json --chunk 256 --decompose",
  ". scratch/env.sh && python scratch/harness.py eval scratch/STACK.sol 10000 10256 scratch/out/stackB.json --chunk 64 --decompose",
  ". scratch/env.sh && python scratch/harness.py pair scratch/out/stackA.json scratch/out/stackB.json",
  ". scratch/env.sh && python scratch/check_configs.py; python scratch/check_gas.py; python scratch/check_decomp.py"
 ],
 "environment": {
  "simulator_commit": "6b6921f8d463314aa7c96234e1be25a25245f704",
  "amm_sim_rs": "0.1.0.post1 (prebuilt wheel, not rebuilt)",
  "python": "3.12.3",
  "numpy": "2.5.4",
  "py-solc-x": "2.1.0",
  "pyrevm": "0.3.7",
  "uv": "0.13.7",
  "solc": "0.8.24, optimizer runs 200, viaIR, evmVersion paris (amm_competition/evm/compiler.py)",
  "run_batch_workers": 8,
  "machine_cpus": 6,
  "steps": 10000,
  "afterSwap_gas_limit": 250000,
  "timing": "CH 1000 seeds 124.7 s; STACK 256 seeds ~47 s incl. decomposition"
 },
 "harness_files": {
  "scratch/harness.py": {
   "sha256": "19007f366f12e2d19660b21cef1a8da109882c7d7c93ecf7d0674a3ba048e499",
   "source": "\"\"\"Paired evaluator: each strategy alone vs VanillaStrategy (amm_sim_rs post1 wheel).\n\nUsage (from checkout root, after `. scratch/env.sh`):\n  python scratch/harness.py eval SRC.sol LO HI OUT.json [--chunk N] [--decompose]\n  python scratch/harness.py pair A.json B.json            (paired stats over shared seeds)\nSeeds are the half-open range [LO, HI). Configs replicate MatchRunner._build_configs\nper seed: default_rng(seed) draws retail_mean_size, retail_arrival_rate, gbm_sigma in that\norder; the engine uses price seed=seed, retail seed=seed+1 (engine.rs).\n\"\"\"\nimport hashlib, json, math, sys, time\nfrom decimal import Decimal\nimport numpy as np\nimport amm_sim_rs\nfrom amm_competition.competition.config import BASELINE_SETTINGS as S, BASELINE_VARIANCE as V\nfrom amm_competition.evm.baseline import load_vanilla_strategy\nfrom amm_competition.evm.compiler import SolidityCompiler\nfrom amm_competition.evm.validator import SolidityValidator\nfrom amm_competition.evm.adapter import EVMStrategyAdapter\n\nN_WORKERS = 8\nBAD = (\"oog\", \"revert\", \"other_halt\", \"tx_error\", \"bad_return\")\n\n\ndef build_config(seed):\n    rng = np.random.default_rng(seed=seed)\n    size = rng.uniform(V.retail_mean_size_min, V.retail_mean_size_max)\n    rate = rng.uniform(V.retail_arrival_rate_min, V.retail_arrival_rate_max)\n    sigma = rng.uniform(V.gbm_sigma_min, V.gbm_sigma_max)\n    return amm_sim_rs.SimulationConfig(\n        n_steps=S.n_steps, initial_price=S.initial_price, initial_x=S.initial_x,\n        initial_y=S.initial_y, gbm_mu=S.gbm_mu, gbm_sigma=sigma, gbm_dt=S.gbm_dt,\n        retail_arrival_rate=rate, retail_mean_size=size,\n        retail_size_sigma=S.retail_size_sigma, retail_buy_prob=S.retail_buy_prob, seed=seed)\n\n\ndef compile_source(src):\n    v = SolidityValidator().validate(src)\n    if not v.valid:\n        raise RuntimeError(f\"validation failed: {v.errors}\")\n    c = SolidityCompiler().compile(src)\n    if not c.success:\n        raise RuntimeError(f\"compile failed: {c.errors}\")\n    return c.bytecode, c.abi\n\n\ndef snapshot_gas():\n    out = {}\n    for row in amm_sim_rs.gas_stats():\n        out[(row[\"role\"], row[\"callback\"])] = dict(row)\n    return out\n\n\ndef merge_gas(total, chunk):\n    for key, row in chunk.items():\n        t = total.setdefault(key, {k: 0 for k in row if k not in (\"role\", \"callback\")})\n        for k, v in row.items():\n            if k in (\"role\", \"callback\"):\n                continue\n            t[k] = max(t[k], v) if k.startswith(\"max\") else t[k] + v\n\n\ndef fee_clamp(w):\n    return min(max(w, 0), 10**17) / 1e18\n\n\ndef arb_leg(spot, fees, prices, k, fee0):\n    \"\"\"Re-run Arbitrageur.execute_arb on the state left by the previous step.\n\n    Reserves are recovered from spot price and k (fees are bucketed, k is invariant\n    up to float drift); fees in force are those captured at the end of the previous step.\n    Returns (arb_edge, arb_volume_y) for one AMM over the whole run.\n    \"\"\"\n    edge = vol = 0.0\n    prev_p, (bid, ask) = S.initial_y / S.initial_x, fee0\n    for t in range(len(prices)):\n        rx, ry = math.sqrt(k / prev_p), math.sqrt(k * prev_p)\n        p = prices[t]\n        if prev_p < p:\n            g = 1.0 - ask\n            ax = min(rx - math.sqrt(k / (g * p)), rx * 0.99)\n            if ax > 0 and ax < rx:\n                ty = (k / (rx - ax) - ry) / g\n                pr = ax * p - ty\n                if ty > 0 and pr > 0:\n                    edge -= pr; vol += ty\n        elif prev_p > p:\n            g = 1.0 - bid\n            ax = (math.sqrt(k * g / p) - rx) / g\n            if ax > 0:\n                yo = ry - k / (rx + ax * g)\n                pr = yo - ax * p\n                if yo > 0 and pr > 0:\n                    edge -= pr; vol += yo\n        prev_p = spot[t]\n        bid, ask = fees[t]\n    return edge, vol\n\n\ndef decompose(res, fee0):\n    steps = res.steps\n    prices = [s.fair_price for s in steps]\n    spot = [s.spot_prices[\"submission\"] for s in steps]\n    fees = [s.fees[\"submission\"] for s in steps]\n    k = S.initial_x * S.initial_y\n    arb_edge, arb_vol = arb_leg(spot, fees, prices, k, fee0)\n    total = res.edges[\"submission\"]\n    return {\"arb_edge\": arb_edge, \"retail_edge\": total - arb_edge,\n            \"arb_vol_rebuilt\": arb_vol, \"arb_vol_reported\": res.arb_volume_y[\"submission\"]}\n\n\ndef evaluate(src, lo, hi, chunk=256, want_decompose=False):\n    bytecode, abi = compile_source(src)\n    vanilla = load_vanilla_strategy()\n    fee0 = None\n    if want_decompose:\n        a = EVMStrategyAdapter(bytecode=bytecode, abi=abi)\n        q = a.after_initialize(Decimal(str(S.initial_x)), Decimal(str(S.initial_y)))\n        fee0 = (float(q.bid_fee), float(q.ask_fee))\n    per_seed, gas_total, gas_chunks = [], {}, []\n    t0 = time.time()\n    for c_lo in range(lo, hi, chunk):\n        seeds = list(range(c_lo, min(hi, c_lo + chunk)))\n        configs = [build_config(s) for s in seeds]\n        amm_sim_rs.gas_stats_reset()\n        if amm_sim_rs.gas_stats():\n            raise RuntimeError(\"gas_stats not empty after reset\")\n        batch = amm_sim_rs.run_batch(list(bytecode), list(vanilla._bytecode), configs, N_WORKERS)\n        g = snapshot_gas()\n        gas_chunks.append({\"seeds\": [seeds[0], seeds[-1] + 1],\n                           \"rows\": {f\"{r}/{c}\": v for (r, c), v in g.items()}})\n        merge_gas(gas_total, g)\n        if len(batch.results) != len(seeds):\n            raise RuntimeError(\"result count mismatch\")\n        for s, r in zip(seeds, batch.results):\n            if r.seed != s:\n                raise RuntimeError(f\"seed order mismatch {r.seed} != {s}\")\n            row = {\"seed\": s, \"edge\": r.edges[\"submission\"], \"edge_vanilla\": r.edges[\"normalizer\"],\n                   \"pnl\": r.pnl[\"submission\"], \"retail_vol\": r.retail_volume_y[\"submission\"],\n                   \"arb_vol\": r.arb_volume_y[\"submission\"]}\n            if want_decompose:\n                row.update(decompose(r, fee0))\n            per_seed.append(row)\n        del batch\n    halts = {f\"{r}/{c}\": {k: v[k] for k in BAD} for (r, c), v in gas_total.items()\n             if any(v[k] for k in BAD)}\n    sub_swap = gas_total.get((\"Submission\", \"afterSwap\"), {})\n    return {\n        \"source_sha256\": hashlib.sha256(src.encode()).hexdigest(),\n        \"seeds\": [lo, hi], \"n\": len(per_seed), \"chunk\": chunk, \"workers\": N_WORKERS,\n        \"seconds\": round(time.time() - t0, 1),\n        \"valid\": not halts, \"halts\": halts,\n        \"mean_edge\": (sum(r[\"edge\"] for r in per_seed) / len(per_seed)) if not halts else None,\n        \"mean_edge_including_halted_run\": sum(r[\"edge\"] for r in per_seed) / len(per_seed),\n        \"gas\": {\"afterSwap_max_ok\": sub_swap.get(\"max_ok_gas\"),\n                \"oog\": sum(v[\"oog\"] for (r, c), v in gas_total.items() if r == \"Submission\"),\n                \"totals\": {f\"{r}/{c}\": v for (r, c), v in gas_total.items()},\n                \"chunks\": gas_chunks},\n        \"per_seed\": per_seed,\n    }\n\n\ndef paired(a, b):\n    if not (a[\"valid\"] and b[\"valid\"]):\n        return {\"n\": 0, \"invalid\": True, \"reason\": \"halt in an arm; excluded from score metrics\"}\n    ea = {r[\"seed\"]: r for r in a[\"per_seed\"]}\n    eb = {r[\"seed\"]: r for r in b[\"per_seed\"]}\n    seeds = sorted(set(ea) & set(eb))\n    if len(seeds) != len(ea) or len(seeds) != len(eb):\n        raise RuntimeError(\"arms cover different seeds; refusing to drop any\")\n\n    def stat(key):\n        d = [ea[s][key] - eb[s][key] for s in seeds]\n        n = len(d); m = sum(d) / n\n        sd = math.sqrt(sum((x - m) ** 2 for x in d) / (n - 1)) if n > 1 else 0.0\n        return d, {\"mean\": m, \"se\": sd / math.sqrt(n), \"sd\": sd}\n\n    d, st = stat(\"edge\")\n    worst = sorted(zip(d, seeds))[:5]\n    out = {\"n\": len(seeds), \"mean_diff\": st[\"mean\"], \"se\": st[\"se\"], \"sd\": st[\"sd\"],\n           \"n_nonzero\": sum(1 for x in d if x != 0.0),\n           \"worst\": [{\"seed\": s, \"diff\": x, \"edge_a\": ea[s][\"edge\"], \"edge_b\": eb[s][\"edge\"]}\n                     for x, s in worst]}\n    if \"arb_edge\" in a[\"per_seed\"][0] and \"arb_edge\" in b[\"per_seed\"][0]:\n        _, out[\"arb_edge_delta\"] = stat(\"arb_edge\")\n        _, out[\"retail_edge_delta\"] = stat(\"retail_edge\")\n        out[\"reconcile_max_abs\"] = max(abs((ea[s][\"edge\"] - eb[s][\"edge\"]) -\n                                           ((ea[s][\"arb_edge\"] - eb[s][\"arb_edge\"]) +\n                                            (ea[s][\"retail_edge\"] - eb[s][\"retail_edge\"])))\n                                       for s in seeds)\n    return out\n\n\nif __name__ == \"__main__\":\n    cmd = sys.argv[1]\n    if cmd == \"eval\":\n        src = open(sys.argv[2]).read()\n        lo, hi, out = int(sys.argv[3]), int(sys.argv[4]), sys.argv[5]\n        chunk = int(sys.argv[sys.argv.index(\"--chunk\") + 1]) if \"--chunk\" in sys.argv else 256\n        if hi > 5_000_000:\n            raise SystemExit(\"seeds >= 5000000 are reserved for confirmation\")\n        r = evaluate(src, lo, hi, chunk, \"--decompose\" in sys.argv)\n        json.dump(r, open(out, \"w\"))\n        print(json.dumps({k: r[k] for k in (\"n\", \"valid\", \"halts\", \"mean_edge\", \"seconds\")}),\n              json.dumps({k: r[\"gas\"][k] for k in (\"afterSwap_max_ok\", \"oog\")}))\n    elif cmd == \"pair\":\n        a, b = json.load(open(sys.argv[2])), json.load(open(sys.argv[3]))\n        print(json.dumps(paired(a, b), indent=1))\n"
  },
  "scratch/OOGFixture.sol": {
   "sha256": "6c915acc62a90c283fddecedd5a6c6e4b35a28e4e1c4e39ddecbe66b597c78ff",
   "source": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {AMMStrategyBase} from \"./AMMStrategyBase.sol\";\nimport {TradeInfo} from \"./IAMMStrategy.sol\";\n\n/// Intentional-OOG fixture: 30 bps, but every afterSwap whose timestamp % 10 == 0\n/// burns far more than the 250,000 afterSwap gas limit.\ncontract Strategy is AMMStrategyBase {\n    uint256 constant FEE = 30 * BPS;\n\n    function afterInitialize(uint256, uint256) external pure override returns (uint256, uint256) {\n        return (FEE, FEE);\n    }\n\n    function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) {\n        if (trade.timestamp % 10 == 0) {\n            for (uint256 i = 0; i < 20000; i++) {\n                slots[i % 32] = slots[i % 32] + i + 1;\n            }\n        }\n        return (FEE, FEE);\n    }\n\n    function getName() external pure override returns (string memory) {\n        return \"OOGFixture\";\n    }\n}\n"
  },
  "scratch/check_configs.py": {
   "sha256": "ff23b31e32e89f62e08bffc4c40468b273293f50035873e42a73abb49439d2a1",
   "source": "import sys, numpy as np\nsys.path.insert(0, \"scratch\")\nfrom harness import build_config\nfrom amm_competition.competition.match import MatchRunner\nfrom amm_competition.competition.config import BASELINE_VARIANCE, build_base_config\nF = [\"n_steps\", \"initial_price\", \"initial_x\", \"initial_y\", \"gbm_mu\", \"gbm_sigma\", \"gbm_dt\",\n     \"retail_arrival_rate\", \"retail_mean_size\", \"retail_size_sigma\", \"retail_buy_prob\", \"seed\"]\nref = MatchRunner(n_simulations=1000, config=build_base_config(seed=None), n_workers=8,\n                  variance=BASELINE_VARIANCE)._build_configs()\nmism = sum(1 for i, c in enumerate(ref) for f in F if getattr(c, f) != getattr(build_config(i), f))\nprint(\"fields_compared\", len(ref) * len(F), \"mismatches\", mism)\nx = build_config(10000)\nrng = np.random.default_rng(seed=10000)\na, b, c = rng.uniform(19, 21), rng.uniform(0.6, 1.0), rng.uniform(0.000882, 0.001008)\nprint(\"seed10000 size,rate,sigma order matches:\", x.retail_mean_size == a, x.retail_arrival_rate == b, x.gbm_sigma == c)\nrng = np.random.default_rng(seed=10000)\nprint(\"negative: sigma-first order would give same sigma:\", rng.uniform(0.000882, 0.001008) == x.gbm_sigma)\nprint(\"negative: seed+1 config equals seed config:\", build_config(10001).gbm_sigma == x.gbm_sigma)\nprint(\"cfg10000\", {f: getattr(x, f) for f in F})\n"
  },
  "scratch/check_gas.py": {
   "sha256": "e84447556fc7a18ce1a61558363d99c7fac36cc6601312dba0628c2e82db3756",
   "source": "import sys, json, amm_sim_rs\nsys.path.insert(0, \"scratch\")\nfrom harness import build_config, compile_source, snapshot_gas, evaluate, paired\nfrom amm_competition.evm.baseline import load_vanilla_strategy\nstack, _ = compile_source(open(\"scratch/STACK.sol\").read())\nvan = list(load_vanilla_strategy()._bytecode)\ncfgs = [build_config(s) for s in range(10000, 10004)]\ndef run(a, b):\n    amm_sim_rs.gas_stats_reset()\n    r = amm_sim_rs.run_batch(a, b, cfgs, 8)\n    g = snapshot_gas()\n    return {k: g[(k, \"afterSwap\")][\"max_ok_gas\"] for k in (\"Submission\", \"Baseline\")}, \\\n           [round(x.edges[\"submission\"], 6) for x in r.results]\nprint(\"STACK as submission:\", run(list(stack), van))\nprint(\"STACK as baseline (swap test only):\", run(van, list(stack)))\namm_sim_rs.gas_stats_reset(); print(\"after reset:\", amm_sim_rs.gas_stats())\n# intentional-OOG fixture\nfx = evaluate(open(\"scratch/OOGFixture.sol\").read(), 10000, 10016, chunk=8)\nprint(\"fixture:\", json.dumps({k: fx[k] for k in (\"n\", \"valid\", \"halts\", \"mean_edge\", \"mean_edge_including_halted_run\")}),\n      json.dumps({k: fx[\"gas\"][k] for k in (\"afterSwap_max_ok\", \"oog\")}),\n      \"chunk_oog:\", [c[\"rows\"][\"Submission/afterSwap\"][\"oog\"] for c in fx[\"gas\"][\"chunks\"]])\nst = json.load(open(\"scratch/out/stackA.json\"))\nprint(\"pair(fixture, STACK):\", paired(fx, st))\n"
  },
  "scratch/check_decomp.py": {
   "sha256": "1d5e465eb85ad8de65af6f5ecfc258a4548136cee4891d1ffb4fd50ab6152a1d",
   "source": "import sys, amm_sim_rs\nfrom decimal import Decimal\nsys.path.insert(0, \"scratch\")\nfrom harness import build_config, compile_source, arb_leg, S\nfrom amm_competition.evm.baseline import load_vanilla_strategy\nfrom amm_competition.evm.adapter import EVMStrategyAdapter\nbc, abi = compile_source(open(\"scratch/STACK.sol\").read())\nq = EVMStrategyAdapter(bytecode=bc, abi=abi).after_initialize(Decimal(\"100\"), Decimal(\"10000\"))\nfee0 = (float(q.bid_fee), float(q.ask_fee))\nprint(\"fee0\", fee0)\nvan = list(load_vanilla_strategy()._bytecode)\nfor s in (10000, 10001):\n    r = amm_sim_rs.run_single(list(bc), van, build_config(s))\n    P = [x.fair_price for x in r.steps]; sp = [x.spot_prices[\"submission\"] for x in r.steps]\n    fe = [x.fees[\"submission\"] for x in r.steps]\n    rep = r.arb_volume_y[\"submission\"]\n    _, ok = arb_leg(sp, fe, P, 1e6, fee0)\n    # wrong: fees of the current step (set after this step's trades) instead of previous step\n    _, bad = arb_leg(sp, fe[1:] + fe[-1:], P, 1e6, fe[0])\n    print(s, \"correct_rel_err\", abs(ok - rep) / rep, \"wrong_timing_rel_err\", abs(bad - rep) / rep)\n"
  }
 }
}