# spline-1: smooth-2d Solidity port The final `Strategy.sol` below validates, deploys at **21,106 bytes**, and passes the 50-run fee replay against the original smooth-2d decoded tables (maximum **0.008898410 bps**). Its exactly shipped packed-basis tables lose **0.009736752 edge** to Taylor's full tables on the replica report set. The real-engine experiment was run on an earlier 24-bit-basis version. That version beat t03 and IB but missed the 245,000-gas peak gate; the final gas-optimized version was not run on those consumed engine seeds. **Its final real-engine gas and paired score remain unverified.** Inputs: [Taylor's solved-game README](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/README.md), [real.py](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/real.py), [evalpol.py](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/evalpol.py), [port-3](https://api.imdnotdead.fun/artifacts/0dbcc10af41b3c3467ff0d9b9cb64c81328fcf18295f9be06b2d81bb98874067), and [smooth-2d](https://api.imdnotdead.fun/artifacts/c2fc0b1a8e42ec954070cb12abde141b18a8c094b40771b12cf16c75324004f3). All figures below are local observations or calculations from those pinned inputs and the embedded harnesses. ## Setup | Step | Local result | |---|---| | Clone `benedictbrady/amm-challenge`, checkout `6b6921f8d463314aa7c96234e1be25a25245f704` in `test/scratch/` | Passed | | Run the supplied `scratch/setup.sh` once from that checkout | Passed, exit 0 | | Pinned `amm_sim_rs` wheel SHA-256 | `aedb68280aca34c110968f00148387c95885207913fb2cf19a1ab4c5cfd6887a`, matched | | Python and packages | Python 3.12.3; wheel 0.1.0.post1, numpy, numba, cma, py-solc-x 2.1.0, pyrevm 0.3.7 | | Solidity compiler | solc 0.8.24 installed; challenge compiler settings unchanged | | `amm-match validate contracts/src/StarterStrategy.sol` | Passed | | `amm-match validate contracts/src/Strategy.sol`, final source | `Strategy 'TaylorGaussianPlainSpline' validated successfully!` | The pinned challenge [compiler](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/evm/compiler.py) and [base contract](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/AMMStrategyBase.sol) were used without modification. The exact executed setup script is embedded below. Toolchain files stayed in scratch; the delivered Solidity source embeds its runtime data and has no external table dependency. ## Design The Gaussian belief filter, state slots 0–7, fixed-point math, and fee formula follow [port-3](https://api.imdnotdead.fun/artifacts/0dbcc10af41b3c3467ff0d9b9cb64c81328fcf18295f9be06b2d81bb98874067), which ports Taylor's [real.py](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/real.py). The final contract's header credits Taylor (gtmcknight). It remains `contract Strategy is AMMStrategyBase`, with no assembly. Both data literals use 32-byte payload blocks prefixed with `PUSH32` (`0x7f`), as port-3 did. The [smooth-2d](https://api.imdnotdead.fun/artifacts/c2fc0b1a8e42ec954070cb12abde141b18a8c094b40771b12cf16c75324004f3) coefficient blob is **2,665 bytes**, SHA-256 `6749a7d91c465a96ad29fa21a4f1e116ac00aaf53233688d27e78f4b42925a18`. This port adds **8,690 bytes** of grid-node basis records and the 49-element `W2L` axis, SHA-256 `deb9ad29ce5e3f51f099611b8f977c37fcf4d50f208845debb68f37727fde14f`. Each basis record occupies eight bytes: a 5-bit first coefficient index and three 19-bit weights at scale **524287**; the fourth weight is `524287 - a - b - c`. The two payloads occupy 11,355 bytes, or 11,748 bytes with block prefixes. Grid-node ask fee is `max(0, Σ Cᵢⱼ Bᵢ Bⱼ)/(8·524287²)` bps. The bid node uses the ask fee at the mirrored row and column. Maximum absolute grid-node difference from the original smooth-2d decoder is **0.001028047 bps**, measured over all six decoded tables. | Phase | Coefficient byte offset | Coefficient columns | Row basis byte offset | Column basis byte offset | Grid columns | |---:|---:|---:|---:|---:|---:| | 0 | 53 | 9 | 0 | 2568 | 13 | | 1 | 585 | 18 | 2672 | 5240 | 49 | | 2 | 1657 | 18 | 5632 | 8200 | 49 | For a lookup, the contract evaluates ask fee at the four grid nodes around `(w,R)` and bid fee at their four mirrored nodes. It clamps each node fee to zero, interpolates each side bilinearly, applies the out-of-grid displacement adjustment, then port-3's exponential fee rule. The row displacement adjustment matters when `w` is outside ±800 bps: the decoded table clips its row but the rule subtracts the original `w`. A shared 4-node contraction reads each coefficient once across adjacent nodes. Precomputed basis values avoid Cox-de Boor divisions during `afterSwap`. ## Gates P and Q **P.** Before changing Taylor's policy, `python3 -I gates.py` in the pinned `research/solved` directory reproduced the [published gate](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/gates.py) output: ```text seed perfect-info gaussian+plain gaussian+qm lattice+qm 10000 448.261189 443.455598 443.522608 443.663520 10001 576.779199 571.463409 571.623551 571.977293 10002 531.886497 525.168028 525.865859 526.411631 ``` **Q.** The embedded standard-library decoder reconstructed the exact packed basis and coefficients shipped in the final contract. The replica scorer called [real.ev](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/real.py) with `{'soft': 1.0}` for both that table and the [full `pol_mid.json`](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/pol_mid.json), on their own trajectories. Difference is packed minus full; sample SE uses the paired differences. | Set | Seeds | n | Full mean edge | Packed mean edge | Mean difference | SE | |---|---|---:|---:|---:|---:|---:| | Choose | 60000..61023 | 1024 | 529.061693433 | 529.051795543 | -0.009897890 | 0.012703835 | | Report | 10000..12047 | 2048 | 532.385686971 | 532.375950219 | -0.009736752 | 0.008966433 | Report worst five `(seed, packed − full)`: (10359, -1.881228032), (11826, -1.616187069), (10652, -1.503660721), (11741, -1.452449805), (11696, -1.429047246). The smooth-2d source reported about +0.0097 full-minus-decoded loss; this independent packed-basis run agrees within its sampling error. ## Gate F Passed against the **original smooth-2d decoded tables**: 50 [replica2.py](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/replica2.py) runs, seeds 70000..70049, first 2,000 own-pool callbacks per run. The Python reference drove each run and recorded `(side, amounts, timestamp, post-trade reserves, expected fees)`. A fresh pyrevm deployment per run received those callbacks in order, each with a 245,000 gas cap. Both fees were compared on every callback: **100,000 successful calls, 200,000 fee comparisons, no replay OutOfGas**. Maximum absolute fee difference **0.008898410277 bps**, mean absolute difference **0.000060668892 bps**, below the 0.01 bps target. Initialization maximum was **4.34e-15 bps**. Pyrevm afterSwap peak **193,623 gas**, mean **95754.61154 gas**. SHA-256 of concatenated ordered per-run trace hashes: `8fbd8a774dc2baf9151c2cce89f5e0374ac298d4714eb3bb08df625926f78ace`. The embedded `check.py` is the replay harness. ## Size The final source SHA-256 is **`27ad2a5f3d2b218138a95f8d4ab616227ca7dfd855a9c60577f86fea09c6caed`**. Solc 0.8.24 via the challenge compiler produced **21,106 / 24,576 deployed bytes** and **21,134 creation bytes**. Deployed runtime SHA-256: `5644f5c6459497079d6d78b00d58e9b29a13f90bc703a4da7286b7079c5dfd70`. The final source passed `amm-match validate`. There are no linked table contracts or assembly blocks. ## Real-engine measurement and gas limit The engine experiment used **only seeds 9520000..9520127**, four chunks of 32 per candidate, each candidate alone against the fixed 30 bps [VanillaStrategy](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol), via `amm_sim_rs.run_batch(X, VanillaStrategy, configs, 8)`. The embedded `engine.py` transcribes [MatchRunner._build_configs](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py) using the [baseline ranges](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py) and `default_rng(seed=i)`; each seed has matched settings across candidates. t03 and IB came from the requested [`code_zb64` t03 artifact](https://api.imdnotdead.fun/artifacts/2333ecf28d4356bd232b85c1e55842e94e1ada05e1cd067830b5625dfdbc5336) and [`code_zb64` IB artifact](https://api.imdnotdead.fun/artifacts/afd5183e9ff3235334e041c00b0cd19079599a2c6464db95f8c1586712105557). Their decoded source hashes matched `cb6d945511e1e10af78baa64c2a6cb25806f0998403ce6440654bfc3c70092d9` and `301941829a44bb60977bb28181a5e4bfa6544f3696763f987054789b2611d686`. Deployed sizes were **14,654 bytes for t03** and **14,528 bytes for IB**. All chunks completed in less than eight minutes each. **Version boundary:** the engine `port` source is the earlier 24-bit-basis file, SHA-256 `1b27d1f99bee42d16c7b2b8989f8118f932d7d9913f644a8112798db7a90999d`, deployed size **22,117 bytes**. It is not the final 19-bit, unrolled-contraction source above. The engine seeds were not rerun after the gas repair. Aggregated `amm_sim_rs.gas_stats()` afterSwap counters per role; peak is maximum successful gas across chunks and mean is `sum_ok_gas / ok`: | Candidate | Role | afterSwap calls | OutOfGas | Peak gas | Mean gas | |---|---|---:|---:|---:|---:| | port v24 | Submission | 1,372,160 | 0 | 249,342 | 144683.72628 | | port v24 | Baseline | 1,389,788 | 0 | 22,592 | 22562.72637 | | t03 | Submission | 1,380,512 | 0 | 235,527 | 135680.72828 | | t03 | Baseline | 1,363,230 | 0 | 22,592 | 22562.79230 | | IB | Submission | 1,370,107 | 0 | 234,958 | 135342.63799 | | IB | Baseline | 1,364,173 | 0 | 22,592 | 22562.81215 | The earlier port had 0 OutOfGas calls, but its **249,342** gas peak exceeds the stated **245,000** peak limit by **4,342**. The final source's Gate F pyrevm peak is 193,623 gas. On the same 2,000 replay callbacks for seed 70000, the final source used **8,752 to 14,374 less pyrevm gas per call** than the engine-tested version (mean saving 12,485.64). That is a replica replay comparison, not a real-engine `gas_stats()` result. The final real-engine peak is therefore unknown. ## Paired edge on the real engine (earlier port version) The following differences are submission edge(port v24) minus submission edge(comparator) on matching seeds. Both candidates in each comparison ran separately against VanillaStrategy. These rows describe the earlier version above; **they do not establish the final source's engine score**. | Comparison | n | Mean difference | SE | Worst five `(seed, difference)` | |---|---:|---:|---:|---| | port v24 − t03 | 128 | +1.314246680 | 0.123842280 | (9520062, -1.464768), (9520067, -1.360214), (9520090, -1.319751), (9520121, -1.133484), (9520057, -0.997555) | | port v24 − IB | 128 | +2.173776453 | 0.131962267 | (9520067, -1.173812), (9520090, -1.092461), (9520075, -0.641801), (9520121, -0.638198), (9520062, -0.431088) | ## Reproduction commands Run these from the pinned challenge checkout after placing the embedded Python files in `scratch/` and extracting the Solidity block to `contracts/src/Strategy.sol`. Taylor's pinned `research/solved/` directory supplies `replica2.py`, `real.py`, `evalpol.py`, `gates.py`, and `pol_mid.json`. The native wheel and Python packages come from the executed setup script. Gate F records callbacks in memory and writes only summaries to scratch. The real-engine port measurements above came from the earlier source hash and cannot be reproduced by running the final source under the same seed rule. ```sh sh scratch/setup.sh (cd ../taylor/research/solved && python3 -I gates.py) . scratch/env.sh && python scratch/replica_compare_spline.py 60000 61024 . scratch/env.sh && python scratch/replica_compare_spline.py 10000 12048 . scratch/env.sh && python scratch/check.py 50 . scratch/env.sh && amm-match validate contracts/src/Strategy.sol ``` The engine harness uses `python scratch/engine.py `, with 32-seed chunks and `timeout 470`; those assigned seeds were consumed by the earlier port and the comparators. The command list is a method record, not a request to reuse them. ## Problems and limits - The first 16-bit basis version missed Gate F against the original decoded tables because small fee changes fed back into the Gaussian filter. The 19-bit packed basis passed the specified 50-run Gate F. - A single larger literal made solc 0.8.24 fail locally; separating `COEFF` and `BASES` compiled successfully. The 24-bit version's engine peak exceeded the gas gate. The final version lowered replay gas and passed validation, size, Q, and F, but has no fresh assigned real-engine seeds left for a direct final gas or paired-score check. - The native wheel, Taylor replica, and setup environment are measurement inputs, not contract runtime dependencies. The verifier's path and byte checks alone do not certify gas or performance. ## Complete source The following blocks are the delivered source text. `Strategy.sol` is the final contract, and the Python decoder/reference are standard-library code. `check.py`, `replica_compare_spline.py`, and `engine.py` show the measurement method. The contract's SHA-256 above is over the exact Solidity block including its trailing newline. ### contracts/src/Strategy.sol ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; // Gaussian solved policy by Taylor (gtmcknight), amm-sim 4812a638. // Port: signed WAD arithmetic; smooth-2d plain spline, signed int16 eighth-bps coefficients. // COEFF and BASES use 32 payload bytes per 33-byte block, prefixed with PUSH32 (0x7f). // Grid basis weights are precomputed at Q=524287. The fourth weight is implicit. // Taylor source: https://github.com/gtmcknight/amm-sim/tree/4812a6382311624e1506aca131ca35c378f930d9/research/solved contract Strategy is AMMStrategyBase { int256 constant U=1e18; int256 constant LN2=693147180559945309; bytes constant COEFF=hex"7f03031605003b006c0082008a008f00920093009500960098009b00a400a700a97f00aa00ac00ad00b000b500bd00d301040103080a0b183e1842184118551841187f75187718a41881152c15221541151715b914c91509142c14d80f940fa90f820f7fdf0ef41083100f1178107708db08ca08f708b709990858089f078b084d04e1047ffb04d0053c046705d10615071c06a5032e0309036902fc04a5050d0442054c047f7602710294026702fb0404029d054000e4042b020f022b021102d402d90421027ffb0474035301da01d901f5026f030a024b038b0283036301c401de01c70256027f78035702c1038202f901a0018f01c801f1028a028102d3026f02da01af01a4017f7c01de0204023802c502350287010101fe011200e501b401a901cc01b501de017f38fe93016bffe900c600e1012a01020121ff2e03e9fed000f0ffa500810021017f01008201cafc1101c6fe730073ff9600effeab003efc5b02eafdf500ccffb3007f32fef7022b000e0095ff190066ffae001cffec003fff76ffedffa50019ffe4007f0afffc0003ffe7003200040003fff80004fffc0002fffe0008ffeffffbfffe007f02fffe0001ffff0001fffa000c00010000ffff0000ffff000000000003fffaff7ffe00000001ffff000000000000fffb000900010000ffff0001ffff0000ffff007f05fff6fffd000000010000000000000000fffb000900010000000000000000007f00000000000000ffff180e003e0075008b00910094009600980099009a009c007f9d009f00a000a200a300a500a600a700a900ab00ae00b400ca01010a0f1214157f161718191a1b1d2025180517fc181c181c1828182918301830181718271819187f35184718a51874185317e5183214d214d914a314eb14dc14f914d414f3157c157f9c154a151b144613c41413150e160d156b0eab0eb50ef10ed80eef0ed60f0b0e7fe40e3f0df60e5f0ec50fce109110be0efd0d4a0e5c07ae0789078c078e07a6077fbc079d07bb083f087c083a07ee072c06900621074609de08b4033703870366037f920394039303b403a70344030b03330360041104a3056d060305b505d00226017f9f021201f9020b02310219022402b6033d039603cd03d503f203bd03a303ec037fd001c4011301a101b201bb01c5020202a402b0029d029802a002cb02f8034f037f7a03d703b1015900b1013c017b018f01b601e701f3020f0252027f02a502c2027feb02f502f90348031c00bc00b001000144014e019a01bc01da020202100228027f3b025d028802bb02e0033403230171ff6b0119010c014c0156019a01a701c6017fe50201021b023f0267028a029b030102c3009affed00ca00d8015e0158015e017f86019501b601ce01eb01ff0234025a027602eb02f501d9fef500ca00ab010d017f27012d015401620183019d01b501de01ff022b023702be0238fd800013ffed007fc20138013100f70116012e014101610180019201c401f2020202e502c7001e017f5ffeef010400d600ff00dc00e000fd010f012d01480167019b01ab021a0241077f65002afbd5ffa4010d00bd00d3009400a700c200d000f001080134014b01a2017f1e06a404560044f926006a00a600a300a1009e007f008e00a800b900dc00f8017f270151015406cf0460ffeefec800d7005a009a006a008c004400530068007f007f9800c200de0141010f064d043c0027ff54002a00640059004e004500400027007f480048006a009400b70115010d05e4042fff480002002800460033003a0036007f160020fff5003600320062007e00fd009c061003dd001aff8a001b00260032007f240004002d0009ff64ffff00140038006e009d00f104f2036dffffff71001aff7fd0000cffabffffffb1001a00080033ff73ffd2002c00b3fff4064a0464fffe007f14fffd0008fffc000fffff000efff8fff1ffea00170017ffb000250085041d027f090000fff40002fff80004fff10001fff20005ffff000fffd0fffc000cffebff7f0905ef04390000000200000003ffff0005000000040002ffec0015ffac005ffe7ffb0265fc48032bfc7f0000fffd0001fffb0003fff50000fff60001000dfff1007f40ff64010bfd3a03dcfc8a024f00000002ffff0004fffd000a00000009fffdff7ff2ffffffbb0079feda0244fc6503f2fd2a0000fffe0001fffc0003fff40000ff7ff5000300040002001dffaf008afed7005ffe4700b500000000000000000000007f0000000000fffffffffffbfff8fffeffe20024ffd8005effd2180e003e0075007f8a00900093009500970099009a009c009d009f00a000a200a300a500a600a8007faa00ac00af00b500ca0101090d111314161718191b1c1e2226180517ff1814187f18181e181a182118151831182217ef181317f7182b1833187f183c185714cc147fda14ac14ce14cb14eb14d915191490150e1556159515b214d114e0141214dd147f960eba0eac0ee40ee30eea0eca0ee40e970f480ea70e400ddb0ddd0ef20f01107f4f0f5c0fad07a907a10799078b07a107ba07af07e8076f07e2084408aa087f077fde07ab0689071706e9036e038c038c039503a3039c03af038903ef03970342027fd602ff035f03ae04c705be05c1023301dc021d021f021a023c0236027101e0027f4802bd03c2041a047c044b048603e1040a01c3011101b401ba01c301c101da017f5402a50344033f031203000305033b032b037e03a101470126013c019d0191017fae01a0024102700229026f02b202fa032e032703590346033301700044010e017f440147017101c601c902050240026e0272028802a502c202bd0314030000d5007f3c00df011201360138018601b101cf01ef02030236025f028c029102b802ce027fab010efeb400fc00cb00fb0122014d0176019501b601dc01f902170240024e027f6302b202a8009c0010003f00d500c3013300ff0158015d018401a201c901ef027f17021e024d024a0220ffdcfdfd007d007700d10128010f00f50135013d0171017f8b01a901d901ea01eb02a202c8ffd2003effb5008500f200e100f000d100fe017f0e01390155018101aa01a40224021a007f0017ffe5ff43009500ed00b500bf007f8200c900cd00f90125013e01710171022a027b07630016fc94ff9400c5009b007f97009f007e008d00a600c400e90111013701720128086b03520002ff5800e2007f4200a7006800a3004c004d006b008100b600d00107013d016c05f60309fe6d007f68ffd40089003c005100410033002f00420054007500b300ca013000b908c6027facffdb00d0ffdb0050002c0055000c0061fff6fff3002a0045006c00b600e2007ff9063b038b001cfd9f003a000bfff5fffc0019ffc9001aff80fffdffe2004a007f6a00aa00cd071901eefff50035002dffcb0004fff3fff600000006fffa002fff7f94ffd7003c00900048075701390003ffaefff3000bffff000300000001fff9007f04ffcd003dffebffcdfff800cb04bb019fffffffff000afff60001fffd0001ff7ffc0006ffed0019ffb4001000180006ff600719022b0000fffcfffb00030000007f000002fff8000dffce0028ff9f0047fec600ddfdb70217fd4f000000000005ff7ffcffff0000fffd0006fff60022ffe10047ffab0109fed00319fd2002190000007f00fffa0004000100010002fff7000dffc7001eff9a004efe70008ffbff038ffd7f670000ffff0003fffd0000ffffffff0001000000080006000bfff6005e005dff7ff8feeb009b00000000ffff0001000000000000ffff0001fff80001ffe90008ff7fd0ff9b000c0040ffda0000000000000000000000000000000000000000000000"; bytes constant BASES=hex"7f01ffffc00000000001e667832b6800f401cdad462c0003c501b5cd4902b808627f019ec38bb0680ebb01888cce35f816be017324909448205c015e8752cc382b827f014ab154dea8382201379e56cc80462901254b1896a055870113b35a3de8662b7f0102d35bc338780500f2a75d27808b0400e32b9e6b909f1700d45c1f9050b42d7f00c6352096a8ca3600b8b2a17f78e12100abd1224b98f8dd009f8ca2fbf911597f0093e12391712a850088cb240ce94450007e46a46f415ea900744fa4b96179807f006ae2a4ec2194c40061fba50861b063005996e50f11cc4e0051b0650101e8737f004a44a4df2a04c200434f64aa5a212b003ccd24637a3d9b0036b9e40b725a037f003111a3a31a7652002bd1232b5a92770026f3e2a50aae62002276a21122ca017f001e55217072e544001a8ba0c3db001b001716600c4b1a730013f19f4a9b343e7f0011199e7fab4d69000e8a1dac6b65e5000c3f9cd1ab7da0000a361bf05b948a7f00086a1b095baa920006d75a1d83bfa700057a192dc3d3b900044ed83af3e6b67f0003519745f3f88f00027e564fb409320001d1555904188f000146d462d426947f0000db136e043332000089d27b6c3e5700004fd18bfc47f2000028d0a08c4ff47f0000114fba04564b0000050ed9445ae6000000cdff2c5db5026964e2f539fbc57f02631262ed8a1603025d0222d6f2310a02573262b2024cc20251a2227f3a69177f024c4fa23f2285ef024739a1f242a33402425ee19932c0d0023dbde13462deab7f02395560c46afcae023523e049d31ac30231281fc51b38d1022d609f36d356c47f0229cbde9f7b7482022668ddffa391f6022335dd57d3af080220319ca88bcba27f021d5adbf263e7ac021ab01b35d403100218301a73641db60215d959abac37887f0213aa58df2c506f0211a2180e646853020fbed739ec7f1d020dff56623c94b87f020c625587eca90b020ae654ab74bc0002098a13cd6ccd7f02084bd2ee54dd727f02072ad20eacebc2020625112f14f858020539904ffd031d020466cf71f50bfa7f0203ab4e958d12d70203060dbb45179f0202754ce3ad1a390201f7cc0f3d1a8f7f02018c4b3e8d188b0201314a722514140200e549aa850d150200a748e83d03757f020075882bccf71f02004ec775bce7fb02003186c6a4d5f202001cc61efcc0ed7f02000ec57f4ca8d502000644e8248d94020001c45a0c6f1202000043d58c4d387f041ad9213f7b6cab041759dff9b3a34b04142bde9ae3db3e04114b5d263c13a57f040eb49b9eec4ba4040c635a0814825b040a541864e4b6ed04088296b884e87c7f0406eb550625162904058a5350ed3f1804045b919c05626904035b4fea957f3f7f0402858e3fd594bc0401d68c9edda20204014a8b0ae5a6320400dd898715a06f7f04008b8816958fdb040050c6bc8d7398040029457c2d4ac804001184589d148c7f040005435504d007040000c274947c5b060dd3a0c553b0070609435d292434937f0605d55931c4b899060360550b152fe10601ba90e0fd8e320600baccdf55c7527f060037493215cf07060007060515991a081c21e8ca8a7627080e67625c7375247f0806139a61046e0e0801cd11fb8d1fc00800398a4f7549140a240025471ac71c7f0a0aaad955548e380a01554b6395aaaa0c0e392638e300000e71c72c71c0aaab7f0e0e391e38e3bbbb102aaae9999a2222128888ab60b071c712111127d27ab2cb7f149999a924907507142d82eedb696abc1405b0692492a65516f6db5df15866667f16ad6022f0b8eb0d167425e43f319cab164924a2972a63f6162a541eb2fb29a07f1615ac194d03d65f160924931fb452e51602b58ce55c87e6160056c7586c5e177f1819999df15bdb6d180795d532ad24921800f2cb55e5db6d1a1d41e9249266667f1a03a855965cfa4f1c1c71eb60b222221e8888a99998aaab1e11111ddddbc71c7f202aaaec71c1c71c22c0002638e038e42238e3ad55516c7222071ca471c32aaa7f24b1c72547189000245b05ea48a149ee242666a8fe023f71240b60e370734c207f24016c1ba9244b8e269d89e8ca887087266989ecc8d0c0a22642762e783926427f2626766e3a919bea2613b16c71921c1f26084ee97f0aa16226027665c4cb26387f26004ee1a49ba52428ec01e0c550374e28cd43e3e2d84e9228b150e680386aa07f289806e8a4608b132881436a5640af86286ce4eb9cc0d793285ac92c7ed902d67f284ace2d037930e9283cd1ed319161662830b22d101193ea28264ceca5e1c80d7f281d806bf9f9fd6d28162a2b134a33a2281028a9f8c26a48280b5968b14aa0fa7f28079a6743e2d7532804c9a5b76b0ced2802c56412db416328016b625d2374507f280099609d2ba54e28002d9ed9f3d3fa280005dd1a5bffec2adb2ae146086a937f2ace0562713879c12ac1696381108a312ab553a476309bd22aa9c1a55168ae927f2a9eb0661358c2622a941d26bcc8d7302a8a04a74e68eceb2a8064a7c8f103827f2a7739a82d111ae62a6e81687b8933042a6638a8b5094bcd2a5e5ca8da51652f7f2a56ea68ec117f1a2a4fdf28eaf9997c2a493828d7c9b4462a42f268b339cf657f2a3d0b287e01eaca2a377f6838ca06642a324c67e45a22212a2d6f2781623df27f2a28e527109a59c42a24aae692b275882a20be26086a912d2a1d1ba57272aca17f2a19c0e4d18ac7d42a16aaa4265ae2b62a13d62371a2fd342a1140a2b41b17407f2a0ee761ee7b30c72a0cc721217349b92a0add604dc362052a09271f7413799b7f2a07a19e952b90692a06499db1b3a65f2a051c9cca6bbb6c2a0417dbe003cf7f7f2a03381af33be2872a027ada04c3f4742a01dd19155405352a015bd8259c14b87f2a00f457366422ee2a00a39648542fc52a0067155c243b2d2a003b94729445147f2a001e938c544d6a2a000d12aa14541f2a0003d1cc9c59202a000090f4945c5f7f2c8115a2ee499de02c7abce2ea99b7b72c749a22d849d27b2c6eaca2b7c9ee127f2c68f36289aa0a612c636da24e62274d2c5e1a62067a44bb2c58f8a1b26a628f7f2c5407a152ba80b02c4f4660e7e29f012c4ab3a0726abd682c464f1ff2dadbca7f2c42175f69a2fa0b2c3e0bded74b18122c3a2b5e3c5b35c22c36751d994b53017f2c32e85ceea36fb52c2f83dc3cdb8bc12c2c46db8473a70a2c29305ac5fbc1777f2c263f5a01e3daec2c23735938b3f34d2c20cad86aec0a812c1e45579914206b7f2c1be1d6c39c34f22c199f95eb1c47f92c177d150ffc59662c157a1432cc691e7f2c139553540c77072c11cdd2743483042c1022d193cc8cfb2c0e9350b35c94d17f2c0d1e8fd3549a6b2c0bc34ef4449dae2c0a810e169c9e7f2c09568d3aec9cc37f2c08430c61b4985f2c07458b8b6c91382c065d0ab89c87332c0588c9e9c47a367f2c04c8091f5c6a242c04194859f456e32c037c4799fc40582c02efc6e00426697f2c0272c62c8408f92c0204457ffbe7ef2c01a3c4daf3c32e2c0150043deb9a9d7f2c010843a95b6e202c00cbc31dcb3d9c2c0099029bb308f62c006f8223a2d0137f2c004e41b61292d82c0034815382512b2c002100fc720aef2c001300b169c00b7f2c0009c072e170632c00044041611bdc2c0001401d68c25b2c000040077063c57f2c0000000000000001ffffc00000000002e38e20e3885555021c71ebaeba08207f04e4925f5d708208047507649249924904315f20a28aebae040ea1175d7414517f0401d40c924c92490620821f5d739249060410504105924808155567fffaaaaa7f0a400027fffa00000a0000000000000001ffffc00000000001e79f43055800d77f01d00845e448035101b937089da0076101a3288b32100cfa018dd98da260140d7f0179468fef481c8c01656c521988266a0152479421e8319a013fd51609203e0c7f012e1157cff84bb3011cf95977205a82010c899aff606a6b00fcbedc69787b5f7f00ed959db6208d5100df0b1ee628a03400d11b5ffa38b3f900c3c3a0f328c8927f00b70021d1a0ddf200aace229670f40b009f29e342490acf00941023d5f922307f00897de452393a21007f6f64b7c152930075e1a507596b79006cd16541c184c57f00643b2567b19e6a005c1be579f1b85800546fe57939d283004d34256649ecdd7f0046656541e20757004000250cc221e5003a0124c7aa3c7700346524735a57017f002f28e410927175002a4923a00a8bc50025c263228aa5e20021916298cabfbf7f001db2e2038ad94f001a23a16392f2830016e020b99b0b4e0013e560065b23a27f00112fdf4aa33b71000ebc5e872352ad000c879dbca36948000a8e1cebe37f357f0008ccdc159b94650007405b3a93a8cc0005e51a5b83bc5a0004b859792bcf037f0003b658944be0b80002dc17ada3f16c00022616c5fc011100019115ddfc0f997f00011994f67c1cf50000bcd4102c2919000076d32bd433f7000044d24a2c3d807f000023516bfc45a800000ed091f44c5f0000048fbce451980000008eed8455467f02712462bad9e413026b1522be69fbdd02653e22b5221457025f9ea29f7a2d6e7f025a35627dca4712025501625082612f025001a2180a7bb5024b3521d4d296927f02469aa18732b1b3024231612f9acd07023df820ce7ae87d0239ede0642b04027f0236119ff1231f840232621f75c33af2022ede9ef27b563a022b85de67a3714a7f022856ddd5b38c10022550dd3d13a67b0222725c9e23c078021fba5bf94bd9f67f021d281b4efbf2e3021aba9a9f940b2e02187059eb8422c402164899333439937f0214425877044f8b02125c97b764649802109616f4bc78a9020eedd62f6c8bad7f020d629567e49d92020bf3d49e94ae45020aa053d3d4bdb5020966930814cbd07f020846523bbcd88502073dd16f34e3c102064c50a2e4ed72020570cfd734f5887f0204aa0f0c8cfbf00203f74e435d00980203574d7bfd036e0202c90cb6e504617f02024b8bf47d035f0201ddcb351d005602017e8a793cfb3402012cc9c13cf3e87f0200e7c90d8cea5f0200ae085e8cde8802007f07b4acd05102005947104cbfa87f02003bc671dcac7b02002585d9c496b9020015c548647e5002000b44be2c632e7f020004c43b84454102000183c0cc2477020000434e7c00be0417275ed033c95c7f0414231d8273ff090411655c1f3435a9040eea1aa96c6c44040cae59243ca1e17f040aaed7929cd5880408e815f7a50640040756d4565533110405f792b1bd5b017f0404c7110ce57d190403c20f6ad5985f0402e50dce95abda04022ccc3b35b6947f040195cab3bdb79104011d093b3daddb0400bf07d4ad987804007846832d76707f0400458549bd46ca040023c42b65088d04000f032b2cbac2040004824c245c6e7f04000081915bec9a0607ee5b526c75f806049716b3dd13b506025991ce6da1377f0600fdccf6b6001b06004b48816611fe06000984c31db87d08108426a9aae8ba7f0804e4db24a4745608009c8e728d93320a253caae3620ea10a04a79b134c57c57f0c4924aa0e9999990c092498fd9466660e2222266662aaaa1040002ffff900007f12aaaaa55550aaab1215555d5553bbbb142aaae9999a2222168888a99998aaab7f1611111ddddbbbbb182aaae9999a22221a8888a99998aaab1a11111ddddbbbbb7f1c2aaae9999a22221e8888a99998aaab1e11111ddddbaaaa202aaae55552aaaa7f2240002ffff9000024aaaaa6666088882415556333331fb22666666a0e9924927f260ccce2be2b62692883a86ae36094f2282702ac9991ce512804e063a2b364947f2aba2ea6a9a842102a6bbeadc3e898632a372a708ff1102c2a1745f000d99ed67f2a06e56d09ba39cd2a00dce89daad67b2d1d7e1b52681fb92cf84e1f64d0322b7f2cd67ee2e37049852cb7e725d61065662c9c5de84468856d2c83ba2a3650a9397f2c6dd26bb380d0692c5a7dacc3c0fa9b2c49926d6ed9276f2c3ae7edbc8956837f2c2e54edb4a187762c23afed5ed1b9e72c1acfecc2f9ed752c138bebe8ca21bf7f2c0dba6ad80a56632c093269988a8b002c05caa83202bf352c035a26ac42f2a27f2c01b7650f0b24e42c00b9636223559b2c003721ad4b84652c0006dff84bb0e17f2ef2571ed5785bf32ee55c600c00690d2ed8da612a90773e2ecccf2231c086787f2ec137e3221896b02eb61323fc28a7d82eab5de4c080b9e42ea116656fa8ccc67f2e973a660a28e0722e8dc76690a0f4db2e84bb67039109f32e7c142763891faf7f2e73cf67b11936012e6beaa7ecc94cdc2e6463e8173164332e5d38e830d97bfb7f2e5667683a4994242e4fed283419aca42e49c7e81ed9c56c2e43f5a7fb09de717f2e3e73a7c939f7a52e3940278a0210fb2e3458a73dea2a662e2fbae6e58243da7f2e2b64e681525d4a2e27542611f276a82e23866597e28fe92e1ff9a513baa8fe7f2e1caba48602c1dc2e1999e3ef52da752e16c263502af2bc2e1422e2a91b0aa57f2e11b921fabb22232e0f82a1459339282e0d7d608a2b4fa92e0ba71fc91b65977f2e09fddf02eb7ae62e087ede382b8f8a2e07281d6963a3752e05f75c9723b69b7f2e04ea9bc1fbc8ef2e03ff5aea7bda632e03335a1133eaeb2e02845936a3fa7a7f2e01f0585b6409042e0175178004167a2e010fd6a50c22d12e00bf15cb0c2dfc7f2e008014f29437ed2e0050941c2c40982e002e93486447f02e0017d277cc4de87f2e000a11aaf452732e000310e26455852e0000501eac5710307b02a2b839bcee7f30753ee2ab11d5a0306fa9e29159ef1d306a42e26b72094e3065092239c2241c7f305ffc21fcba3f71305b1b21b4ca5b35305664e1625277523051d92105c293b17f304d76e09f8ab03b30493d60300accd830452c1fb7b2e973304141df36eb05f47f303d7e5eae1b22443039e09e1dbb3e4c303667dd862b59f63033135ce7d3752b7f302fe25c432b8fd4302cd45b988ba9d93029e81ae86bc32530271d1a3333db9f7f30247299794bf3323021e7d8bb1c09c7301f7c17f9141f45301d2e9733a433987f301afe966b2c46a73018eb55a014585c3016f3d4d2d468a03015179403cc775b7f30135613336c84793011add2621c8fe030101ed1904c997b300ea7d0be5ca1327f300d484fecbca6ef300bff8f1bdcaa9b300acc8e4c1cac1f3009aecd7df4ab647f3008a58cb1c4a8533007afcbe7f4a2d53006cd0b20fc9ad33005fc4a5d3c90377f30053d099d1c82e930048e48e11472d43003ef8829845fdf30035fc776d449f47f3002de86c97c30fc30026ac621d414e0300203c5805bf5893001a904e56bd2e17f30015984517bacd1300114c3c4eb83413000d983402b561b3000a782c3ab25477f30007e024fcaf0b030005bc1e4fab83e3000408183a27bda30002b412c2a3b6d7f30001b40df09f6e130000fc09ca1ae1e300008006559610e3000038039a10f9a7f3000010019e8b9ab3000004006885f2a300000000000000001ffffc0000000007f01753f50229825ed010624daae488b9100af9da072b11eb8006e97a23f41cd2e7f00400020e38a84bd0020c49d2f1b3333000dd317f173c65a00041891fa142bfe7f0000830c189451eb0238e3a12f6af684021d209cf833e759020c49d6c8b4cccc7f0203a40fc9b56dfc0200748923e5920304200027fffa800004097b5d1bac1fdb7f04012f8fcc6d4ba90628f5e7ae12666606051ed5678ce93e081c71e71c72aaaa7f0a40002d555155550c55556aaaa955550e55556aaaa955551055556aaaa955557f1255556aaaa955551455556d5551000016aaaaa71c7071c71615556749f2acf17f189999a7ae10a3d7182d82ea5d49f9cd1805b060fedba5741aa0002835e079437f1a51ebad0b49154e1a228f6c44f9e0561a0a3da79aaab8811a0147e0c42b7bf57f1ccbca2046b8c8001c991c222ac154ad1c6f9e21be79fd691c4e649f750aae417f1c34845bc17353461c21125716d3d8851c132391e8442a0e1c09cc8ca8d433ee7f1c042247cb93e2341c013983c3ab20f01c0027410419dc2f1c000000000000007f01ffffc00000000001e79f43055800d701d00845e448035101b937089da007617f01a3288b32100cfa018dd98da260140c0179468fef481c8b01656c52198826697f0152479421e83198013fd51609203e09012e1157cff84baf011cf95977205a7d7f010c899aff606a6400fcbedc69787b5700ed959db6208d4700df0b1ee628a0277f00d11b5ffa38b3e900c3c3a0f328c88000b70021d1a0dddc00aace229670f3f17f009f29e342490ab100941023d5f9220e00897de4523939f9007f6f64b7c152657f0075e1a507596b45006cd16541c1848b00643b2567b19e27005c1be579f1b80e7f00546fe57939d230004d34256649ec810046656541e206f1004000250cc221747f003a0124c7aa3bfc00346524735a567a002f28e4109270e1002a4923a00a8b237f0025c263228aa5320021916298cabf01001db2e2038ad880001a23a16392f1a47f0016e020b99b0a5d0013e560065b229e00112fdf4aa33a5a000ebc5e872351817f000c879dbca36807000a8e1cebe37ddd0008ccdc159b92f70007405b3a93a7457f0005e51a5b83baba0004b859792bcd480003b658944bdee10002dc17ada3ef787f00022616c5fbfeff00019115ddfc0d6800011994f67c1aa40000bcd4102c26a77f000076d32bd43161000044d24a2c3ac7000023516bfc42c900000ed091f449597f0000048fbce44e6b0000008eed8451ef027124629ec9e795026b1522a0f9ff8b7f02653e22964a1832025f9ea27f2a3177025a35625bfa4b49025501622d3265947f025001a1f3328048024b3521ae6a9b5102469aa15f3ab69f024231610612d21d7f023df820a35aedbb0239ede0377b09660236119fc2db250b0232621f45e3409a7f022ede9ec10b5bff022b85de34ab7729022856dda1339204022550dd070bac807f0222725c66a3c68a021fba5bc05be00f021d281b149bf8fe021aba9a63dc11457f02187059ae7c28d002164898f4dc3f8f02144258377c556e02125c9776ac6a5c7f02109616b2ec7e46020eedd5ec94911b020d62952414a2c8020bf3d459dcb33b7f020aa0538e4cc26202096692c1d4d02a02084651f4d4dc8202073dd127bce7577f02064c505afcf098020570cf8ef4f8310204aa0ec40cfe110203f74dfab502257f0203574d334d045c0202c90c6e4d04a302024b8bac0d02e90201ddcaed0cff1a7f02017e8a319cf92502012cc97a34f0f70200e7c8c73ce67f0200ae081924d9aa7f02007f077044ca6602005946cd14b8a102003bc62ff4a4480200258599548d4a7f020015c5099c739502000b44812c5715020004c4008437ba0200018387f415707f0200004317f3f0260415875e3e53e2180412991ce2ec191f040ff1db71b4510b7f040d8ed9edf488c6040b6bd85afcbf3c04098596bc24f3580407d89514ad24067f0406611367f5503104051b91b94576c4040404500bed96ab0403180e633daed17f0402530cc28dbe220401b1cb2d1dc388040130c9a645bdf00400cc083155ac447f04008086d1a58d7004004a858a75605f040026045f1d23fe0400100352ecd7367f040004c2693478f404000081a54408220608535c1d6c5b050604d1576424fcc37f060277925d6d8edf06010a8d618df28d06004f08c8de0900060009c4eb9db36b7f08111126980ae8ba08050e9b1f6c74560800a1ce71e593320a253caae3620ea17f0a04a79b134c604d0c4924ac30c155550c09249edb6bcccc0e555568888199997f0e0aaad8cccc77771022222aaaaa2222128888a99998aaab1211111ddddbbbbb7f142aaae9999a2222168888a99998aaab1611111ddddbbbbb182aaae9999a22227f1a8888a99998aaab1a11111ddddbbbbb1c2aaae9999a22221e8888a99998aaab7f1e11111ddddbbbbb202aaae9999a2222228888aaaaa8888822111123bbbb19997f2466666888815555240cccde6663db6d2655556c30c12492260aaae3026b62697f2883a86ae36094f2282702ac9991ce3c2804e063a2b363ed2aba2ea6980844447f2a6bbead9b589d732a372a704801191b2a1745ef9469ac312a06e56c76fa4bad7f2a00dce7e61aec842d16c15c1d68214d2cf0cca0411034a82cce74a3c7a04d267f2caf8b26b9b06a5e2c93e1a91ff08be42c7b4a2b02f8b1502c65966c6b80da377f2c52982d622106302c42216def8134d12c34036e1c4165af2c28102df11198627f2c1e19ad7689cc7e2c15f16cb55a019b2c0f696bb622374e2c0a532a818a6d2d7f2c0680a92032a2cf2c03c3679ac2d7ca2c01ed65f9e30bb42c00d02446333e227f2c003de2885b6eac2c0007e0c8fb9ce62ef8861e4348557f2eeb369f86e862487f2ede62e0b208702e2ed208e1c5307f242ec625e2c0f88f1d2ebab823a5f0a00b7f2eafbd2474a0b1e22ea532a52da8c4952e9b1625d190d8172e9165a660e0ec5a7f2e881e66dc3901522e7f3ea7442116f22e76c3a799312d2c2e6eab67dbf143f47f2e66f3a80cf15b3d2e5f99e82cc972f92e589be83c018b1c2e51f7283b31a3997f2e4ba9e82ae9bc622e45b1680bb9d56b2e400ba7de31eea62e3ab627a2e208077f2e35ae675a5a21812e30f2a7052a3b062e2c8026a3e2548a2e2854e6371a6dff7f2e246ea5bf5a87592e20caa53d3aa08b2e1d66e4b142b9872e1a41241c0ad2417f2e1757237e22eaab2e14a662d81302b82e122ce22a7b1a5c2e0fe7e175db318a7f2e0dd5a0bad348342e0bf35ff9e35e4d2e0a3f1f33ab73ca2e08b65e68b3889b7f2e0756dd998b9cb52e061e5cc6cbb00a2e050a9bf103c28e2e04195b18bbd4337f2e03485a3e83e4ed2e0294d962fbf4ae2e01fd1886a403692e017e97aa1411127f2e0116d6cddc1d9b2e00c3d5f29428f82e00835518bc331b2e00529440f43bf77f2e002fd36bc443802e00189299bc49a82e000a51cb744e622e000311017c51a27f2e0000903c5c535a307be5229be9bcee307616a29019d5a03070776277a1ef1d7f306b06a252fa094e3065c3622282241c3060ad21e6a23f71305bc2e19fd25b357f305704214e72775230526fe0f2ea93b1304e05a08db2b03b3049c4601f2accd87f3045ab5fa7c2e9733041ba1f27e305f4303def9e9ff32244303a4b5e106b3e4c7f3036cc1d79a359f63033719cdc13752b30303a9c38238fd4302d26db8e3ba9d97f302a351adec3c3253027651a2a33db9f3024b5d970e3f33230222658b34c09c77f301fb617f1d41f45301d64572cec3398301b305664f446a7301919159a5c585c7f30171e14cd8c68a030153e93fef4775b301379932efc84793011ce925e0c8fe07f30103c918c94997b300ec2d0bafca132300d60cfe9aca6ef300c158f191caa9b7f300ae08e49a4ac1f3009c0cd7bb4ab643008b58cafc4a8533007be0be634a2d57f3006d98b1f6c9ad33006074a5bdc9037300546c99bec82e9300496c8e00472d47f3003f6c8289c5fdf30036607760c49f43002e3c6c8d430fc30026f46214c14e07f300207857fe3f5893001ac04e50bd2e130015c04512bacd1300116c3c4ab83417f3000db433ffb561b3000a8c2c383254730007ec24faaf0b030005c81e4e2b83e7f3000410183927bda30002b812c223b6d30001b80df01f6e130000fc09c99ae1e7f300008006559610e3000038039a10f9a3000010019e8b9ab3000004006885f2a7f300000000000000001ffffc000000000016798118338303100f0e65c2570af7c7f0097b4210b8163f20057caa15a3a33a8002cf31e367304b00012f698c50bbd1c7f00059e522acc43000000b3cb8c8c7c6f023079627bdaee9f0214731d7d33f8267f02060f56315cee640200c20e4db58675043c3c6baba99999041969a47d7afe7a7f0407879931345a350400f10d484d0a0e062222235a330c300604445283ad5a357f081861abe2ba22220a8888a99998aaab0a11111ddddbaaaa0c2aaae55552aaaa7f0e40002d555155551055556d5551000012aaaaa55550aaab1215555d5553bbbb7f142aaae9999a2222168888abe2b861861611112ad1aa507518c30c235a3088887f185249285071a93e181861a2d1ab27d218030c57f3d495551a66666c16b8e38e7f1a2b336cff29b0b01a0ccce8af8aa1f51a0199a16733862b1ccb2ca160f0a72f7f1c941d6371093f5d1c6806a2a4e9fae61c45b05f9be2be761c2be2daf55b6eb77f1c19659550b3f0531c0d00cf4d4c27f41c057c498a93fa461c01a004a7db4bf17f1c003401448a01a11c00000000000000ff60ff7eff9cffb0ffc4ffceffd8ffe27fffe7ffecffeffff2fff4fff5fff6fff7fff8fff9fffafffbfffcfffdfffeffff7f0000000100020003000400050006000700080009000a000b000c000e001100147f0019001e00280032003c00500064008200a00000000000000000000000000000"; struct Belief { int256 m; int256 v; int256 fb; int256 fa; int256 sp; int256 r; uint256 t; uint256 cnt; } function getName() external pure override returns(string memory) { unchecked {return "TaylorGaussianPlainSpline";} } function mul(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*b/U;} } function divi(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*U/b;} } function ab(int256 x) internal pure returns(int256){ unchecked {return x<0?-x:x;} } function clip(int256 x,int256 a,int256 b) internal pure returns(int256){ unchecked {return xb?b:x);} } function ln(int256 x) internal pure returns(int256 z){ unchecked { require(x>0); int256 k; while(x< U){x*=2;k--;} while(x>=2*U){x/=2;k++;} int256 y=divi(x-U,x+U); int256 y2=mul(y,y); int256 q=y; z=y; for(int256 n=3;n<=29;n+=2){q=mul(q,y2);z+=q/n;} return 2*z+k*LN2; } } function exp(int256 x) internal pure returns(int256){ unchecked { if(x< -42*U)return 0; require(x<60*U); int256 k=(x>=0?x+LN2/2:x-LN2/2)/LN2; int256 r=x-k*LN2; int256 r2=mul(r,r); int256 even=665280*U+mul(r2,75600*U+mul(r2,840*U+r2)); int256 odd=mul(r,332640*U+mul(r2,10080*U+mul(r2,42*U))); int256 s=divi(even+odd,even-odd); return k>=0?s*int256(uint256(1)<>128>0){z>>=128;r<<=64;} if(z>>64>0){z>>=64;r<<=32;} if(z>>32>0){z>>=32;r<<=16;} if(z>>16>0){z>>=16;r<<=8;} if(z>>8>0){z>>=8;r<<=4;} if(z>>4>0){z>>=4;r<<=2;} if(z>>2>0){r<<=1;} for(uint256 i=0;i<7;i++)r=(r+n/r)/2; return int256(r10*U)return 0;return divi(exp(-mul(x,x)/2),2506628274631000200);} } // Hart rational normal tail approximation; erf(x)=2*Phi(x*sqrt(2))-1. function cdf(int256 x,int256 density) internal pure returns(int256){ unchecked { int256 y=ab(x);if(y>8*U)return x>0?U:int256(0); int256 n=35262496599891000; n=mul(n,y)+700383064443688000;n=mul(n,y)+6373962203531650000; n=mul(n,y)+33912866078383000000;n=mul(n,y)+112079291497871000000; n=mul(n,y)+221213596169931000000;n=mul(n,y)+220206867912376000000; int256 d=88388347648318400; d=mul(d,y)+1755667163182640000;d=mul(d,y)+16064177579207000000; d=mul(d,y)+86780732202946100000;d=mul(d,y)+296564248779674000000; d=mul(d,y)+637333633378831000000;d=mul(d,y)+793826512519948000000; d=mul(d,y)+440413735824752000000; int256 tail=mul(mul(density,2506628274631000200),divi(n,d));return x>0?U-tail:tail; } } function trunc(int256 m,int256 v,int256 lo,int256 hi) internal pure returns(int256 Z,int256 mt,int256 vt){ unchecked { if(v<=0)return (lo<=m&&m<=hi?U:int256(0),m,0); int256 sd=root(v);int256 a=divi(lo-m,sd);int256 b=divi(hi-m,sd); int256 pa=pdf(a);int256 pb=pdf(b); Z=cdf(b,pb)-cdf(a,pa); if(Z<1e6)return(Z,m>57)&31;v.a=int256((x>>38)&524287);v.b=int256((x>>19)&524287);v.c=int256(x&524287);v.d=524287-v.a-v.b-v.c; } } struct Grid {Basis r0;Basis r1;Basis c0;Basis c1;} function fill(int256[5] memory dst,Basis memory b,uint256 start) internal pure { unchecked { uint256 i=b.first-start;dst[i]=b.a;dst[i+1]=b.b;dst[i+2]=b.c;dst[i+3]=b.d; } } function quad(bytes memory data,uint256 cb,uint256 cols,Grid memory g) internal pure returns(int256[4] memory out){ unchecked { uint256 rs=g.r0.firstg.r1.first?g.r0.first+4:g.r1.first+4; uint256 cs=g.c0.firstg.c1.first?g.c0.first+4:g.c1.first+4; int256[5] memory rx;int256[5] memory ry;int256[5] memory cx;int256[5] memory cy; fill(rx,g.r0,rs);fill(ry,g.r1,rs);fill(cx,g.c0,cs);fill(cy,g.c1,cs); for(uint256 a=0;a0?out[z]*U/2199014866952:int256(0); } } function knot(bytes memory data,uint256 j) internal pure returns(int256){ unchecked {return i16(data,8592+2*j)*5*U;} } function fees(int256 w,int256 r,uint256 ph) internal pure returns(int256 fb,int256 fa){ unchecked { bytes memory coeffs=COEFF;bytes memory bases=BASES; int256 p=clip((w+800*U)/5,0,320*U);uint256 i=uint256(p/U);if(i>319)i=319;int256 f=p-int256(i)*U;int256 wc=p*5-800*U; uint256 j;int256 g;uint256 n2; if(ph==0){r=clip(r,-30*U,30*U);p=(r+30*U)/5;j=uint256(p/U);if(j>11)j=11;g=p-int256(j)*U;n2=13;} else{r=clip(r,-800*U,800*U);uint256 lo;uint256 hi=48; while(hi-lo>1){uint256 mid=(hi+lo)/2;if(r>=knot(bases,mid))lo=mid;else hi=mid;} j=lo;g=divi(r-knot(bases,j),knot(bases,j+1)-knot(bases,j));n2=49; } uint256 cb;uint256 cols;uint256 rb;uint256 vb; if(ph==0){cb=53;cols=9;rb=0;vb=2568;} else if(ph==1){cb=585;cols=18;rb=2672;vb=5240;} else{cb=1657;cols=18;rb=5632;vb=8200;} Basis memory r0=basis(bases,rb,i);Basis memory r1=basis(bases,rb,i+1); Basis memory c0=basis(bases,vb,j);Basis memory c1=basis(bases,vb,j+1); int256[4] memory aa=quad(coeffs,cb,cols,Grid(r0,r1,c0,c1)); int256 a0=mul(aa[0],U-f)+mul(aa[1],f); int256 a1=mul(aa[2],U-f)+mul(aa[3],f); int256 af=mul(a0,U-g)+mul(a1,g); Basis memory mr0=basis(bases,rb,320-i);Basis memory mr1=basis(bases,rb,319-i); Basis memory mc0=basis(bases,vb,n2-1-j);Basis memory mc1=basis(bases,vb,n2-2-j); int256[4] memory bb=quad(coeffs,cb,cols,Grid(mr0,mr1,mc0,mc1)); int256 b0=mul(bb[0],U-f)+mul(bb[1],f); int256 b1=mul(bb[2],U-f)+mul(bb[3],f); int256 bf=mul(b0,U-g)+mul(b1,g); int256 bo=bf+w-wc;int256 ao=af+wc-w; fb=bo>0?U-exp(-bo/10000):int256(0);fa=ao>0?U-exp(-ao/10000):int256(0); fb=clip(fb,0,U/10);fa=clip(fa,0,U/10); } } function save(Belief memory b) internal { unchecked { slots[0]=uint256(b.m);slots[1]=uint256(b.v);slots[2]=uint256(b.fb);slots[3]=uint256(b.fa); slots[4]=uint256(b.sp);slots[5]=uint256(b.r);slots[6]=b.t;slots[7]=b.cnt; } } function afterInitialize(uint256 x,uint256 y) external override returns(uint256,uint256){ unchecked { Belief memory b; b.sp=int256(y*1e18/x);b.r=b.sp;b.m=ln(b.sp); b.fb=2809067366013162;b.fa=2809067366013162;save(b);return(uint256(b.fb),uint256(b.fa)); } } struct Work {int256 lo;int256 hi;int256 m;int256 v;int256 lp;int256 la;int256 Z;int256 mt;int256 vt;int256 d;int256 pi;} function update(Belief memory b,int256 s,bool buy,uint256 dt) internal pure returns(bool arb){ unchecked { Work memory q; q.lo=ln(mul(b.sp,U-b.fb));q.hi=ln(divi(b.sp,U-b.fa));q.m=b.m;q.v=b.v; uint256 n=dt-1;if(n>12)n=12; for(uint256 i=0;i0?divi(q.la,q.la+lr):int256(0);arb=q.pi>U/2; if(q.pi>5e15&&q.pi<995e15){ b.m=mul(q.pi,q.lp)+mul(U-q.pi,q.mt); b.v=mul(q.pi,mul(q.lp-b.m,q.lp-b.m))+mul(U-q.pi,q.vt+mul(q.mt-b.m,q.mt-b.m)); }else if(arb){b.m=q.lp;b.v=0;}else{b.m=q.mt;b.v=q.vt;} int256 pe=exp(b.m);b.r=clip(b.r,mul(pe,997e15),divi(pe,997e15));b.cnt=0; } } function afterSwap(TradeInfo calldata t) external override returns(uint256,uint256){ unchecked { Belief memory b=Belief(int256(slots[0]),int256(slots[1]),int256(slots[2]),int256(slots[3]),int256(slots[4]),int256(slots[5]),slots[6],slots[7]); int256 s=int256(t.reserveY*1e18/t.reserveX);bool arb; if(t.timestamp>b.t)arb=update(b,s,t.isBuy,t.timestamp-b.t); uint256 ph; if(!arb){ int256 c=t.isBuy?divi(mul(s,U-b.fb),997e15):divi(mul(s,997e15),U-b.fa); if(t.isBuy?cb.r)b.r=c; b.cnt++;ph=b.cnt==1?1:2; } int256 w=(ln(s)-b.m)*10000;int256 r=(ln(b.r)-b.m)*10000; (b.fb,b.fa)=fees(w,r,ph);b.sp=s;b.t=t.timestamp;save(b); return(uint256(b.fb),uint256(b.fa)); } } } ``` ### scratch/spline_reference.py ```python """Standard-library decoder for the spline coefficients and packed basis shipped in Strategy.sol.""" import re,struct from pathlib import Path Q=524287 PHASES=((53,9,0,2568,13,22,5),(585,18,2672,5240,49,24,14),(1657,18,5632,8200,49,24,14)) def _literal(source,name,size): enc=bytes.fromhex(re.search(r'bytes constant '+name+r'=hex"([0-9a-f]+)"',source)[1]) return b''.join(enc[i+1:i+33] for i in range(0,len(enc),33))[:size] def _tables(path): source=Path(path).read_text() coeff=_literal(source,'COEFF',2665) bases=_literal(source,'BASES',8690) w2l=list(struct.unpack_from('>49h',bases,8592)) out={'H_bps':5.,'NW':321,'W0':160,'N2':49,'C2':24,'FB':6,'W2L':w2l, 'g':0.05368206098114493,'lam':0.8,'sigma':9.45,'size':20.0} return coeff,bases,out def _basis(x,inner,hi): knots=[0]*4+list(inner)+[hi]*4 b=[int(knots[i]<=x>57)&31;a=(x>>38)&Q;b=(x>>19)&Q;c=x&Q return [(first+k,v) for k,v in enumerate((a,b,c,Q-a-b-c)) if v] def decode(path='contracts/src/Strategy.sol',packed=False): """Return pol_mid-style tables; packed=True evaluates the shipped Q-basis exactly.""" coeff,bases,out=_tables(path) for ph,(cb,mv,rb,vb,n2,nu,nv) in enumerate(PHASES): C=struct.unpack_from('>'+str((nu+4)*mv)+'h',coeff,cb) if packed: rows=[_basis_packed(bases,rb,i) for i in range(321)] cols=[_basis_packed(bases,vb,j) for j in range(n2)] else: offset=2 if ph==0 else (521 if ph==1 else 1593) ku=struct.unpack_from('>'+str(nu)+'H',coeff,offset+2) kv=list(coeff[offset+2+2*nu:offset+2+2*nu+nv]) rows=[_basis(i,ku,320) for i in range(321)] cols=[_basis(j,kv,n2-1) for j in range(n2)] fee=[] for ru in rows: line=[] for cv in cols: v=sum(C[a*mv+b]*wa*wb for a,wa in ru for b,wb in cv) line.append(max(0.,v/(8*Q*Q) if packed else v/8)) fee.append(line) out['A%d'%ph]=[[round((i-160)*5+v,6) for v in line] for i,line in enumerate(fee)] if not packed else [[(i-160)*5+v for v in line] for i,line in enumerate(fee)] out['B%d'%ph]=[[round(-(i-160)*5+v,6) for v in line] for i,line in enumerate(fee[::-1]) for line in [line[::-1]]] if not packed else [[-(i-160)*5+v for v in line[::-1]] for i,line in enumerate(fee[::-1])] return out ``` ### scratch/standalone.py ```python """Taylor (gtmcknight) Gaussian plain filter with the original smooth-2d decoded spline table. Standard library only; spline_reference reads the COEFF and BASES literals in Strategy.sol. """ import math from spline_reference import decode SIG2=.000945**2 LD_M,LD_S=math.log(11.12e-4),1.176 def phi(x):return math.exp(-.5*x*x)/math.sqrt(2*math.pi) def Phi(x):return .5*(1+math.erf(x/math.sqrt(2))) def trunc(m,v,lo,hi): if v<=0:return float(lo<=m<=hi),m,0. sd=math.sqrt(v);a=(lo-m)/sd;b=(hi-m)/sd;z=Phi(b)-Phi(a) if z<1e-12:return z,lo if m=W[48]:p2=48. else: lo,hi=0,48 while hi-lo>1: mid=(lo+hi)//2 if v>=W[mid]:lo=mid else:hi=mid p2=lo+(v-W[lo])/(W[hi]-W[lo]) n2=13 if ph==0 else 49;j=min(n2-2,int(p2));g=p2-j def bi(tab): return (tab[i][j]*(1-f)+tab[i+1][j]*f)*(1-g)+(tab[i][j+1]*(1-f)+tab[i+1][j+1]*f)*g a,b=bi(A),bi(B) return (min(.1,1-math.exp(-(b+w)*1e-4)) if b>-w else 0.,min(.1,1-math.exp(-(a-w)*1e-4)) if a>w else 0.) def init(self,*args): self.fb,self.fa=self._fees(0,0,0);return self.fb,self.fa def on_trade(self,is_buy,ax,ay,t,x,y,arb=False,p=100.,s2=100.,j=0): s=y/x;dt=t-self.tlast;is_arb=False if dt>=1: self.cnt=0;lo=math.log(self.sp*(1-self.fb));hi=math.log(self.sp/(1-self.fa));m,v=self.m,self.v for _ in range(min(dt-1,12)): v+=SIG2;_,m,v=trunc(m,v,lo,hi) v+=SIG2 lp=math.log(s*(1-self.fb)) if is_buy else math.log(s/(1-self.fa));sd=math.sqrt(v) la=phi((lp-m)/sd)/sd;Z,mt,vt=trunc(m,v,lo,hi);d=max(abs(math.log(s/self.sp)),1e-9) lr=Z*.26*phi((math.log(d)-LD_M)/LD_S)/(d*LD_S) pi=la/(la+lr) if la+lr>0 else 0.;is_arb=pi>.5 if .0052 else 'contracts/src/Strategy.sol') n=int(sys.argv[1]) if len(sys.argv)>1 else 1 out=[] for seed in range(70000,70000+n): row=gate(seed,c);out.append(row);print(row,flush=True) (HERE/'gateF.json').write_text(json.dumps(out)) ``` ### scratch/replica_compare_spline.py ```python import sys,json,math,time from pathlib import Path from multiprocessing import Pool sys.path.insert(0,str(Path('../taylor/research/solved').resolve())) import real from spline_reference import decode base=Path('../taylor/research/solved/pol_mid.json').resolve();quant=Path('scratch/quant_decoded.json').resolve() if not quant.exists():quant.write_text(json.dumps(decode(packed=True))) start,end=map(int,sys.argv[1:3]);seeds=list(range(start,end));dest=Path(f'scratch/replica_{start}_{end}.json') assert not dest.exists() t=time.time() with Pool(8) as pool: def run(path): tasks=[(str(path),{'soft':1.0},seeds[i:i+8]) for i in range(0,len(seeds),8)] return {r[0]:r[1] for part in pool.map(real.ev,tasks) for r in part} full=run(base);comp=run(quant) diffs=[(s,comp[s]-full[s]) for s in seeds];m=sum(x[1] for x in diffs)/len(diffs);se=math.sqrt(sum((x[1]-m)**2 for x in diffs)/(len(diffs)-1)/len(diffs)) out={'start':start,'end':end,'n':len(diffs),'mean_diff':m,'se':se,'worst5':sorted(diffs,key=lambda x:x[1])[:5],'mean_full':sum(full.values())/len(full),'mean_comp':sum(comp.values())/len(comp),'seconds':time.time()-t} dest.write_text(json.dumps(out,indent=2));print(out,flush=True) ``` ### scratch/engine.py ```python import sys,json,math,time,hashlib from pathlib import Path import amm_sim_rs from amm_competition.competition.match import MatchRunner from amm_competition.competition.config import BASELINE_VARIANCE,build_base_config from amm_competition.evm.compiler import SolidityCompiler from check import compiled,HERE def vanilla(): s=Path('contracts/src/VanillaStrategy.sol').read_text() c=SolidityCompiler().compile(s,contract_name='VanillaStrategy') assert c.success,c.errors return c.bytecode def configs(start,end): # _build_configs seeds parameter variability with np.default_rng(i). # Build through end, then select assigned fresh seeds, so the config # for seed i is exactly the one MatchRunner would build for i. # Equivalent direct transcription avoids allocating 9.5M configs. import numpy as np base=build_base_config(seed=None);v=BASELINE_VARIANCE;out=[] for seed in range(start,end): rng=np.random.default_rng(seed) size=rng.uniform(v.retail_mean_size_min,v.retail_mean_size_max) rate=rng.uniform(v.retail_arrival_rate_min,v.retail_arrival_rate_max) sig=rng.uniform(v.gbm_sigma_min,v.gbm_sigma_max) out.append(amm_sim_rs.SimulationConfig(n_steps=base.n_steps,initial_price=base.initial_price,initial_x=base.initial_x,initial_y=base.initial_y,gbm_mu=base.gbm_mu,gbm_sigma=sig,gbm_dt=base.gbm_dt,retail_arrival_rate=rate,retail_mean_size=size,retail_size_sigma=base.retail_size_sigma,retail_buy_prob=base.retail_buy_prob,seed=seed)) return out if __name__=='__main__': kind=sys.argv[1];start,end=map(int,sys.argv[2:4]) assert 9520000<=start$R/env.sh;. $R/env.sh command -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/;} W=amm_sim_rs-0.1.0.post1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl;curl -LsSf https://github.com/gtmcknight/amm-sim/releases/download/sim-6b6921f8/$W -o $R/$W echo "aedb68280aca34c110968f00148387c95885207913fb2cf19a1ab4c5cfd6887a $R/$W"|sha256sum -c - uv venv --python 3.12 .venv;uv pip install $R/$W numpy numba cma py-solc-x==2.1.0 pyrevm==0.3.7;uv pip install --no-deps -e . python -c "import solcx;solcx.install_solc('0.8.24')" amm-match validate contracts/src/StarterStrategy.sol ```