38 digits fixed, 71 floating
FP127 is fixed point with 128 bits after the point. FP19 is a 256-bit float that reaches 10±78,913. WAD gives the fraction 60 bits.
Against 300-digit arithmetic
FP127, FP19 and 15 other libraries, run through 14 scenarios of up to 10,000 steps each.
Deploy it or inline it
Each format is one Yul source, built into a deployed contract and an inline library that are fuzzed equal on every int256.
No owner, no upgrades
No contract has storage, a proxy or an admin key. A new version gets a new address, and the old ones stay.
Leave a market alone and its interest goes wrong
Put $10,000 in at 5% a year and accrue it in one step after N days. Aave and Morpho approximate ex with three terms, so the longer a market waits for an update, the fewer digits survive: after 10,000 days, one. FP127 and FP19 lose less than two digits over the whole range.
Correct digits against exact arithmetic, each capped at what the library's format holds. OpenZeppelin, Uniswap and Maker have no exponential, so they are not here. The input is the continuous-accrual scenario's; data: ladder.json.
Every library, every N
| library · correct digits after | 1 day | 10 days | 100 days | 365 days | 1,000 days | 10,000 days |
|---|---|---|---|---|---|---|
| Floating point | ||||||
| FP19 | 71.2 | 71.3 | 71.3 | 71.3 | 71.3 | 71.3 |
| ABDKMathQuad | 33.8 | 33.6 | 34.0 | 33.6 | 33.6 | 33.3 |
| Fixed point | ||||||
| FP127 | 38.6 | 38.6 | 38.6 | 38.5 | 38.0 | 37.1 |
| ABDK 64.64 | 19.1 | 18.9 | 19.0 | 19.3 | 18.8 | 17.8 |
| Solady | 18.3 | 18.7 | 18.2 | 18.1 | 18.1 | 17.9 |
| Solmate | 18.3 | 18.7 | 18.2 | 18.1 | 18.1 | 17.9 |
| PRBMath SD | 18.3 | 17.9 | 17.7 | 18.1 | 17.7 | 17.7 |
| PRBMath UD | 18.3 | 17.9 | 17.7 | 18.1 | 17.7 | 17.7 |
| snekmate | 18.3 | 18.7 | 18.2 | 18.1 | 18.1 | 17.9 |
| Balancer | 18.3 | 18.7 | 18.2 | 18.1 | 18.1 | 17.9 |
| Aave | 16.8 | 12.8 | 8.8 | 6.6 | 4.8 | 1.2 |
| Morpho | 13.7 | 12.5 | 8.8 | 6.6 | 4.8 | 1.2 |
Twice the digits, and competitive on gas
FP127 carries twice the digits of every 18-decimal library and costs less than PRBMath's SD59x18 on add, mul, div, exp, ln, pow and sqrt. FP19 carries twice binary128's digits and costs less than ABDKMathQuad on add, mul, div, exp, ln and pow. Solady is cheaper than both, at 18 digits.
Each dot is a library: the digits its format holds at 1, against its gas as a multiple of FP127's over the ops both offer; hover for the range. Median of inline calls over random inputs that take no shortcut (t). Aave, Morpho and Maker are formulas inside protocols, so they have no gas. Every op: per op; data: gas.json, fp19/gas.json.
Gas per call, 24 ops
| Floating point | Fixed point | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| op · gas per call | FP19 | Quad | FP127 | 64.64 | Solady | Solmate | PRB SD | PRB UD | snek | Balancer | OZ | Uniswap |
| digits at 1 | 71 | 34 | 38 | 19 | 18 | 18 | 18 | 18 | 18 | 18 | 18 | 18 |
add | 662 | 765 | 128 | 162 | 3 | — | 189 | 150 | — | — | — | — |
mul | 530 | 688 | 267 | 171 | 126 | 131 | 485 | 237 | — | — | — | — |
div | 800 | 818 | 412 | 221 | 93 | 97 | 509 | 261 | — | — | — | — |
expᵗ | 3,278 | 5,808 | 2,716 | 3,380 | 430 | 430 | 2,816 | 2,720 | 604 | 1,040 | — | — |
lnᵗ | 3,043 | 16,335 | 1,944 | 7,080 | 556 | 632 | 7,083 | 6,474 | 1,226 | 1,091 | — | — |
powᵗ | 5,901 | 23,597 | 3,317 | — | 1,279 | 1,355 | 10,065 | 9,544 | — | 2,223 | — | — |
sqrtᵗ | 1,205 | 759 | 469 | 828 | 393 | 456 | 978 | 824 | — | 2,349 | 766 | — |
avg | 663 | — | 114 | 31 | 60 | — | 154 | 105 | 113 | — | 318 | — |
abs | 133 | 21 | 140 | 120 | 18 | — | 121 | — | — | — | 18 | — |
divDown | 987 | — | 475 | — | 87 | 150 | — | — | 323 | — | 239 | 179 |
divUp | 988 | — | 478 | — | 113 | 176 | — | — | 386 | — | 621 | 282 |
inv | 747 | 1,259 | 242 | 202 | 93 | — | 177 | 94 | — | — | — | — |
log2ᵗ | 2,822 | 15,553 | 1,723 | 6,990 | — | — | 6,724 | 6,402 | — | 1,908 | — | — |
mulDown | 727 | — | 315 | — | 86 | 150 | — | — | 323 | — | 239 | 179 |
mulUp | 728 | — | 337 | — | 110 | 176 | — | — | 386 | — | 621 | 282 |
powuᵗ | 6,631 | — | 5,189 | 3,133 | 2,318 | 2,559 | 4,006 | 3,881 | — | — | — | — |
sub | 745 | 1,236 | 140 | 162 | 3 | — | 187 | 150 | — | — | — | — |
exp2ᵗ | 3,096 | 5,073 | 2,668 | 3,225 | — | — | 2,671 | 2,557 | — | — | — | — |
gavg | 2,099 | — | 1,079 | 833 | 449 | — | 960 | 949 | — | — | — | — |
cbrtᵗ | 2,734 | — | 1,936 | — | 619 | — | — | — | 1,424 | 2,311 | — | — |
log10ᵗ | 3,038 | — | 1,934 | — | — | — | 8,618 | 8,233 | — | 1,891 | — | — |
log2Up | 679 | — | 209 | — | 247 | — | — | — | 505 | — | 513 | — |
neg | 127 | 9 | 116 | 76 | — | — | 134 | — | — | — | — | — |
sign | 139 | 181 | 75 | — | — | — | 84 | — | 78 | — | — | — |
Correct to the last wei
BlockulatorWad keeps Solady's function names and returns the exact answer, rounded the way each function promises, on all 108,000 results we tested across 27 functions and rounding directions. The libraries it replaces are a wei off on up to 98% of their results for some functions.
Seeded inputs over each function's domain, including those whose exact value sits next to a wei boundary. Every library here is 18-decimal fixed point. Every library that offers them is exact on divWad, divWadUp, mulWad, mulWadUp, sDivWad, sMulWad, sqrtWad, sqrtWadUp. Counts: wad.md.
Share wrong, per function
| Fixed point | ||||||||
|---|---|---|---|---|---|---|---|---|
| function · share wrong | BWad | Solady | Solmate | PRB SD | PRB UD | snek | OZ | Uniswap |
cbrtWad | 0 of 4,000 | 0 | — | — | — | 23% | — | — |
expWad | 0 of 3,995 | 48% | 48% | 72% | 93% | 48% | — | — |
lnWad | 0 of 3,998 | 24% | 24% | 98% | 98% | 24% | — | — |
log2Wad | 0 of 3,998 | — | — | 93% | 90% | — | — | — |
log10Wad | 0 of 3,998 | — | — | 88% | 90% | — | — | — |
powWad | 0 of 3,461 | 66% | 66% | 71% | 85% | — | — | — |
lambertW0Wad | 0 of 3,999 | 28% | — | — | — | — | — | — |
mulWad | 0 of 3,720 | 0 | 0 | 0 | — | 0 | 0 | 0 |
mulWadUp | 0 of 3,720 | 0 | 0 | — | — | 0 | 0 | 0 |
divWad | 0 of 3,966 | 0 | 0 | 0 | — | 0 | 0 | 0 |
divWadUp | 0 of 3,966 | 0 | 0 | — | — | 0 | 0 | 0 |
sMulWad | 0 of 3,715 | 0 | 0 | 0 | — | — | — | — |
sDivWad | 0 of 3,937 | 0 | 0 | 0 | — | — | — | — |
sqrtWad | 0 of 4,000 | 0 | 0 | 0 | — | — | 0 | — |
sqrtWadUp | 0 of 4,000 | — | — | — | — | — | 0 | — |
Everything else we measured
14 real calculations, up to 10,000 steps
Compounding, loans, bonding curves, option pricing and decay, run in every library and checked against 300-digit arithmetic.
edges139 calls where formats break
Tiny and huge arguments and the ends of each domain, across 15 ops: which libraries return zero, revert or lose every digit.
in productionAave and Morpho as deployed
The live markets' own accrual against the formula each says it computes.
incidentsFour exploits, replayed
Real attacks rerun from their own transactions, and what would have stopped each one.