blockulator

Ladder

13 scenarios, 87 inputs, N from 1 to 10,000, every cell against 200-digit arithmetic.

Each scenario is measured twice: against the exact inputs, which is what a protocol sees, and against the inputs as each format rounds them, which isolates the arithmetic. The chart covers every input; the table below it is the reference input, cell by cell.

9,384 cells checked live on Sepolia at block 11,928,247, 0 mismatches. 2026-10-16, runner 0xfcdf2f18…. Re-run: uv run scripts/ladder/livecap.py

How this was measured
truth
For every scenario, input and N the same loop is run in exact real arithmetic with mpmath at 300 decimal digits (scripts/ladder/ladder.py), from the exact rational parameters in scenarios.json. Closed forms are used where the loop has one (compounding, the cumulative product, the geometric mean, the round trip, per-second and continuous accrual, the option walk and the decay); the bonding curve, the amortising loan and the Black-Scholes chain are stepped.
rounding
Each library receives the parameters floored into its own representation (2^-128, 2^-64, 10^-18 or 10^-27 units, or the nearest float for ABDKMathQuad and FP256; scripts/ladder/inputs.json). truthFormat is the exact loop started from those floored parameters, so digitsFormat measures the library's arithmetic alone, while digits measures what a protocol sees: the format's rounding of the inputs plus the arithmetic.
digits
digits = floor(-log10 |v - t| / |t|), the number of correct leading significant digits by relative error, capped at 100, which is reported as exact. It is not a string comparison: a value can be correct to 36 digits while its 37th printed digit happens to agree with the truth, or while a carry makes the printed prefix differ earlier.
agree
agree is the count of leading significant digits of the printed value (42 significant digits) that are literally equal to the printed truth. The demo page colours the rest of the value with it. It is a reading aid, not a measurement: a carry across 0.999… / 1.000… gives 0.
gas
gasTotal is measured inside the adapter around the scenario function (the parameter reads and the loop), after the runner has warmed the adapter and the FP127 object, so the call into the adapter and the ABI decoding are excluded. The FP127 (deployed) form includes one staticcall per op; FP127Lib and the other libraries are internal calls. Aave, Morpho and Maker answer only the accrual scenarios their models describe and report Unsupported elsewhere, which the tables show as a revert. gasPerStep = gasTotal / N. Reverted cells carry no gas.
live
LadderRunner.run(scenario, form, n, p) on Sepolia executes any cell with one eth_call and returns (ok, raw, reason, gasPerStep, gasTotal). scripts/ladder/livecap.py sends every cell's floored parameters p and compares the returned raw word with the committed one bit for bit (or the revert selector for a reverted cell). liveMaxN is the largest N per form the public RPC completed within its gas limit, measured by scripts/ladder/livecap.py.
reproduce
make ladder regenerates ladder.json and ladder.md from the Foundry harness (test/ladder/Ladder.t.sol) and this script; make ladder-check fails CI when the committed dataset differs. Versions of every library and of forge are recorded in the dataset. Generated 2026-10-15; versions: aave aave-v3-origin@8305565ae342 (MathUtils, transcribed), abdk v3.2, balancer balancer-v3-monorepo@2b9ce4b1b8ad (LogExpMath.sol, vendored), forge forge Version: 1.7.1, fp127 60e7ec3, huff sepolia:0xfae694D0c2c44181791F838c54Ed64C3151FfE30@11857616, maker dss pot.sol rpow via solady v0.1.26, morpho morpho-blue@8e26ca6a8dbc (MathLib, transcribed), prb-math v4.2.0, solady v0.1.26.

Daily compound interest

Step: b = b * (1 + r). Result: balance after N days.

Per-block or per-day accrual in every lending protocol: one mul per step, N steps.

Over all 10 inputs

