{"item":"a1","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[2] = 0; slots[3] = WAD; slots[4] = 0;\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]; slots[15] = 0; slots[9] = 0; slots[10] = 0; slots[11] = 0; slots[12] = 0;\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 = 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[16];\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[11] = pHat; 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 = sqrt(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        // Timestamp/count identify the first observed print, not the end of the step.\n        // Linearized two-pool router share: s(f) = 1/2 + (30bps-f)/(4*size).\n        // max f*s(f)*flow gives f = 15bps + size at equal prices.\n        uint256 retailMid = 15 * BPS + wmul(sizeHat, 500000000000000000);\n        // Later prints use a volatility premium and expected arrival flow instead.\n        uint256 arbMid = 4 * BPS + wmul(sigmaHat, 700000000000000000) + wmul(wmul(lambdaHat,sizeHat), 4842 * BPS);\n        uint256 mid = 28 * BPS;\n        uint256 estimate = wmul(pHat, 7 * WAD / 10) + wmul(fastHat, 3 * WAD / 10);\n        uint256 gap = wdiv(absDiff(spot, estimate), estimate);\n        if (gap > TOX_CAP) gap = TOX_CAP;\n        uint256 shift = wmul(gap, 800000000000000000);\n        uint256 bidFee;\n        uint256 askFee;\n        if (spot >= estimate) { bidFee = mid + shift; askFee = mid > shift ? mid - shift : 0; }\n        else { askFee = mid + shift; bidFee = mid > shift ? mid - shift : 0; }\n        bidFee = clampFee(bidFee); askFee = clampFee(askFee);\n\n        slots[0] = bidFee; slots[1] = askFee; slots[2] = trade.timestamp;\n        slots[3] = dirState; slots[4] = actEma; slots[5] = pHat;\n        slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat;\n        slots[16] = spot;\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    function getName() external pure override returns (string memory) { return \"no_cubic\"; }\n}\n","sha256":"2ba9d99e5dd76da1dbfd3152136ac6531899dba8ca66d479ec69d3fbf22c8b6f","input_sources":{"recovery":"https://api.imd.fun/artifacts/372e7282ee336f557b6861ecc8ef6730b4e65b637c6f8018c1d3127c1ecabc9f","audit":"https://api.imd.fun/artifacts/02c134d9ed51858f06d02b6dec25e6922016490f11e3a8174af512a6a77b6569","rules":"https://api.imd.fun/artifacts/ddbbaac58282566e0505d895c83daf348487cc322e8c482e61d4d87e6e4628de","prior":"https://api.imd.fun/artifacts/f5de2d1e4002e37761d90e15463ba72b437ee3a948eb8d142f18f0f7740d92a1"},"tuning":{"screen":[{"name":"original","paired":{"n":256,"mean_diff":-20.769367115588118,"se":0.2449741301786319,"worst":[{"seed":10237,"diff":-31.777844374863548},{"seed":10121,"diff":-31.14201729150625},{"seed":10025,"diff":-30.09615285046482},{"seed":10254,"diff":-29.49928039202109},{"seed":10253,"diff":-28.87916583232868}]},"valid":true,"gas":{"max_ok":241989,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236407,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2556886,"ok":2556886,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2712204,"ok":2712197,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"68cc95b39e04f78af6975f5fbc0781e2edbf644d4fc427ab192d64723bc33f0a","edge_decomposition":{"candidate":{"edge":502.44594660327806,"retail_edge":542.7860421514848,"arb_edge":-40.340095548206705,"retail_volume":80706.28658036445,"arb_volume":27599.704771942266},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-16.729558469878388,"se":0.17927743628090653,"tercile":1,"retail_edge_diff":-6.692895646874778,"arb_edge_diff":-10.036662823003498,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-20.992003108330582,"se":0.23796460235927566,"tercile":2,"retail_edge_diff":-8.61449218402286,"arb_edge_diff":-12.377510924308169,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-24.63406692909314,"se":0.29013921386242825,"tercile":3,"retail_edge_diff":-10.358562038230602,"arb_edge_diff":-14.275504890862257,"v2_retail_volume":87648.18951565126}]},{"name":"m28s6","paired":{"n":256,"mean_diff":-24.45926982212321,"se":0.44805540795010196,"worst":[{"seed":10237,"diff":-45.49398426264884},{"seed":10199,"diff":-42.52757865747435},{"seed":10067,"diff":-41.68387731113501},{"seed":10144,"diff":-41.47574767256776},{"seed":10025,"diff":-40.71051178835933}]},"valid":true,"gas":{"max_ok":241951,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236398,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2743539,"ok":2743539,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2888444,"ok":2888437,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"60e7c11c4096862d6266408c284b275eec4145b78b546b74d42dbb364ddfb035","edge_decomposition":{"candidate":{"edge":498.75604389674294,"retail_edge":567.5432544791199,"arb_edge":-68.78721058237696,"retail_volume":81409.0221704229,"arb_volume":31253.350135390454},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-18.90396586813232,"se":0.5145216579970509,"tercile":1,"retail_edge_diff":11.527881242353278,"arb_edge_diff":-30.431847110485464,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-25.14429120170526,"se":0.6089044022791196,"tercile":2,"retail_edge_diff":16.189568501437343,"arb_edge_diff":-41.3338597031429,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-29.39490891363782,"se":0.7254991313998447,"tercile":3,"retail_edge_diff":20.965136610437966,"arb_edge_diff":-50.3600455240762,"v2_retail_volume":87648.18951565126}]},{"name":"m28s8","paired":{"n":256,"mean_diff":-6.645463448511675,"se":0.12537143684566646,"worst":[{"seed":10081,"diff":-13.656341435442187},{"seed":10019,"diff":-13.12980088982215},{"seed":10144,"diff":-12.544067069548873},{"seed":10165,"diff":-12.129005718398048},{"seed":10067,"diff":-11.747956586764985}]},"valid":true,"gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2781636,"ok":2781636,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2511351,"ok":2511344,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"2ba9d99e5dd76da1dbfd3152136ac6531899dba8ca66d479ec69d3fbf22c8b6f","edge_decomposition":{"candidate":{"edge":516.5698502703544,"retail_edge":549.7758289827517,"arb_edge":-33.205978712397254,"retail_volume":74085.61546049877,"arb_volume":21330.121384367703},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-5.641850220906022,"se":0.1501991449111901,"tercile":1,"retail_edge_diff":-2.992996332352499,"arb_edge_diff":-2.648853888553567,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-6.893379126567739,"se":0.20181384531385285,"tercile":2,"retail_edge_diff":-1.5685360903403194,"arb_edge_diff":-5.324843036227749,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-7.412968212503684,"se":0.2449597581994096,"tercile":3,"retail_edge_diff":-0.09635239361433806,"arb_edge_diff":-7.316615818889453,"v2_retail_volume":87648.18951565126}]},{"name":"m32s6","paired":{"n":256,"mean_diff":-25.025387665426738,"se":0.4071139728441854,"worst":[{"seed":10237,"diff":-44.02946404291856},{"seed":10078,"diff":-42.06106375542788},{"seed":10067,"diff":-41.640412430518154},{"seed":10144,"diff":-41.00368366397936},{"seed":10025,"diff":-39.98376024833567}]},"valid":true,"gas":{"max_ok":241951,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236398,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2851553,"ok":2851553,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2641601,"ok":2641594,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"1357c3b7dd6e8eee4c003995d7c826864c24ae0574ae3d820046b447697bd66a","edge_decomposition":{"candidate":{"edge":498.1899260534394,"retail_edge":560.29685423604,"arb_edge":-62.106928182600356,"retail_volume":75182.33046183009,"arb_volume":27160.731728809427},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-20.023718648600187,"se":0.467734868069444,"tercile":1,"retail_edge_diff":4.619100843066897,"arb_edge_diff":-24.64281949166722,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-25.75465357889923,"se":0.5523706489474589,"tercile":2,"retail_edge_diff":8.917152163264854,"arb_edge_diff":-34.67180574216406,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-29.356633933684638,"se":0.674739052769645,"tercile":3,"retail_edge_diff":13.403160620494655,"arb_edge_diff":-42.75979455417922,"v2_retail_volume":87648.18951565126}]},{"name":"m32s8","paired":{"n":256,"mean_diff":-8.804329875249582,"se":0.12974206905305857,"worst":[{"seed":10144,"diff":-14.968438222261511},{"seed":10219,"diff":-14.540741586807883},{"seed":10019,"diff":-14.260221116899856},{"seed":10011,"diff":-13.955070339032773},{"seed":10177,"diff":-13.848567279509325}]},"valid":true,"gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2862146,"ok":2862146,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2279809,"ok":2279802,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"15f32018a2bf14a842d7d0a8f738c4d5d4b8c82b1bf4f83bb6a00bd85a14ef70","edge_decomposition":{"candidate":{"edge":514.4109838436166,"retail_edge":543.9502985429671,"arb_edge":-29.53931469935045,"retail_volume":68999.33810794912,"arb_volume":18187.11138366247},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-8.064351631432025,"se":0.172551326471954,"tercile":1,"retail_edge_diff":-8.650784766248158,"arb_edge_diff":0.5864331348159705,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-9.048264779207576,"se":0.21255102558480501,"tercile":2,"retail_edge_diff":-7.446315870527729,"arb_edge_diff":-1.6019489086802734,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-9.309078841507002,"se":0.2605843820805044,"tercile":3,"retail_edge_diff":-6.0393489342487765,"arb_edge_diff":-3.2697299072580766,"v2_retail_volume":87648.18951565126}]},{"name":"m36s8","paired":{"n":256,"mean_diff":-12.423942146523203,"se":0.1499654658669089,"worst":[{"seed":10101,"diff":-19.284716660266156},{"seed":10067,"diff":-18.630418976180408},{"seed":10001,"diff":-18.49591339847393},{"seed":10084,"diff":-18.430653220665818},{"seed":10219,"diff":-18.14483958184337}]},"valid":true,"gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389,"call_counts":[{"role":"Baseline","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Baseline","callback":"afterSwap","calls":2906057,"ok":2906057,"oog":0,"other_errors":0},{"role":"Baseline","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"oog":0,"other_errors":0},{"role":"Submission","callback":"afterSwap","calls":2037427,"ok":2037420,"oog":7,"other_errors":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"oog":0,"other_errors":0}]},"sha256":"7153e74533ee636c3441e8b4ab8cdd88cc043efbc1e2a8efe9e5befbab68bbc6","edge_decomposition":{"candidate":{"edge":510.791371572343,"retail_edge":537.263440201101,"arb_edge":-26.472068628758123,"retail_volume":64360.48538588117,"arb_volume":15480.572297116674},"V2":{"edge":523.2153137188661,"retail_edge":551.3340836925895,"arb_edge":-28.11876997372316,"retail_volume":76160.11993119739,"arb_volume":22397.16805382091}},"by_v2_retail_volume_tercile":[{"n":86,"mean_diff":-11.934760584678727,"se":0.21716583489651747,"tercile":1,"retail_edge_diff":-15.15604705639853,"arb_edge_diff":3.221286471719772,"v2_retail_volume":64427.690148025016},{"n":85,"mean_diff":-12.705595952504417,"se":0.2610433269056143,"tercile":2,"retail_edge_diff":-14.174756622500773,"arb_edge_diff":1.4691606699962905,"v2_retail_volume":76542.50871560028},{"n":85,"mean_diff":-12.637224979584634,"se":0.2912453146491779,"tercile":3,"retail_edge_diff":-12.868357341860792,"arb_edge_diff":0.23113236227604433,"v2_retail_volume":87648.18951565126}]}]},"freeze":null,"seed_ranges":{"screen":[10000,10255],"second_stage":[12000,12511],"confirmation":[4170000,4171999]},"paired":{"n":0,"mean_diff":null,"se":null,"worst":[]},"gas":{"candidate":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389,"call_counts":[{"role":"Baseline","callback":"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},{"role":"Baseline","callback":"afterSwap","calls":2781636,"ok":2781636,"max_ok_gas":22592,"sum_ok_gas":62761977720,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Baseline","callback":"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},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"max_ok_gas":236389,"sum_ok_gas":60515584,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Submission","callback":"afterSwap","calls":2511351,"ok":2511344,"max_ok_gas":241852,"sum_ok_gas":276333367753,"oog":7,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"max_ok_gas":21557,"sum_ok_gas":5518592,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0}]},"V2":{"max_ok":243554,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236377,"call_counts":[{"role":"Baseline","callback":"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},{"role":"Baseline","callback":"afterSwap","calls":2749671,"ok":2749671,"max_ok_gas":22592,"sum_ok_gas":62040662676,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Baseline","callback":"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},{"role":"Submission","callback":"afterInitialize","calls":256,"ok":256,"max_ok_gas":236377,"sum_ok_gas":60512512,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Submission","callback":"afterSwap","calls":2644187,"ok":2644180,"max_ok_gas":243554,"sum_ok_gas":294618218760,"oog":7,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},{"role":"Submission","callback":"getName","calls":256,"ok":256,"max_ok_gas":21545,"sum_ok_gas":5515520,"oog":0,"revert":0,"other_halt":0,"tx_error":0,"bad_return":0}]}},"valid":false,"blocked":{"step":"runtime-budget preflight after complete six-variant screen","error":"The remaining top-two stage plus one 2000-seed paired confirmation cannot fit the item cap of <60 minutes at measured throughput. Stopped before those stages rather than consume a partial fresh confirmation block. paired.n=0 denotes no completed confirmation; complete 256-seed tuning comparisons are retained."},"method":{"repository":"https://github.com/benedictbrady/amm-challenge","commit":"6b6921f8d463314aa7c96234e1be25a25245f704","n_steps":10000,"gas_limit":250000,"workers":8,"batch_size":16,"config":"For each requested seed only: numpy.random.default_rng(seed), draws uniform size(19,21), rate(0.6,1.0), sigma(0.000882,0.001008), in that order. build_config(seed=seed); engine price seed=seed and retail seed=seed+1.","comparison":"Each strategy separately in run_batch(strategy, VanillaStrategy, configs, 8), never head-to-head. Paired d=total edge(candidate)-total edge(V2); se=sample SD(ddof=1)/sqrt(n). No errored seeds dropped.","validity":"After BOTH runs: candidate total callback OOG <= V2 total callback OOG, zero other errors in either run, and complete seed coverage.","edge":"Engine directly accumulates retail cash-flow edge and negative arbitrage profit at current true price, for reporting only. Runtime strategy receives only existing observable TradeInfo. No oracle input.","terciles":"Sort confirmation seeds by V2 retail Y volume (seed tie-break), numpy.array_split into three groups. Paired total gains and true retail/arb edge reported per group.","chart_optimization":"Unused step chart snapshots omitted; step-end fee averages still accumulated from identical quotes. No trading or gas-limit changes.","compiler":"SolidityCompiler at pinned commit: solc 0.8.24, optimizer 200, viaIR, Paris.","variants":"Original first/later mapping plus constant midpoint/skew pairs (28bps,0.6),(28,0.8),(32,0.6),(32,0.8),(36,0.8); price estimators unchanged.","patches":"diff --git a/amm_sim_rs/src/evm/strategy.rs b/amm_sim_rs/src/evm/strategy.rs\nindex 1d06af1..b91e0b6 100644\n--- a/amm_sim_rs/src/evm/strategy.rs\n+++ b/amm_sim_rs/src/evm/strategy.rs\n@@ -9,6 +9,46 @@ use revm::{\n };\n use thiserror::Error;\n \n+// ---- IMD gas instrumentation (audit only; does not change gas limits or economics) ----\n+use std::collections::BTreeMap;\n+use std::sync::Mutex;\n+\n+/// Per (role, callback) call statistics.\n+#[derive(Clone, Default, Debug)]\n+pub struct CallStats {\n+    pub calls: u64,\n+    pub ok: u64,\n+    pub max_ok_gas: u64,\n+    pub sum_ok_gas: u128,\n+    pub oog: u64,\n+    pub revert: u64,\n+    pub other_halt: u64,\n+    pub tx_error: u64,\n+    pub bad_return: u64,\n+}\n+\n+impl CallStats {\n+    fn merge(&mut self, o: &CallStats) {\n+        self.calls += o.calls; self.ok += o.ok; self.max_ok_gas = self.max_ok_gas.max(o.max_ok_gas);\n+        self.sum_ok_gas += o.sum_ok_gas; self.oog += o.oog; self.revert += o.revert;\n+        self.other_halt += o.other_halt; self.tx_error += o.tx_error; self.bad_return += o.bad_return;\n+    }\n+}\n+\n+pub static GAS_STATS: Mutex<BTreeMap<(String, String), CallStats>> = Mutex::new(BTreeMap::new());\n+\n+pub fn gas_stats_snapshot() -> Vec<(String, String, CallStats)> {\n+    GAS_STATS.lock().unwrap().iter().map(|((r, c), v)| (r.clone(), c.clone(), v.clone())).collect()\n+}\n+\n+pub fn gas_stats_reset() { GAS_STATS.lock().unwrap().clear(); }\n+\n+const CB_INIT: usize = 0;\n+const CB_SWAP: usize = 1;\n+const CB_NAME: usize = 2;\n+const CB_NAMES: [&str; 3] = [\"afterInitialize\", \"afterSwap\", \"getName\"];\n+// ---- end instrumentation header ----\n+\n use crate::types::trade_info::{encode_after_initialize, decode_fee_pair, TradeInfo, SELECTOR_GET_NAME};\n use crate::types::wad::Wad;\n \n@@ -56,16 +96,33 @@ pub struct EVMStrategy {\n     db: InMemoryDB,\n     /// Pre-allocated calldata buffer for after_swap (196 bytes)\n     trade_calldata: [u8; 196],\n+    /// Instrumentation: role label given at construction (\"Submission\"/\"Baseline\").\n+    role: String,\n+    /// Instrumentation: local per-callback stats, flushed to GAS_STATS on drop.\n+    stats: [CallStats; 3],\n+}\n+\n+impl Drop for EVMStrategy {\n+    fn drop(&mut self) {\n+        let mut g = GAS_STATS.lock().unwrap();\n+        for (i, st) in self.stats.iter().enumerate() {\n+            if st.calls > 0 {\n+                g.entry((self.role.clone(), CB_NAMES[i].to_string())).or_default().merge(st);\n+            }\n+        }\n+    }\n }\n \n impl EVMStrategy {\n     /// Create a new EVM strategy from compiled bytecode.\n     pub fn new(bytecode: Vec<u8>, default_name: String) -> Result<Self, EVMError> {\n         let mut strategy = Self {\n-            name: default_name,\n+            name: default_name.clone(),\n             bytecode: bytecode.clone(),\n             db: InMemoryDB::default(),\n             trade_calldata: [0u8; 196],\n+            role: default_name,\n+            stats: Default::default(),\n         };\n \n         strategy.deploy()?;\n@@ -123,7 +180,7 @@ impl EVMStrategy {\n         }?;\n \n         // Now insert the code at our fixed address\n-        let bytecode = Bytecode::new_raw(deployed_code);\n+        let bytecode = revm::interpreter::analysis::to_analysed(Bytecode::new_raw(deployed_code));\n         let account_info = AccountInfo {\n             balance: U256::ZERO,\n             nonce: 1,\n@@ -137,7 +194,7 @@ impl EVMStrategy {\n \n     /// Fetch the strategy name from the contract.\n     fn fetch_name(&mut self) -> Result<(), EVMError> {\n-        let result = self.call(&SELECTOR_GET_NAME, GAS_LIMIT_NAME)?;\n+        let result = self.call(&SELECTOR_GET_NAME, GAS_LIMIT_NAME, CB_NAME)?;\n \n         // Decode string return value\n         // String is encoded as: offset (32 bytes) + length (32 bytes) + data\n@@ -166,10 +223,11 @@ impl EVMStrategy {\n     /// Returns (bid_fee, ask_fee) in WAD.\n     pub fn after_initialize(&mut self, initial_x: Wad, initial_y: Wad) -> Result<(Wad, Wad), EVMError> {\n         let calldata = encode_after_initialize(initial_x, initial_y);\n-        let result = self.call(&calldata, GAS_LIMIT_INIT)?;\n+        let result = self.call(&calldata, GAS_LIMIT_INIT, CB_INIT)?;\n \n-        decode_fee_pair(&result)\n-            .ok_or_else(|| EVMError::InvalidReturnData(\"Failed to decode fee pair\".into()))\n+        let d = decode_fee_pair(&result);\n+        if d.is_none() { self.stats[CB_INIT].bad_return += 1; }\n+        d.ok_or_else(|| EVMError::InvalidReturnData(\"Failed to decode fee pair\".into()))\n     }\n \n     /// Handle a trade event and return updated fees.\n@@ -182,10 +240,11 @@ impl EVMStrategy {\n \n         // Copy calldata to avoid borrow conflict\n         let calldata = self.trade_calldata;\n-        let result = self.call(&calldata, GAS_LIMIT_TRADE)?;\n+        let result = self.call(&calldata, GAS_LIMIT_TRADE, CB_SWAP)?;\n \n-        decode_fee_pair(&result)\n-            .ok_or_else(|| EVMError::InvalidReturnData(\"Failed to decode fee pair\".into()))\n+        let d = decode_fee_pair(&result);\n+        if d.is_none() { self.stats[CB_SWAP].bad_return += 1; }\n+        d.ok_or_else(|| EVMError::InvalidReturnData(\"Failed to decode fee pair\".into()))\n     }\n \n     /// Reset the strategy for a new simulation.\n@@ -194,7 +253,8 @@ impl EVMStrategy {\n     }\n \n     /// Make a call to the contract.\n-    fn call(&mut self, calldata: &[u8], gas_limit: u64) -> Result<Vec<u8>, EVMError> {\n+    fn call(&mut self, calldata: &[u8], gas_limit: u64, cb: usize) -> Result<Vec<u8>, EVMError> {\n+        self.stats[cb].calls += 1;\n         let mut evm = Evm::builder()\n             .with_db(&mut self.db)\n             .modify_tx_env(|tx| {\n@@ -206,11 +266,16 @@ impl EVMStrategy {\n             })\n             .build();\n \n-        let result = evm.transact_commit()\n-            .map_err(|e| EVMError::ExecutionFailed(format!(\"{:?}\", e)))?;\n+        let result = match evm.transact_commit() {\n+            Ok(r) => r,\n+            Err(e) => { self.stats[cb].tx_error += 1; return Err(EVMError::ExecutionFailed(format!(\"{:?}\", e))); }\n+        };\n \n         match result {\n-            ExecutionResult::Success { output, .. } => {\n+            ExecutionResult::Success { output, gas_used, .. } => {\n+                let st = &mut self.stats[cb];\n+                st.ok += 1; st.sum_ok_gas += gas_used as u128;\n+                if gas_used > st.max_ok_gas { st.max_ok_gas = gas_used; }\n                 match output {\n                     Output::Call(data) => Ok(data.to_vec()),\n                     Output::Create(_, _) => {\n@@ -219,12 +284,15 @@ impl EVMStrategy {\n                 }\n             }\n             ExecutionResult::Revert { output, .. } => {\n+                self.stats[cb].revert += 1;\n                 Err(EVMError::ExecutionFailed(format!(\"Reverted: {:?}\", output)))\n             }\n             ExecutionResult::Halt { reason, .. } => {\n                 if matches!(reason, revm::primitives::HaltReason::OutOfGas(_)) {\n+                    self.stats[cb].oog += 1;\n                     Err(EVMError::OutOfGas)\n                 } else {\n+                    self.stats[cb].other_halt += 1;\n                     Err(EVMError::ExecutionFailed(format!(\"Halted: {:?}\", reason)))\n                 }\n             }\ndiff --git a/amm_sim_rs/src/lib.rs b/amm_sim_rs/src/lib.rs\nindex 35d9e59..b3e66f9 100644\n--- a/amm_sim_rs/src/lib.rs\n+++ b/amm_sim_rs/src/lib.rs\n@@ -65,11 +65,35 @@ fn run_single(\n         .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))\n }\n \n+/// Instrumentation: snapshot of per-(role, callback) EVM call stats as dicts.\n+#[pyfunction]\n+fn gas_stats(py: Python<'_>) -> PyResult<Vec<PyObject>> {\n+    use pyo3::types::PyDict;\n+    let mut out = Vec::new();\n+    for (role, cb, st) in crate::evm::strategy::gas_stats_snapshot() {\n+        let d = PyDict::new_bound(py);\n+        d.set_item(\"role\", role)?; d.set_item(\"callback\", cb)?;\n+        d.set_item(\"calls\", st.calls)?; d.set_item(\"ok\", st.ok)?;\n+        d.set_item(\"max_ok_gas\", st.max_ok_gas)?; d.set_item(\"sum_ok_gas\", st.sum_ok_gas as u64)?;\n+        d.set_item(\"oog\", st.oog)?; d.set_item(\"revert\", st.revert)?;\n+        d.set_item(\"other_halt\", st.other_halt)?; d.set_item(\"tx_error\", st.tx_error)?;\n+        d.set_item(\"bad_return\", st.bad_return)?;\n+        out.push(d.into_any().unbind());\n+    }\n+    Ok(out)\n+}\n+\n+/// Instrumentation: clear stats.\n+#[pyfunction]\n+fn gas_stats_reset() { crate::evm::strategy::gas_stats_reset(); }\n+\n /// Python module definition\n #[pymodule]\n fn amm_sim_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {\n     m.add_function(wrap_pyfunction!(run_batch, m)?)?;\n     m.add_function(wrap_pyfunction!(run_single, m)?)?;\n+    m.add_function(wrap_pyfunction!(gas_stats, m)?)?;\n+    m.add_function(wrap_pyfunction!(gas_stats_reset, m)?)?;\n     m.add_class::<SimulationConfig>()?;\n     m.add_class::<LightweightSimResult>()?;\n     m.add_class::<BatchSimulationResult>()?;\ndiff --git a/amm_sim_rs/src/simulation/engine.rs b/amm_sim_rs/src/simulation/engine.rs\nindex 6834c43..150a482 100644\n--- a/amm_sim_rs/src/simulation/engine.rs\n+++ b/amm_sim_rs/src/simulation/engine.rs\n@@ -113,6 +113,9 @@ impl SimulationEngine {\n         edges.insert(submission_name.clone(), 0.0);\n         edges.insert(baseline_name.clone(), 0.0);\n \n+        let mut retail_edges = edges.clone();\n+        let mut arb_edges = edges.clone();\n+\n         // Run simulation steps\n         let mut steps = Vec::with_capacity(self.config.n_steps as usize);\n \n@@ -141,9 +144,10 @@ impl SimulationEngine {\n             for amm in amms.iter_mut() {\n                 if let Some(arb_result) = arbitrageur.execute_arb(amm, fair_price, t as u64) {\n                     *arb_volume_y.get_mut(&arb_result.amm_name).unwrap() += arb_result.amount_y;\n-                    let entry = edges.entry(arb_result.amm_name).or_insert(0.0);\n+                    let entry = edges.entry(arb_result.amm_name.clone()).or_insert(0.0);\n                     // AMM edge is the negative of arbitrageur profit at true price\n                     *entry += -arb_result.profit;\n+                    *arb_edges.get_mut(&arb_result.amm_name).unwrap() -= arb_result.profit;\n                 }\n             }\n \n@@ -157,27 +161,17 @@ impl SimulationEngine {\n                 } else {\n                     trade.amount_y - trade.amount_x * fair_price\n                 };\n+                *retail_edges.get_mut(&trade.amm_name).unwrap() += trade_edge;\n                 let entry = edges.entry(trade.amm_name).or_insert(0.0);\n                 *entry += trade_edge;\n             }\n \n-            // 4. Capture step result and accumulate fees\n-            let step = capture_step(\n-                t,\n-                fair_price,\n-                &amms,\n-                &names,\n-                &initial_reserves,\n-                initial_fair_price,\n-            );\n-            // Accumulate fees for averaging\n-            for name in &names {\n-                if let Some((bid_fee, ask_fee)) = step.fees.get(name) {\n-                    *cumulative_bid_fees.get_mut(name).unwrap() += bid_fee;\n-                    *cumulative_ask_fees.get_mut(name).unwrap() += ask_fee;\n-                }\n+            // Reporting only: omit chart snapshots; retain exact step-end fee averages.\n+            for amm in &amms {\n+                let quote = amm.fees();\n+                *cumulative_bid_fees.get_mut(&amm.name).unwrap() += quote.bid_fee.to_f64();\n+                *cumulative_ask_fees.get_mut(&amm.name).unwrap() += quote.ask_fee.to_f64();\n             }\n-            steps.push(step);\n         }\n \n         // Calculate final PnL (reserves + accumulated fees)\n@@ -209,6 +203,8 @@ impl SimulationEngine {\n             strategies: vec![submission_name, baseline_name],\n             pnl,\n             edges,\n+            retail_edges,\n+            arb_edges,\n             initial_fair_price,\n             initial_reserves,\n             steps,\ndiff --git a/amm_sim_rs/src/types/result.rs b/amm_sim_rs/src/types/result.rs\nindex 0257335..d1df1a6 100644\n--- a/amm_sim_rs/src/types/result.rs\n+++ b/amm_sim_rs/src/types/result.rs\n@@ -57,6 +57,10 @@ pub struct LightweightSimResult {\n     /// Edge by strategy name (sum over trades)\n     #[pyo3(get)]\n     pub edges: HashMap<String, f64>,\n+    #[pyo3(get)]\n+    pub retail_edges: HashMap<String, f64>,\n+    #[pyo3(get)]\n+    pub arb_edges: HashMap<String, f64>,\n \n     /// Initial fair price\n     #[pyo3(get)]\n","experiment_py":"import json,hashlib,time,math,sys\nfrom pathlib import Path\nimport numpy as np\nimport amm_sim_rs as sim\nfrom amm_competition.competition.config import build_config\nfrom amm_competition.evm.baseline import get_vanilla_bytecode_and_abi\nfrom amm_competition.evm.compiler import SolidityCompiler\nROOT=Path('scratch'); VAN=list(get_vanilla_bytecode_and_abi()[0]); ERR=('revert','other_halt','tx_error','bad_return')\ndef configs(start,end):\n out=[]\n for seed in range(start,end):\n  r=np.random.default_rng(seed); size=r.uniform(19,21);rate=r.uniform(.6,1);sigma=r.uniform(.000882,.001008)\n  out.append(build_config(seed=seed,retail_mean_size=size,retail_arrival_rate=rate,gbm_sigma=sigma))\n return out\ndef compile(name):\n src=(ROOT/(name+'.sol')).read_text(); r=SolidityCompiler().compile(src)\n if not r.success: raise RuntimeError(str(r.errors))\n return list(r.bytecode)\ndef run(name,start,end):\n bc=compile(name);sim.gas_stats_reset();t=time.time();rows=[]\n # bounded batches avoid retaining millions of step objects; configs constructed only for requested seeds\n for lo in range(start,end,16):\n  br=sim.run_batch(bc,VAN,configs(lo,min(lo+16,end)),8)\n  for r in br.results:\n   rows.append(dict(seed=r.seed,edge=r.edges['submission'],retail_edge=r.retail_edges['submission'],arb_edge=r.arb_edges['submission'],retail_volume=r.retail_volume_y['submission'],arb_volume=r.arb_volume_y['submission']))\n  del br\n  if (lo-start)%128==0:print(name,lo,'elapsed',round(time.time()-t),flush=True)\n stats=sim.gas_stats();sub=[s for s in stats if s['role']=='Submission'];swap=[s for s in sub if s['callback']=='afterSwap'];init=[s for s in sub if s['callback']=='afterInitialize']\n gas=dict(max_ok=max((s['max_ok_gas'] for s in swap),default=0),oog=sum(s['oog'] for s in sub),other_errors={k:sum(s[k] for s in sub) for k in ERR},init_max=max((s['max_ok_gas'] for s in init),default=0),call_counts=stats)\n obj=dict(name=name,seeds=[start,end-1],seconds=time.time()-t,gas=gas,rows=rows)\n (ROOT/f'{name}-{start}.json').write_text(json.dumps(obj));print('DONE',name,start,obj['seconds'],gas,flush=True)\n return obj\ndef paired(a,b):\n bmap={r['seed']:r for r in b['rows']};ds=[(r['seed'],r['edge']-bmap[r['seed']]['edge']) for r in a['rows']];v=np.array([d for _,d in ds]);return dict(n=len(v),mean_diff=float(v.mean()),se=float(v.std(ddof=1)/math.sqrt(len(v))),worst=[dict(seed=s,diff=d) for s,d in sorted(ds,key=lambda r:r[1])[:5]])\ndef valid(a,b):\n return a['gas']['oog']<=b['gas']['oog'] and not any(a['gas']['other_errors'].values()) and not any(b['gas']['other_errors'].values())\ndef cached_run(name,start,end):\n p=ROOT/f'{name}-{start}.json'\n if p.exists():\n  obj=json.loads(p.read_text())\n  if len(obj['rows'])==end-start:\n   print('REUSE completed tuning measurement',name,start,flush=True)\n   return obj\n return run(name,start,end)\ndef main():\n t=time.time()\n (ROOT/'V2_native_probe.sol').write_bytes((ROOT/'V2.sol').read_bytes())\n probe=run('V2_native_probe',10040,10064)\n old=json.loads((ROOT/'V2-10000.json').read_text());oldmap={r['seed']:r for r in old['rows']}\n assert all(r==oldmap[r['seed']] for r in probe['rows']), 'Native host build changed seed results'\n assert probe['gas']['oog']==4, probe['gas']\n print('Cached-analysis parity: all six row fields identical on 24 seeds, including exactly 4 known OOGs',flush=True)\n names=['original','m28s6','m28s8','m32s6','m32s8','m36s8'];summary=[]\n base=cached_run('V2',10000,10256)\n for name in names:\n  a=cached_run(name,10000,10256);summary.append(dict(name=name,paired=paired(a,base),valid=valid(a,base),gas=a['gas']))\n (ROOT/'screen.json').write_text(json.dumps(summary));rank=sorted([r for r in summary if r['valid']],key=lambda r:-r['paired']['mean_diff']);top=[r['name'] for r in rank[:2]]\n if not top:raise RuntimeError('No gas-valid candidate in initial screen; trim required')\n base2=run('V2',12000,12512);second=[]\n for name in top:\n  a=run(name,12000,12512);second.append(dict(name=name,paired=paired(a,base2),valid=valid(a,base2),gas=a['gas']))\n (ROOT/'second.json').write_text(json.dumps(second));winner=sorted([r for r in second if r['valid']],key=lambda r:-r['paired']['mean_diff'])[0]['name']\n src=(ROOT/(winner+'.sol')).read_text();freeze=dict(name=winner,sha256=hashlib.sha256(src.encode()).hexdigest(),unix_time=time.time(),elapsed_seconds=time.time()-t,selection='highest mean gain among gas-valid top-two second-stage variants; no subsequent reselection')\n (ROOT/'freeze.json').write_text(json.dumps(freeze));print('FROZEN',freeze,flush=True)\n # exactly one confirmation, both roles separately vs Vanilla, no tuning after freeze\n a=run(winner,4170000,4172000);b=run('V2',4170000,4172000)\n out=dict(freeze=freeze,paired=paired(a,b),valid=valid(a,b));(ROOT/'confirmation.json').write_text(json.dumps(out));print(out,flush=True)\nif __name__=='__main__':main()\n","setup_sh":"set -eu;R=$PWD/scratch;mkdir -p $R/tmp $R/bin $R/solcx\necho \"export TMPDIR=$R/tmp XDG_CACHE_HOME=$R/xc UV_CACHE_DIR=$R/uvc UV_PYTHON_INSTALL_DIR=$R/uvpy RUSTUP_HOME=$R/rustup CARGO_HOME=$R/cargo SOLCX_BINARY_PATH=$R/solcx VIRTUAL_ENV=$PWD/.venv PATH=$PWD/.venv/bin:$R/bin:$R/cargo/bin:\\$PATH\" >$R/env.sh;. $R/env.sh\ncommand -v uv >/dev/null||{ curl -LsSf https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-unknown-linux-gnu.tar.gz|tar --no-same-owner -xz -C $R/tmp;cp $R/tmp/uv-*/uv $R/bin/;}\ncc --version >/dev/null 2>&1||{ curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest -o $R/tmp/mm.tbz;python3 -c \"import sys,tarfile;tarfile.open(sys.argv[1]).extract('bin/micromamba',sys.argv[2])\" $R/tmp/mm.tbz $R;MAMBA_ROOT_PREFIX=$R/mamba $R/bin/micromamba create -yq -p $R/cenv -c conda-forge gcc;ln -sf $(ls $R/cenv/bin/*gcc|head -n1) $R/bin/cc;}\ncommand -v cargo >/dev/null||{ curl -sSf https://sh.rustup.rs|sh -s -- -y --profile minimal --no-modify-path;}\nuv venv --python 3.12 .venv;uv pip install -e . maturin\nmaturin develop --release --uv --manifest-path amm_sim_rs/Cargo.toml\namm-match validate contracts/src/StarterStrategy.sol\n","audit_harness_fixes":"build_configs delegates to direct requested-seed configs; individual run validity excludes OOG; main compares candidate OOG<=V2 only after both runs; other errors remain fatal and exit status follows combined validity.","host_optimizations":"Rust RUSTFLAGS=-C target-cpu=native; deployed revm bytecode analyzed once instead of per call. 8-seed native-build parity and 24-seed cached-analysis parity checked exact equality of all six measured row fields against original host results; latter reproduces 4 known V2 OOGs and max successful afterSwap gas 243554.","config_parity_check":"Direct builder matched MatchRunner exactly for all 12 config fields on seeds 0..7; no simulations run on that diagnostic block."},"diagnostics":["x_error': 0, 'bad_return': 0}, {'role': 'Baseline', 'callback': '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}, {'role': 'Submission', 'callback': 'afterInitialize', 'calls': 256, 'ok': 256, 'max_ok_gas': 236389, 'sum_ok_gas': 60515584, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'afterSwap', 'calls': 2511351, 'ok': 2511344, 'max_ok_gas': 241852, 'sum_ok_gas': 276333367753, 'oog': 7, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'getName', 'calls': 256, 'ok': 256, 'max_ok_gas': 21557, 'sum_ok_gas': 5518592, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}]}\nm32s6 10000 elapsed 11\nm32s6 10128 elapsed 100\nDONE m32s6 10000 177.727153301239 {'max_ok': 241951, 'oog': 7, 'other_errors': {'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, 'init_max': 236398, 'call_counts': [{'role': 'Baseline', 'callback': '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}, {'role': 'Baseline', 'callback': 'afterSwap', 'calls': 2851553, 'ok': 2851553, 'max_ok_gas': 22592, 'sum_ok_gas': 64338621004, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Baseline', 'callback': '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}, {'role': 'Submission', 'callback': 'afterInitialize', 'calls': 256, 'ok': 256, 'max_ok_gas': 236398, 'sum_ok_gas': 60517888, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'afterSwap', 'calls': 2641601, 'ok': 2641594, 'max_ok_gas': 241951, 'sum_ok_gas': 291951755997, 'oog': 7, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'getName', 'calls': 256, 'ok': 256, 'max_ok_gas': 21566, 'sum_ok_gas': 5520896, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}]}\nm32s8 10000 elapsed 10\nm32s8 10128 elapsed 89\nDONE m32s8 10000 158.38165473937988 {'max_ok': 241852, 'oog': 7, 'other_errors': {'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, 'init_max': 236389, 'call_counts': [{'role': 'Baseline', 'callback': '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}, {'role': 'Baseline', 'callback': 'afterSwap', 'calls': 2862146, 'ok': 2862146, 'max_ok_gas': 22592, 'sum_ok_gas': 64578965812, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Baseline', 'callback': '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}, {'role': 'Submission', 'callback': 'afterInitialize', 'calls': 256, 'ok': 256, 'max_ok_gas': 236389, 'sum_ok_gas': 60515584, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'afterSwap', 'calls': 2279809, 'ok': 2279802, 'max_ok_gas': 241852, 'sum_ok_gas': 252999513865, 'oog': 7, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'getName', 'calls': 256, 'ok': 256, 'max_ok_gas': 21557, 'sum_ok_gas': 5518592, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}]}\nm36s8 10000 elapsed 9\nm36s8 10128 elapsed 81\nDONE m36s8 10000 145.96465468406677 {'max_ok': 241852, 'oog': 7, 'other_errors': {'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, 'init_max': 236389, 'call_counts': [{'role': 'Baseline', 'callback': '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}, {'role': 'Baseline', 'callback': 'afterSwap', 'calls': 2906057, 'ok': 2906057, 'max_ok_gas': 22592, 'sum_ok_gas': 65570446384, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Baseline', 'callback': '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}, {'role': 'Submission', 'callback': 'afterInitialize', 'calls': 256, 'ok': 256, 'max_ok_gas': 236389, 'sum_ok_gas': 60515584, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'afterSwap', 'calls': 2037427, 'ok': 2037420, 'max_ok_gas': 241852, 'sum_ok_gas': 228192153226, 'oog': 7, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}, {'role': 'Submission', 'callback': 'getName', 'calls': 256, 'ok': 256, 'max_ok_gas': 21557, 'sum_ok_gas': 5518592, 'oog': 0, 'revert': 0, 'other_halt': 0, 'tx_error': 0, 'bad_return': 0}]}\n","Setup script was run once; initial compilation encountered a local moved-value error in the added arb accumulator. Fixed with clone, then release rebuild and StarterStrategy validation passed.","Initial baseline throughput probe was interrupted before completing the screen. No selection used it. Rebuilt reporting-only chart optimization before restarting all measurements."],"partial_runs":[{"file":"original-10000.json","gas":{"max_ok":241989,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236407},"n":256,"seconds":215.32079362869263},{"file":"m32s8-10000.json","gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389},"n":256,"seconds":158.38165473937988},{"file":"m28s6-10000.json","gas":{"max_ok":241951,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236398},"n":256,"seconds":218.83859753608704},{"file":"V2-10000.json","gas":{"max_ok":243554,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236377},"n":256,"seconds":228.452974319458},{"file":"m32s6-10000.json","gas":{"max_ok":241951,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236398},"n":256,"seconds":177.727153301239},{"file":"V2_native_probe-10040.json","gas":{"max_ok":243554,"oog":4,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236377},"n":24,"seconds":17.600780248641968},{"file":"m28s8-10000.json","gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389},"n":256,"seconds":168.29341101646423},{"file":"V2_native_probe-10000.json","gas":{"max_ok":240793,"oog":0,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236377},"n":8,"seconds":6.5849997997283936},{"file":"m36s8-10000.json","gas":{"max_ok":241852,"oog":7,"other_errors":{"revert":0,"other_halt":0,"tx_error":0,"bad_return":0},"init_max":236389},"n":256,"seconds":145.96465468406677}],"gas_scope":{"type":"screen only; no completed confirmation","seeds":[10000,10255]},"code_status":"Provisional screen leader only; no second-stage selection or confirmation freeze.","executed_seed_ranges":{"screen":[10000,10255],"second_stage":null,"confirmation":null,"diagnostic_simulations":[[10000,10007],[10040,10063]]},"confirmation_started":false,"screen_top_two":["m28s8","m32s8"],"conclusion":"All six variants lost to exact V2 on the 256-seed screen. No confirmed improvement, no board submission, and no fresh confirmation seeds consumed.","targets_by_v2_retail_volume_tercile":{"source":"requester brief","top10":[4.1639,5.0149,5.7501],"first":[7.293,8.7183,10.1415]},"runtime_budget":{"item_cap_seconds":3600,"elapsed_since_first_artifact_download_seconds":2022.5925765037537,"estimated_confirmation_seconds":2781.523960952957,"estimated_second_stage_seconds":1028.8334434827168,"estimate_basis":"linear projection from cached-analysis 24-seed V2 run and completed 256-seed candidate screens; excludes compilation overhead","reservation_required_seconds":1200,"stop_reason":"The remaining prescribed stages cannot fit the <60min item cap; stopped after full screen before spending the unused second-stage or fresh confirmation blocks."},"baseline_sha256":"28417e116f57f1029fdd1803832e852574902c1ae7253c05657f317db76da4ab","checks":{"input_code_hashes":"both match brief exactly","config_builder_parity":"8 seeds x 12 fields exact against MatchRunner","host_native_parity":"8 seeds, all six result fields exact","host_cached_analysis_parity":"24 seeds, all six result fields exact, 4 known OOGs reproduced","screen_statistics":"independently recomputed with statistics.mean and statistics.stdev; all six pass","edge_accumulators":"total edge = retail edge + arb edge within 1e-8 on all screen seeds","callback_accounting":"calls = successes + OOG + other transaction failures on every role/callback row; no other errors","source_quotes":"all 7 URLs fetched again; every quote found exactly","confirmation_coverage":"none; no freeze or confirmation file exists","output":"JSON parses, code hash verified, result below 64000 bytes"},"stage_status":{"screen":"complete: six variants, 256 paired seeds each, all gas-valid under candidate<=V2 OOG rule","second_stage":"not started: runtime-budget block","freeze":"not performed: required second-stage selection incomplete","confirmation":"not started; 4170000..4171999 remains unused"}}
