Do not promote; retain NP2. Frozen mixture candidate: `rr10s6625`. Confirmation gain versus NP2 is **-0.304711 ± 0.026608** (standard error), measured once on 2,000 fresh seeds. This is simulator evidence for this mechanism; no leaderboard score is inferred. `blocked`: null. The baseline was reconstructed from [TWO](https://api.imdnotdead.fun/artifacts/528a6da78583c6142644a552c86670f9d25c20e39e92f4de44deae05ddc8cecd) plus the specified [NP routing block](https://api.imdnotdead.fun/artifacts/da313379a2e69e9286668865e06b18dfcae25732c82b934b0fd9c2ef0d8c2ff5). Its SHA-256 is `51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0`. The simulator checkout was pinned to `6b6921f8d463314aa7c96234e1be25a25245f704`. The supplied setup completed and StarterStrategy validated. The [CH source](https://raw.githubusercontent.com/ChengHua926/amm-challenge/d34a5199c59a4c44d5336a25f1436b4ae1f21104/contracts/src/Strategy.sol) hash matched `6dd68f77a70900319460215374143dbd5d924198450a46d9f5f91f6b1e3d35c3`; the local 0..999 check returned **525.5258821780834**, within 1e-8 of the required 525.525882178. The first-print weight is `wR + P(arb)*(wA-wR)`. Later-print update code, same-direction second-print handling, the NP routing block, the original residual gate, and the sigma update remain as in NP2. The stale-direction and attraction constants are selected jointly with the new update. Silent steps mean `max(timestamp-lastTs-1,0)`, including zero for the initial timestamp. Probability inputs use the pre-update pHat and sigmaHat, and uncapped `amountY/reserveY`. Selected tuning point: ```json { "tag": "rr10s6625_240", "point": { "wA": 0.5, "wR": 0.1, "stale": 6625, "posterior": "posterior_m50" }, "start": 10000, "n": 240, "mean_diff": -0.36689854432512753, "se": 0.07407981939186564, "mean_edge": 522.4858370442986 } ``` The selected P(arb) is a 12×3×8 empirical conditional-frequency table fitted from 486,864 first prints on tuning seeds 10000..10079. Arb labels come from the engine's initial-arbitrage phase; first prints from the subsequent routing phase are retail. The initial table used NP2 trajectories. The refitted table (`posterior_m50`) used the initial-table candidate with wA=0.5, wR=0.03 and NP2's stale constants. Both use only those same 80 tuning seeds; model fitting never uses confirmation seeds. Ratio q upper bin boundaries: [0.25,0.5,0.75,1,1.22,1.5,2,3,4,6,9]; silence bins: [0,1,>=2]; tradeRatio upper boundaries: [0.00025,0.0005,0.001,0.002,0.004,0.008,0.02]. Equality goes into the upper bin. For cell count n and arb count a, marginal counts n_qs,a_qs across trade sizes, the smoothed estimate is `(a + 32*(a_qs+2)/(n_qs+4))/(n+32)`. Round `255*P` to nearest integer and flatten q-major, then silence, then trade size. The exact 288-byte fitted table is embedded in the code below. This fit is conditional on the training policy; transfer to the selected policy is tested by the fresh-seed confirmation. On the fresh block, arb edge changed by +3.431744 and retail edge by -3.736455. Their sum is the paired loss reported above. All tuning points below use seeds 10000..10079 (80 seeds). Rows with n=240 extend that same point to seeds 10000..10239; they add 160 seeds and do not exceed 256 distinct tuning seeds per point. Table defaults are wA=0.5, wR=0.03, stale=6850 BPS units, attract=1.05, initial empirical table. `posterior_m50` means the refitted table. `threshold` is the q<=1.22 binary-classifier ablation. | Point | Parameters overriding defaults | n | mean_diff | SE | |---|---|---:|---:|---:| | m50 | `{"wA":0.5,"wR":0.03}` | 80 | -5.439757 | 0.277015 | | m75 | `{"wA":0.75,"wR":0.03}` | 80 | -7.417395 | 0.297044 | | m50s3 | `{"wA":0.5,"wR":0.03,"stale":3000}` | 80 | -39.110358 | 0.836043 | | m100 | `{"wA":1.0,"wR":0.03}` | 80 | -11.055372 | 0.401995 | | m50s5 | `{"wA":0.5,"wR":0.03,"stale":5000}` | 80 | -9.171872 | 0.267598 | | m75r0 | `{"wA":0.75,"wR":0}` | 80 | -10.312194 | 0.391160 | | refit50 | `{"wA":0.5,"wR":0.03,"posterior":"posterior_m50"}` | 80 | -3.407815 | 0.230110 | | m50s9 | `{"wA":0.5,"wR":0.03,"stale":9000}` | 80 | -147.033945 | 6.600758 | | refit50s9 | `{"wA":0.5,"wR":0.03,"stale":9000,"posterior":"posterior_m50"}` | 80 | -118.817864 | 6.066592 | | m50s12 | `{"wA":0.5,"wR":0.03,"stale":12000}` | 80 | -279.791620 | 7.425629 | | m75r10 | `{"wA":0.75,"wR":0.1}` | 80 | -4.220596 | 0.266363 | | m50r10s9 | `{"wA":0.5,"wR":0.1,"stale":9000}` | 80 | -111.358764 | 5.129950 | | m50a08 | `{"wA":0.5,"wR":0.03,"attract":0.8}` | 80 | -5.291888 | 0.290832 | | hard122 | `{"wA":0.75,"wR":0.03,"kind":"threshold"}` | 80 | -37.786402 | 1.043892 | | log50 | `{"kind":"logistic","wA":0.5,"wR":0.03}` | 80 | -5.641805 | 0.280097 | | m50a13 | `{"wA":0.5,"wR":0.03,"attract":1.3}` | 80 | -6.120967 | 0.274413 | | log50r10 | `{"kind":"logistic","wA":0.5,"wR":0.1}` | 80 | -1.613376 | 0.188876 | | m50r10 | `{"wA":0.5,"wR":0.1}` | 80 | -1.429949 | 0.190204 | | refit50r10 | `{"wA":0.5,"wR":0.1,"posterior":"posterior_m50"}` | 80 | -0.494025 | 0.161159 | | rr10s55 | `{"wA":0.5,"wR":0.1,"stale":5500,"posterior":"posterior_m50"}` | 80 | -4.603169 | 0.190531 | | refit50s6250 | `{"wA":0.5,"wR":0.03,"stale":6250,"posterior":"posterior_m50"}` | 80 | -2.228912 | 0.149355 | | rr10s60 | `{"wA":0.5,"wR":0.1,"stale":6000,"posterior":"posterior_m50"}` | 80 | -1.547649 | 0.127232 | | refit50s7250 | `{"wA":0.5,"wR":0.03,"stale":7250,"posterior":"posterior_m50"}` | 80 | -6.420653 | 0.419037 | | rr10s65 | `{"wA":0.5,"wR":0.1,"stale":6500,"posterior":"posterior_m50"}` | 80 | -0.222512 | 0.117198 | | rr10s6250 | `{"wA":0.5,"wR":0.1,"stale":6250,"posterior":"posterior_m50"}` | 80 | -0.640739 | 0.114613 | | rr10s70 | `{"wA":0.5,"wR":0.1,"stale":7000,"posterior":"posterior_m50"}` | 80 | -1.024880 | 0.193558 | | rr10s6625 | `{"wA":0.5,"wR":0.1,"stale":6625,"posterior":"posterior_m50"}` | 80 | -0.212342 | 0.126717 | | rr10a08 | `{"wA":0.5,"wR":0.1,"attract":0.8,"posterior":"posterior_m50"}` | 80 | -0.720268 | 0.161614 | | rr10s65a09 | `{"wA":0.5,"wR":0.1,"stale":6500,"attract":0.9,"posterior":"posterior_m50"}` | 80 | -0.279975 | 0.116771 | | refit50r10_240 | `{"wA":0.5,"wR":0.1,"posterior":"posterior_m50"}` | 240 | -0.729081 | 0.088247 | | rr10a13 | `{"wA":0.5,"wR":0.1,"attract":1.3,"posterior":"posterior_m50"}` | 80 | -1.146851 | 0.165176 | | rr10s65_240 | `{"wA":0.5,"wR":0.1,"stale":6500,"posterior":"posterior_m50"}` | 240 | -0.376668 | 0.071528 | | rr10s65a12 | `{"wA":0.5,"wR":0.1,"stale":6500,"attract":1.2,"posterior":"posterior_m50"}` | 80 | -0.498598 | 0.123350 | | rr10s6625_240 | `{"wA":0.5,"wR":0.1,"stale":6625,"posterior":"posterior_m50"}` | 240 | -0.366899 | 0.074080 | Each candidate and NP2 was run separately against compiled VanillaStrategy, never against each other. Every `amm_sim_rs.run_batch` call contained at most 20 configs and used 8 workers. Config draws follow [MatchRunner](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)`, then `build_config(seed=seed,gbm_sigma=sigma,retail_arrival_rate=rate,retail_mean_size=size)`. Other fields use the pinned [canonical defaults](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py): 10000 steps, initial price 100, X=100, Y=10000, mu=0, dt=1, buy probability 0.5, retail log-size sigma 1.2. The [engine](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs) uses price seed=seed and retail seed=seed+1. Differences subtract submission edges, with sample SD (ddof=1)/sqrt(n). Baseline tuning outcomes are reused across candidates on the same seeds. Paired confirmation (frozen UTC: 2026-11-07T18:58:06.294542+00:00), after the source hash and parameters were frozen; the candidate was run exactly once per seed on 2760000..2761999: ```json { "seed_start": 2760000, "seed_end": 2761999, "n": 2000, "mean_diff": -0.30471083316545067, "se": 0.026607985916926122, "worst_5": [ { "seed": 2761835, "candidate_edge": 760.9930030460275, "np2_edge": 772.3784460155103, "diff": -11.385442969482824 }, { "seed": 2761215, "candidate_edge": 637.14813382628, "np2_edge": 641.3747263681447, "diff": -4.226592541864761 }, { "seed": 2761808, "candidate_edge": 708.3752347434247, "np2_edge": 712.455440435594, "diff": -4.080205692169329 }, { "seed": 2761874, "candidate_edge": 638.9610289518073, "np2_edge": 642.6173606194961, "diff": -3.656331667688846 }, { "seed": 2761308, "candidate_edge": 587.4404828543052, "np2_edge": 591.0021997964465, "diff": -3.561716942141288 } ] } ``` Split is mean edge per simulation, using the engine's negative arb-profit contribution and retail trade contributions. Observational scratch instrumentation adds separate accumulators and labels; it does not alter state or decisions. On 80 seeds the instrumented and original engines produced exactly equal NP2 edges; split sums agree with total edge within 1e-8 on every confirmation seed. ```json { "candidate": { "arb": -27.457149561181474, "retail": 550.8947898302393, "edge": 523.4376402690579 }, "NP2": { "arb": -30.888893408957426, "retail": 554.6312445111807, "edge": 523.7423511022233 } } ``` Checks: final source passed the pinned compiler/validator. Storage remains slots[0..12], with no new state slots. A separate pyrevm stress check used 3,000 synthetic constant-product swaps on both sides, sizes from 0.000001 to 0.05 of reserves and timestamp increments from {0,1,2,8,64}. All hooks succeeded with fees within [0,0.1]. Gas is read from `evm.result.gas_used`, not the executor's estimated gas field. These are sampled bounds, not an exhaustive proof. ```json { "calls": 3000, "initialization_gas": 189944, "max_swap_gas": 111891, "all_success": true } ``` Next: Retain NP2. This constrained first-print mixture did not demonstrate an improvement in the fresh paired metric. The tuning split showed better arb protection offset by lost retail edge. A follow-up should fit a conditional retail fair-price target and test it separately, or reconsider the wR<=0.1 constraint; further tuning must use a new confirmation block. Delta (exact unified diff against reconstructed NP2): ```diff --- NP2.sol +++ Strategy.sol @@ -5,6 +5,8 @@ import {TradeInfo} from "./IAMMStrategy.sol"; contract Strategy is AMMStrategyBase { + uint256 constant MIX_WA = 500000000000000000; + uint256 constant MIX_WR = 100000000000000000; uint256 constant ELAPSED_CAP = 8; uint256 constant SIGNAL_THRESHOLD = WAD / 650; uint256 constant DIR_DECAY = 750000000000000000; @@ -39,7 +41,7 @@ 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 STALE_DIR_COEF = 6625 * BPS; uint256 constant SIGMA_TOX_COEF = 500 * BPS; uint256 constant TAIL_KNEE = 600 * BPS; uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000; @@ -88,6 +90,13 @@ { uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0; uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL; + if (firstInStep) { + uint256 silent = trade.timestamp > lastTs ? trade.timestamp - lastTs - 1 : 0; + uint256 ratio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0; + uint256 q = sigmaHat > 0 ? wdiv(ret, sigmaHat) : 0; + uint256 probability = _arbProbability(q, silent, ratio); + alpha = MIX_WR + wmul(probability, MIX_WA - MIX_WR); + } uint256 prePhat = pHat; bool secondPrint = !firstInStep && stepTradeCount == 1; bool sameDir = false; bool oppDir = false; @@ -202,6 +211,20 @@ return (bidFee, askFee); } + function _arbProbability(uint256 q, uint256 silent, uint256 ratio) internal pure returns (uint256) { + uint256 qi = q < 250000000000000000 ? 0 : q < 500000000000000000 ? 1 : + q < 750000000000000000 ? 2 : q < WAD ? 3 : q < 1220000000000000000 ? 4 : + q < 1500000000000000000 ? 5 : q < 2 * WAD ? 6 : q < 3 * WAD ? 7 : + q < 4 * WAD ? 8 : q < 6 * WAD ? 9 : q < 9 * WAD ? 10 : 11; + uint256 si = silent > 2 ? 2 : silent; + uint256 ti = ratio < 250000000000000 ? 0 : ratio < 500000000000000 ? 1 : + ratio < 1000000000000000 ? 2 : ratio < 2000000000000000 ? 3 : + ratio < 4000000000000000 ? 4 : ratio < 8000000000000000 ? 5 : + ratio < 20000000000000000 ? 6 : 7; + bytes memory posterior = hex"cad4e5f3f9efdae18f77552a5d8080805f502a0b2d515151bdc2d3dee6ddcaca896e501d3471717166502f0b12474b4bafb0c2cccfceb9b97f6047121453606065452e0909274343969caeb6a5ada8a56c533d0f0a3d4c4c583f2807051837377985999f898394944d43330c0622353543321f060411252656688383695775783931260a020d2022312c1b0502081a1b324069694330555829211b0501041314221b120400020c101f26404f1e0c1f32141c0f03000106091e150b020001040910121a331504051e140d0902000002051610080100000206120c141d1202030d0e09080100000104110e0b01000001040a0805080d010004000703000000000109030000000000010607010a0600000101060401010100010b01010101000001"; + return uint256(uint8(posterior[(qi * 3 + si) * 8 + ti])) * WAD / 255; + } + function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) { if (fee <= TAIL_KNEE) return fee; return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope); ``` Code (full Strategy.sol). SHA-256 of the UTF-8 code block contents, including its final LF: `73659ff6ff530082f1d8916d0728f704ac42c645b4c9743d8732d2c3115d41c2`. ```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 MIX_WA = 500000000000000000; uint256 constant MIX_WR = 100000000000000000; 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 = 6625 * 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; 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; if (firstInStep) { uint256 silent = trade.timestamp > lastTs ? trade.timestamp - lastTs - 1 : 0; uint256 ratio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0; uint256 q = sigmaHat > 0 ? wdiv(ret, sigmaHat) : 0; uint256 probability = _arbProbability(q, silent, ratio); alpha = MIX_WR + wmul(probability, MIX_WA - MIX_WR); } 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)); } 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 _arbProbability(uint256 q, uint256 silent, uint256 ratio) internal pure returns (uint256) { uint256 qi = q < 250000000000000000 ? 0 : q < 500000000000000000 ? 1 : q < 750000000000000000 ? 2 : q < WAD ? 3 : q < 1220000000000000000 ? 4 : q < 1500000000000000000 ? 5 : q < 2 * WAD ? 6 : q < 3 * WAD ? 7 : q < 4 * WAD ? 8 : q < 6 * WAD ? 9 : q < 9 * WAD ? 10 : 11; uint256 si = silent > 2 ? 2 : silent; uint256 ti = ratio < 250000000000000 ? 0 : ratio < 500000000000000 ? 1 : ratio < 1000000000000000 ? 2 : ratio < 2000000000000000 ? 3 : ratio < 4000000000000000 ? 4 : ratio < 8000000000000000 ? 5 : ratio < 20000000000000000 ? 6 : 7; bytes memory posterior = hex"cad4e5f3f9efdae18f77552a5d8080805f502a0b2d515151bdc2d3dee6ddcaca896e501d3471717166502f0b12474b4bafb0c2cccfceb9b97f6047121453606065452e0909274343969caeb6a5ada8a56c533d0f0a3d4c4c583f2807051837377985999f898394944d43330c0622353543321f060411252656688383695775783931260a020d2022312c1b0502081a1b324069694330555829211b0501041314221b120400020c101f26404f1e0c1f32141c0f03000106091e150b020001040910121a331504051e140d0902000002051610080100000206120c141d1202030d0e09080100000104110e0b01000001040a0805080d010004000703000000000109030000000000010607010a0600000101060401010100010b01010101000001"; return uint256(uint8(posterior[(qi * 3 + si) * 8 + ti])) * WAD / 255; } 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"; } } ```