Line: median correct digits over the inputs; band: the range; capped at 80 on the axis. FP127Lib coincides with FP127 and is not drawn. A missing point means every input reverted at that N. FP127 emerald, Solady gold, ABDK sapphire, PRBMath red, Quad violet, Balancer teal, Aave orange, Morpho plum, Maker slate, FP256 black, labelled at the line end; Aave, Morpho and Maker appear only on the accrual scenarios their models describe. Hover a point for the numbers.
NFP127FP127LibABDKSoladyPRBMathQuadBalancerAaveMorphoMakerFP256
1 38 (35–39) 38 (35–39) 19 (16–20) 18 (15–19) 18 (15–19) 33 (33–35) 18 (15–19) — 10 rev — 10 rev 27 (24–28) 71 (71–71)
2 38 (35–38) 38 (35–38) 19 (15–19) 18 (14–19) 18 (14–19) 33 (33–34) 18 (14–19) — 10 rev — 10 rev 26 (25–27) 71 (71–71)
5 38 (35–38) 38 (35–38) 18.5 (15–19) 18 (14–19) 18 (14–19) 33 (32–33) 18 (14–19) — 10 rev — 10 rev 26 (24–27) 70 (70–71)
10 37 (34–38) 37 (34–38) 18 (15–19) 17 (14–18) 17 (14–18) 32 (32–33) 17 (14–18) — 10 rev — 10 rev 26 (24–26) 70 (70–71)
20 37 (34–37) 37 (34–37) 18 (15–18) 17 (13–18) 17 (13–18) 32 (32–32) 17 (13–18) — 10 rev — 10 rev 26 (24–26) 70 (70–70)
50 37 (34–37) 37 (34–37) 17.5 (14–18) 17 (13–18) 17 (13–18) 32 (31–32) 17 (13–18) — 10 rev — 10 rev 25 (24–26) 69 (69–70)
100 36 (33–37) 36 (33–37) 17 (14–18) 16 (13–17) 16 (13–17) 31 (31–32) 16 (13–17) — 10 rev — 10 rev 25 (24–25) 69 (69–69)
365 36 (33–36) 36 (33–36) 16.5 (14–17) 16 (12–17) 16 (12–17) 31 (31–31) 16 (12–17) — 10 rev — 10 rev 24 (24–25) 68 (68–69)
1000 35 (32–36) 35 (32–36) 16 (13–17) 15 (12–16) 15 (12–16) 30 (30–31) 15 (12–16) — 10 rev — 10 rev 24 (24–24) 68 (68–68)
10000 34 (32–35) 34 (32–35) 15 (13–16) 14 (11–15) 14 (11–15) 29 (29–30) 14 (11–15) — 10 rev — 10 rev 23 (23–23) 67 (67–67)

Median (min–max) correct digits over the inputs, capped at 80; "rev" counts inputs that reverted at that N and are excluded.

The inputs and the ops
inputparameterswhy
reference referenceprincipal = 10000, rate = 0.1/365$10,000 at 10% APR, the headline cell
tiny-lowprincipal = 1, rate = 0.01/365one unit at 1%: the integer part is small, the fraction carries everything
tiny-highprincipal = 1, rate = 0.5/365one unit at 50%
mid-1pctprincipal = 10000, rate = 0.01/365a slow rate: the per-step factor is close to 1
mid-5pctprincipal = 10000, rate = 0.05/365a typical lending rate
mid-50pctprincipal = 10000, rate = 0.5/365a high rate: the balance grows 150x by N = 10,000
largeprincipal = 1000000, rate = 0.1/365a million-unit position
hugeprincipal = 100000000, rate = 0.1/365a hundred-million-unit pool
huge-highprincipal = 100000000, rate = 0.5/365the largest balance the ladder reaches, near 10^14
fractionprincipal = 0.001, rate = 0.1/365a sub-unit balance: leading zeros in WAD

Library calls per step: FP127 mul; FP127Lib mul; ABDK mul; Solady sMulWad; PRBMath mul; Quad mul; Balancer mulDown; Aave unsupported; Morpho unsupported; Maker rpow, rmul; FP256 mul. Parameters reach each adapter floored into its representation (ladder-inputs.json).

The reference input in full: principal = 10000, rate = 0.1/365

Each cell: the value with the digits that agree with the truth in ink and the rest in red; below it, correct digits against the exact truth, against the format-rounded truth, the signed error in units of the last place, and gas per step.

