## delta ```solidity After NP2 initialization of slots 0..12 add: slots[13]=0;slots[14]=0; Before NP2 writes slots[0..10] add: if(trade.isBuy)slots[13]=trade.timestamp;else slots[14]=trade.timestamp; if(absDiff(bidFee,askFee)>12*BPS){uint256 m=(bidFee+askFee)/2;if(bidFee>askFee){bidFee=m+12*BPS/2;askFee=m-12*BPS/2;}else{askFee=m+12*BPS/2;bidFee=m-12*BPS/2;}} uint256 a=trade.timestamp-slots[trade.isBuy?14:13]; if(a>=20){uint256 q=_powWad(WAD-100000000000000000,a-20+1);if(trade.isBuy)askFee=askFee>bidFee?bidFee+wmul(askFee-bidFee,q):bidFee-wmul(bidFee-askFee,q);else bidFee=bidFee>askFee?askFee+wmul(bidFee-askFee,q):askFee-wmul(askFee-bidFee,q);} ``` ## code ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; contract Strategy is AMMStrategyBase { uint256 constant ELAPSED_CAP = 8; uint256 constant SIGNAL_THRESHOLD = WAD / 650; uint256 constant DIR_DECAY = 750000000000000000; uint256 constant ACT_DECAY = 530000000000000000; uint256 constant SIZE_DECAY = 530000000000000000; uint256 constant TOX_DECAY = 910000000000000000; uint256 constant SIGMA_DECAY = 690000000000000000; uint256 constant LAMBDA_DECAY = 990000000000000000; uint256 constant SIZE_BLEND_DECAY = 828000000000000000; uint256 constant TOX_BLEND_DECAY = 51000000000000000; uint256 constant ACT_BLEND_DECAY = 985000000000000000; uint256 constant PHAT_ALPHA = 270000000000000000; uint256 constant PHAT_ALPHA_RETAIL = 60000000000000000; uint256 constant PHAT_ALPHA_SAME = 120000000000000000; uint256 constant REVERT_U = 0; uint256 constant DIR_IMPACT_MULT = 4; uint256 constant GATE_SIGMA_MULT = 7200000000000000000; uint256 constant MIN_GATE = 30000000000000000; uint256 constant TRADE_TOX_BOOST = 3500 * BPS; uint256 constant STALE_ATTRACT_FRAC = 1050000000000000000; uint256 constant RET_CAP = WAD / 35; uint256 constant TOX_CAP = WAD / 5; uint256 constant TRADE_RATIO_CAP = WAD / 5; uint256 constant LAMBDA_CAP = 1820000000000000000; uint256 constant STEP_COUNT_CAP = 64; uint256 constant BASE_FEE = 4 * BPS; uint256 constant SIGMA_COEF = 200000000000000000; uint256 constant LAMBDA_COEF = 12 * BPS; uint256 constant FLOW_SIZE_COEF = 4842 * BPS; uint256 constant TOX_COEF = 300 * BPS; uint256 constant TOX_QUAD_COEF = 15000 * BPS; uint256 constant ACT_COEF = 91843 * BPS; uint256 constant DIR_COEF = 20 * BPS; uint256 constant DIR_TOX_COEF = 100 * BPS; uint256 constant STALE_DIR_COEF = 6850 * BPS; uint256 constant SIGMA_TOX_COEF = 500 * BPS; uint256 constant TAIL_KNEE = 600 * BPS; uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000; uint256 constant TAIL_SLOPE_ATTRACT = 850000000000000000; function afterInitialize(uint256 initialX, uint256 initialY) external override returns (uint256, uint256) { slots[0] = BASE_FEE; slots[1] = BASE_FEE; slots[2] = 0; slots[3] = WAD; slots[4] = 0; slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD; slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000; slots[9] = 0; slots[10] = 0; slots[11] = 0; slots[12] = 0; slots[13]=0;slots[14]=0; return (BASE_FEE, BASE_FEE); } function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) { uint256 prevBidFee = slots[0]; uint256 prevAskFee = slots[1]; uint256 lastTs = slots[2]; uint256 dirState = slots[3]; uint256 actEma = slots[4]; uint256 pHat = slots[5]; uint256 sigmaHat = slots[6]; uint256 lambdaHat = slots[7]; uint256 sizeHat = slots[8]; uint256 toxEma = slots[9]; uint256 stepTradeCount = slots[10]; bool isNewStep = trade.timestamp > lastTs; if (isNewStep) { uint256 elapsedRaw = trade.timestamp - lastTs; uint256 elapsed = elapsedRaw > ELAPSED_CAP ? ELAPSED_CAP : elapsedRaw; dirState = _decayCentered(dirState, DIR_DECAY, elapsed); actEma = wmul(actEma, _powWad(ACT_DECAY, elapsed)); sizeHat = wmul(sizeHat, _powWad(SIZE_DECAY, elapsed)); toxEma = wmul(toxEma, _powWad(TOX_DECAY, elapsed)); if (stepTradeCount > 0 && elapsedRaw > 0) { uint256 lambdaInst = (stepTradeCount * WAD) / elapsedRaw; if (lambdaInst > LAMBDA_CAP) lambdaInst = LAMBDA_CAP; lambdaHat = wmul(lambdaHat, LAMBDA_DECAY) + wmul(lambdaInst, WAD - LAMBDA_DECAY); } stepTradeCount = 0; } bool firstInStep = stepTradeCount == 0; uint256 spot = trade.reserveX > 0 ? wdiv(trade.reserveY, trade.reserveX) : pHat; if (pHat == 0) pHat = spot; uint256 feeUsed = trade.isBuy ? prevBidFee : prevAskFee; uint256 gamma = feeUsed < WAD ? WAD - feeUsed : 0; uint256 pImplied; if (gamma == 0) { pImplied = spot; } else { pImplied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma); } { uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0; uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL; uint256 prePhat = pHat; bool secondPrint = !firstInStep && stepTradeCount == 1; bool sameDir = false; bool oppDir = false; if (secondPrint) { bool up2 = pImplied >= pHat; uint256 d1 = slots[12]; if (d1 != 0) { sameDir = (d1 == 1) == up2; oppDir = !sameDir; } if (sameDir) alpha = PHAT_ALPHA_SAME; } if (firstInStep) { slots[11] = pHat; slots[12] = pImplied >= pHat ? 1 : 2; } uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT); if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE; if (ret <= adaptiveGate) { pHat = wmul(pHat, WAD - alpha) + wmul(pImplied, alpha); } if (oppDir && REVERT_U > 0) { uint256 pre = slots[11]; if (pre > pHat) pHat = pHat + wmul(pre - pHat, REVERT_U); else pHat = pHat - wmul(pHat - pre, REVERT_U); } if (firstInStep) { if (ret > RET_CAP) ret = RET_CAP; sigmaHat = wmul(sigmaHat, SIGMA_DECAY) + wmul(ret, WAD - SIGMA_DECAY); } } // Interior retail routing equalizes fee-adjusted marginal prices. // Subsequent trades in a step cannot be the initial arbitrage trade. if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) { uint256 normalSpot = trade.isBuy ? wdiv(wmul(spot, gamma), WAD - 30 * BPS) : wdiv(wmul(spot, WAD - 30 * BPS), gamma); pHat = wmul(pHat, 90 * WAD / 100) + wmul(normalSpot, 10 * WAD / 100); } uint256 tradeRatio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0; if (tradeRatio > TRADE_RATIO_CAP) tradeRatio = TRADE_RATIO_CAP; if (tradeRatio > SIGNAL_THRESHOLD) { uint256 push = tradeRatio * DIR_IMPACT_MULT; if (push > WAD / 4) push = WAD / 4; if (trade.isBuy) { dirState = dirState + push; if (dirState > 2 * WAD) dirState = 2 * WAD; } else { dirState = dirState > push ? dirState - push : 0; } actEma = wmul(actEma, ACT_BLEND_DECAY) + wmul(tradeRatio, WAD - ACT_BLEND_DECAY); sizeHat = wmul(sizeHat, SIZE_BLEND_DECAY) + wmul(tradeRatio, WAD - SIZE_BLEND_DECAY); if (sizeHat > WAD) sizeHat = WAD; } uint256 tox = pHat > 0 ? wdiv(absDiff(spot, pHat), pHat) : 0; if (tox > TOX_CAP) tox = TOX_CAP; toxEma = wmul(toxEma, TOX_BLEND_DECAY) + wmul(tox, WAD - TOX_BLEND_DECAY); uint256 toxSignal = toxEma; stepTradeCount = stepTradeCount + 1; if (stepTradeCount > STEP_COUNT_CAP) stepTradeCount = STEP_COUNT_CAP; uint256 flowSize = wmul(lambdaHat, sizeHat); uint256 fBase = BASE_FEE + wmul(SIGMA_COEF, sigmaHat) + wmul(LAMBDA_COEF, lambdaHat) + wmul(FLOW_SIZE_COEF, flowSize); uint256 fMid = fBase + wmul(TOX_COEF, toxSignal) + wmul(TOX_QUAD_COEF, wmul(toxSignal, toxSignal)) + wmul(ACT_COEF, actEma); fMid = fMid + wmul(SIGMA_TOX_COEF, wmul(sigmaHat, toxSignal)); uint256 dirDev; bool sellPressure; if (dirState >= WAD) { dirDev = dirState - WAD; sellPressure = true; } else { dirDev = WAD - dirState; sellPressure = false; } uint256 skew = wmul(DIR_COEF, dirDev) + wmul(DIR_TOX_COEF, wmul(dirDev, toxSignal)); uint256 bidFee; uint256 askFee; if (sellPressure) { bidFee = fMid + skew; askFee = fMid > skew ? fMid - skew : 0; } else { askFee = fMid + skew; bidFee = fMid > skew ? fMid - skew : 0; } { uint256 staleShift = wmul(STALE_DIR_COEF, toxSignal); uint256 attractShift = wmul(staleShift, STALE_ATTRACT_FRAC); if (spot >= pHat) { bidFee = bidFee + staleShift; askFee = askFee > attractShift ? askFee - attractShift : 0; } else { askFee = askFee + staleShift; bidFee = bidFee > attractShift ? bidFee - attractShift : 0; } } { bool tradeAligned = (trade.isBuy && spot >= pHat) || (!trade.isBuy && spot < pHat); if (tradeAligned) { uint256 tradeBoost = wmul(TRADE_TOX_BOOST, tradeRatio); if (trade.isBuy) { bidFee = bidFee + tradeBoost; } else { askFee = askFee + tradeBoost; } } } if (sellPressure) { bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_PROTECT)); askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_ATTRACT)); } else { askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_PROTECT)); bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_ATTRACT)); } if(trade.isBuy)slots[13]=trade.timestamp;else slots[14]=trade.timestamp; if(absDiff(bidFee,askFee)>12*BPS){uint256 m=(bidFee+askFee)/2;if(bidFee>askFee){bidFee=m+12*BPS/2;askFee=m-12*BPS/2;}else{askFee=m+12*BPS/2;bidFee=m-12*BPS/2;}} uint256 a=trade.timestamp-slots[trade.isBuy?14:13]; if(a>=20){uint256 q=_powWad(WAD-100000000000000000,a-20+1);if(trade.isBuy)askFee=askFee>bidFee?bidFee+wmul(askFee-bidFee,q):bidFee-wmul(bidFee-askFee,q);else bidFee=bidFee>askFee?askFee+wmul(bidFee-askFee,q):askFee-wmul(askFee-bidFee,q);} slots[0] = bidFee; slots[1] = askFee; slots[2] = trade.timestamp; slots[3] = dirState; slots[4] = actEma; slots[5] = pHat; slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat; slots[9] = toxEma; slots[10] = stepTradeCount; return (bidFee, askFee); } function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) { if (fee <= TAIL_KNEE) return fee; return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope); } function _powWad(uint256 factor, uint256 exp) internal pure returns (uint256 result) { result = WAD; while (exp > 0) { if (exp & 1 == 1) result = wmul(result, factor); factor = wmul(factor, factor); exp >>= 1; } } function _decayCentered(uint256 centered, uint256 decayFactor, uint256 elapsed) internal pure returns (uint256) { uint256 mul = _powWad(decayFactor, elapsed); if (centered >= WAD) { return WAD + wmul(centered - WAD, mul); } uint256 below = wmul(WAD - centered, mul); return below < WAD ? WAD - below : 0; } function getName() external pure override returns (string memory) { return "no_cubic"; } } ``` ## sha256 `de39a375cb1a3fb7d2acfc901db47ae927308074d114c27b338bbb1dada3e871` Hash covers the UTF-8 Solidity block including its final newline. Local `amm-match validate scratch/Candidate.sol` passed; see validation details below. ## tuning The cap preserves NP2’s computed midpoint. The inactive side then contracts toward the active side by `1-(1-f)^max(age-k+1,0)`. Slots 13 and 14 store the last bid/ask trade timestamp. Only the inactive side contracts on a callback; repeated prints at one timestamp do not increment its age. Time zero is the initialization reference for a side that has never traded. There is no callback during an entirely idle step, so fees then remain unchanged until the next trade. Other NP2 constants and equations are unchanged. All following measurements are local experiments on the pinned simulator, not external leaderboard observations. NP2 was reconstructed from [TWO](https://api.imd.fun/artifacts/528a6da78583c6142644a552c86670f9d25c20e39e92f4de44deae05ddc8cecd) plus the specified [NP block](https://api.imd.fun/artifacts/da313379a2e69e9286668865e06b18dfcae25732c82b934b0fd9c2ef0d8c2ff5); its SHA-256 is `51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0`. Calibration on seeds 0..999, each strategy against the simulator’s fixed 30-bps VanillaStrategy: CH mean edge 525.525882178083 (requested 525.525882178; absolute error 8.34e-11); NP2 526.115572245986 (matches 526.1156 rounded). CH hash `6dd68f77a70900319460215374143dbd5d924198450a46d9f5f91f6b1e3d35c3`. CH source: [pinned Strategy.sol](https://raw.githubusercontent.com/ChengHua926/amm-challenge/d34a5199c59a4c44d5336a25f1436b4ae1f21104/contracts/src/Strategy.sol). Calibration seeds were not used to select constants. Pairing follows the item’s explicit call: `amm_sim_rs.run_batch(candidate, np2, configs, 8)`, taking `edges["submission"] - edges["normalizer"]` from the same market per seed. This differs from separately comparing each against Vanilla; no board-transfer claim is made for this head-to-head estimate. [Batch interface](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/lib.rs). Configs reproduce [MatchRunner draw order](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py): `g=default_rng(seed); size=g.uniform(19,21); rate=g.uniform(.6,1); sigma=g.uniform(.000882,.001008)`, with `cfg.seed=seed`. Other [baseline settings](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py): 10,000 steps, initial price 100, reserves 100 X / 10,000 Y, mu 0, dt 1, retail buy probability .5, retail size sigma 1.2. Engine price seed is seed and retail seed is seed+1. Batches were chunked to 20 simulations for memory use. Initial lowering-only cap results (seeds 10000..10099; n=100 each) prompted the midpoint-preserving implementation; the initial sweep was deliberately stopped and incomplete trials were discarded. | cap bps | k | fraction | mean_diff | SE | |---:|---:|---:|---:|---:| | 4 | 3 | 0.1 | -219.180517 | 4.842593 | | 4 | 3 | 0.3 | -220.362576 | 4.849018 | Centered-cap grid: caps {4,8,12}, k {3,20}, fraction {.1,.5}; seeds 10000..10099, n=100 per point. | cap bps | k | fraction | mean_diff | SE | |---:|---:|---:|---:|---:| | 4 | 3 | 0.1 | -56.299176 | 1.555148 | | 4 | 3 | 0.5 | -57.411752 | 1.546935 | | 4 | 20 | 0.1 | -55.921502 | 1.558620 | | 4 | 20 | 0.5 | -55.921677 | 1.558606 | | 8 | 3 | 0.1 | -52.455895 | 1.522728 | | 8 | 3 | 0.5 | -54.888869 | 1.497918 | | 8 | 20 | 0.1 | -51.779832 | 1.533621 | | 8 | 20 | 0.5 | -51.781777 | 1.533459 | | 12 | 3 | 0.1 | -48.983392 | 1.487228 | | 12 | 3 | 0.5 | -52.964240 | 1.459670 | | 12 | 20 | 0.1 | -47.851689 | 1.491574 | | 12 | 20 | 0.5 | -47.853342 | 1.491515 | The three largest centered-grid means were extended on seeds 10100..10199; the table includes the first 100, so n=200 per point. | cap bps | k | fraction | mean_diff | SE | |---:|---:|---:|---:|---:| | 12 | 20 | 0.1 | -47.188880 | 1.093313 | | 12 | 20 | 0.5 | -47.190742 | 1.093263 | | 12 | 3 | 0.1 | -48.286606 | 1.093103 | Chosen before confirmation: cap 12 bps, k=20, fraction=0.1, highest extended tuning mean (-47.188880). This is the least harmful tested centered point, not a demonstrated improvement. Compact formatting and local-variable names in the delivered block were checked to produce identical deployed executable bytecode to the selected tuning source after excluding the Solidity metadata trailer. ## paired Frozen candidate evaluated once on fresh seeds 2530000..2531999. No confirmation seed was used for tuning or repeated for another candidate. SE is sample standard deviation of the paired differences (ddof=1) divided by sqrt(n); worst lists the five smallest differences. ```json { "n": 2000, "mean_diff": -47.11457422107319, "se": 0.35436932734438115, "worst": [ { "seed": 2531705, "diff": -248.72728614257994 }, { "seed": 2531822, "diff": -153.2775011257463 }, { "seed": 2530022, "diff": -143.78382998971188 }, { "seed": 2530088, "diff": -137.91850909796108 }, { "seed": 2531713, "diff": -135.37126996180984 } ] } ``` ## fee_stats Step-end fees use the simulator’s per-run `average_fees`, which averages over all 10,000 steps including steps with no trades ([engine](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs)). Mean bid/ask/spread below are in bps, equally weighted across runs. A run counts toward bid>40 when its mean step-end bid exceeds 40 bps. “Mid slope per 10k retail Y” is defined here as the cross-run OLS slope, with intercept, of mean midpoint fee in bps against that strategy’s total routed retail Y divided by 10,000. It is a descriptive association, not a causal derivative or a within-run time trend. | population | strategy | n | bid bps | ask bps | bid-ask bps | mid slope bps / 10k retail Y | runs bid>40 | |---|---|---:|---:|---:|---:|---:|---:| | confirm head-to-head | NP2 | 2000 | 36.630907 | 35.389604 | 1.241303 | 1.800833 | 267 | | confirm head-to-head | candidate | 2000 | 31.972095 | 31.989770 | -0.017675 | 1.356063 | 2 | | calibration vs Vanilla | NP2 | 1000 | 36.478405 | 35.394115 | 1.084290 | 1.687607 | 103 | The brief’s 90 runs with mean bid above 40 bps are not reproduced by this calibration population: the observed count is 103/1000. The matching NP2 edge score and hash establish the local baseline; no equivalence between the brief’s run labels/population and these seeds is assumed. Local checks: Validating strategy...; Compiling strategy...; Strategy 'no_cubic' validated successfully!. Hook stress check for the delivered code: {"calls": 3000, "all_success": true, "max_gas": 194356, "max_spread_bps": 12.0}. The hook test uses randomized trade sizes/reserves, timestamps including zero elapsed time and large gaps, and prolonged directional runs; checks every return for success, fee bounds, and spread <= chosen cap. Maximum gas comes from `pyrevm.EVM.result.gas_used`, not the executor’s estimate. ## blocked `null` — setup, calibration, validation, hook checks, grid, and single confirmation completed. ## next Do not promote this cap. Preserve NP2 while testing a conditional cap that activates only during a verified stale-side episode; measure each candidate separately against Vanilla before making a leaderboard claim.