NtruthFP127 (deployed, staticcall)FP127Lib (inline)ABDKMath64x64Solady FixedPointMathLibPRBMath SD59x18ABDKMathQuad (binary128)Balancer LogExpMathAave v3 MathUtils (RAY)Morpho Blue MathLibMaker rpow (RAY)FP256 (float, inline)
1 10002.7397260273972602739726027397260273973 10002.7397260273972602739726027397260273831
38 digits · exact vs format · -4810.96 ULP · 2148 gas/step
10002.7397260273972602739726027397260273831
38 digits · exact vs format · -4810.96 ULP · 888 gas/step
10002.7397260273972600785191700012433102529
19 digits · exact vs format · -3605.48 ULP · 934 gas/step
10002.73972602739726
19 digits · exact vs format · -273.973 ULP · 744 gas/step
10002.73972602739726
19 digits · exact vs format · -273.973 ULP · 1104 gas/step
10002.7397260273972602739726027397248603154
33 digits · 33 vs format · ULP · 2933 gas/step
10002.73972602739726
19 digits · exact vs format · -273.973 ULP · 1015 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10002.7397260273972602739726
27 digits · exact vs format · -2739.73 ULP · 610 gas/step
10002.7397260273972602739726027397260273973
71 digits · 71 vs format · ULP · 2901 gas/step
2 10005.4802026646650403452805404391067742541 10005.4802026646650403452805404391067742258
38 digits · 42 vs format · -9625.4 ULP · 1885 gas/step
10005.4802026646650403452805404391067742258
38 digits · 42 vs format · -9625.4 ULP · 623 gas/step
10005.4802026646650399542451230494588543252
19 digits · 23 vs format · -7213.33 ULP · 610 gas/step
10005.480202664665039797
19 digits · 22 vs format · -548.281 ULP · 488 gas/step
10005.480202664665039797
19 digits · 22 vs format · -548.281 ULP · 848 gas/step
10005.480202664665040345280540439104093104
33 digits · 33 vs format · ULP · 1974 gas/step
10005.480202664665039797
19 digits · 22 vs format · -548.281 ULP · 759 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10005.48020266466504034528053
26 digits · 27 vs format · -10439.1 ULP · 420 gas/step
10005.4802026646650403452805404391067742541
71 digits · 71 vs format · ULP · 2067 gas/step
5 10013.7061382924386210524857642965155424808 10013.7061382924386210524857642965155424101
38 digits · 42 vs format · -24083.1 ULP · 1727 gas/step
10013.7061382924386210524857642965155424101
38 digits · 42 vs format · -24083.1 ULP · 464 gas/step
10013.7061382924386200740608440784562560566
19 digits · 23 vs format · -18048.8 ULP · 415 gas/step
10013.706138292438619679
18 digits · 21 vs format · -1373.49 ULP · 335 gas/step
10013.706138292438619679
18 digits · 21 vs format · -1373.49 ULP · 695 gas/step
10013.7061382924386210524857642965089797718
33 digits · 33 vs format · ULP · 1398 gas/step
10013.706138292438619679
18 digits · 21 vs format · -1373.49 ULP · 606 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10013.70613829243862105248574
26 digits · 26 vs format · -24296.5 ULP · 197 gas/step
10013.7061382924386210524857642965155424808
70 digits · 70 vs format · ULP · 1566 gas/step
10 10027.4310624075663873328585783270357249574 10027.4310624075663873328585783270357248157
37 digits · 41 vs format · -48232.5 ULP · 1674 gas/step
10027.4310624075663873328585783270357248157
37 digits · 41 vs format · -48232.5 ULP · 411 gas/step
10027.4310624075663853733086060271428863189
18 digits · 22 vs format · -36147.3 ULP · 350 gas/step
10027.431062407566384582
18 digits · 21 vs format · -2750.86 ULP · 284 gas/step
10027.431062407566384582
18 digits · 21 vs format · -2750.86 ULP · 644 gas/step
10027.43106240756638733285857832702353373
32 digits · 32 vs format · ULP · 1206 gas/step
10027.431062407566384582
18 digits · 21 vs format · -2750.86 ULP · 555 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10027.43106240756638733285853
26 digits · 26 vs format · -48327.0 ULP · 121 gas/step
10027.4310624075663873328585783270357249574
70 digits · 70 vs format · ULP · 1399 gas/step
20 10054.9373711336135548503369243222913751056 10054.9373711336135548503369243222913748213
37 digits · 41 vs format · -96731.2 ULP · 1648 gas/step
10054.9373711336135548503369243222913748213
37 digits · 41 vs format · -96731.2 ULP · 384 gas/step
10054.937371133613550920398935217825453492
18 digits · 22 vs format · -72494.6 ULP · 318 gas/step
10054.937371133613549333
18 digits · 21 vs format · -5517.34 ULP · 258 gas/step
10054.937371133613549333
18 digits · 21 vs format · -5517.34 ULP · 618 gas/step
10054.9373711336135548503369243222684323598
32 digits · 32 vs format · ULP · 1110 gas/step
10054.937371133613549333
18 digits · 21 vs format · -5517.34 ULP · 529 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10054.93737113361355485033684
26 digits · 26 vs format · -84322.3 ULP · 68 gas/step
10054.9373711336135548503369243222913751056
70 digits · 70 vs format · ULP · 1316 gas/step
50 10137.9098421416552959332725454243516547326 10137.909842141655295933272545424351654016
37 digits · 41 vs format · -243824.0 ULP · 1632 gas/step
10137.909842141655295933272545424351654016
37 digits · 41 vs format · -243824.0 ULP · 368 gas/step
10137.9098421416552860271844023476450757926
18 digits · 21 vs format · -182735.0 ULP · 298 gas/step
10137.909842141655282022
17 digits · 20 vs format · -13911.3 ULP · 243 gas/step
10137.909842141655282022
17 digits · 20 vs format · -13911.3 ULP · 603 gas/step
10137.9098421416552959332725454242952441686
32 digits · 32 vs format · ULP · 1053 gas/step
10137.909842141655282022
17 digits · 20 vs format · -13911.3 ULP · 514 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10137.90984214165529593327234
25 digits · 26 vs format · -205424.0 ULP · 31 gas/step
10137.9098421416552959332725454243516547326
69 digits · 69 vs format · ULP · 1266 gas/step
100 10277.721596739264220164675884991779643531 10277.7215967392642201646758849917796420782
36 digits · 40 vs format · -494375.0 ULP · 1627 gas/step
10277.7215967392642201646758849917796420782
36 digits · 40 vs format · -494375.0 ULP · 363 gas/step
10277.7215967392642000792805576092625585716
17 digits · 21 vs format · -370510.0 ULP · 292 gas/step
10277.721596739264191958
17 digits · 20 vs format · -28206.7 ULP · 238 gas/step
10277.721596739264191958
17 digits · 20 vs format · -28206.7 ULP · 598 gas/step
10277.7215967392642201646758849916676515892
31 digits · 31 vs format · ULP · 1034 gas/step
10277.721596739264191958
17 digits · 20 vs format · -28206.7 ULP · 509 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 10277.72159673926422016467546
25 digits · 25 vs format · -424992.0 ULP · 17 gas/step
10277.721596739264220164675884991779643531
69 digits · 69 vs format · ULP · 1249 gas/step
365 11051.5578161626437393801159668054461177946 11051.5578161626437393801159668054461120925
36 digits · 40 vs format · -1.94032e+6 ULP · 1624 gas/step
11051.5578161626437393801159668054461120925
36 digits · 40 vs format · -1.94032e+6 ULP · 359 gas/step
11051.5578161626436605492209384882240641446
17 digits · 21 vs format · -1.45417e+6 ULP · 287 gas/step
11051.557816162643628692
16 digits · 19 vs format · -110688.0 ULP · 234 gas/step
11051.557816162643628692
16 digits · 19 vs format · -110688.0 ULP · 594 gas/step
11051.5578161626437393801159668049905361029
31 digits · 31 vs format · ULP · 1020 gas/step
11051.557816162643628692
16 digits · 19 vs format · -110688.0 ULP · 505 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 11051.5578161626437393801143
24 digits · 25 vs format · -1.66681e+6 ULP · 6 gas/step
11051.5578161626437393801159668054461177946
68 digits · 68 vs format · ULP · 1237 gas/step
1000 13151.2942008121758666272801482974151894245 13151.2942008121758666272801482974151708344
35 digits · 39 vs format · -6.32587e+6 ULP · 1624 gas/step
13151.2942008121758666272801482974151708344
35 digits · 39 vs format · -6.32587e+6 ULP · 358 gas/step
13151.294200812175609621539323218497585799
16 digits · 20 vs format · -4.74092e+6 ULP · 286 gas/step
13151.294200812175505839
16 digits · 19 vs format · -360788.0 ULP · 233 gas/step
13151.294200812175505839
16 digits · 19 vs format · -360788.0 ULP · 593 gas/step
13151.2942008121758666272801482960083685618
30 digits · 30 vs format · ULP · 1016 gas/step
13151.294200812175505839
16 digits · 19 vs format · -360788.0 ULP · 504 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 13151.29420081217586662727473
24 digits · 24 vs format · -5.4183e+6 ULP · 2 gas/step
13151.2942008121758666272801482974151894245
68 digits · 68 vs format · ULP · 1234 gas/step
10000 154769.34069144112806190764064318746174622 154769.340691441128061907640643187459558592
34 digits · 39 vs format · -7.44411e+8 ULP · 1641 gas/step
154769.340691441128061907640643187459558592
34 digits · 39 vs format · -7.44411e+8 ULP · 358 gas/step
154769.340691441097818583337575315539424992
15 digits · 20 vs format · -5.57891e+8 ULP · 286 gas/step
154769.340691441085644663
15 digits · 18 vs format · -4.24172e+7 ULP · 233 gas/step
154769.340691441085644663
15 digits · 18 vs format · -4.24172e+7 ULP · 593 gas/step
154769.340691441128061907640643019251346999
29 digits · 29 vs format · ULP · 1015 gas/step
154769.340691441085644663
15 digits · 18 vs format · -4.24172e+7 ULP · 504 gas/step
reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 reverts Unsupported(uint8): the library has no model for this scenario 0x7bb9ae15 154769.34069144112806190700363
23 digits · 23 vs format · -6.37013e+8 ULP · 0 gas/step
154769.34069144112806190764064318746174622
67 digits · 67 vs format · ULP · 1233 gas/step

Full dataset: ladder.json. Regenerate with make ladder.