Introduction

v3.5.0

DeFiMath is a pure-Solidity library of gas-optimized 18-decimal fixed-point math primitives — 40+ functions spanning six modules: math, options, binary options, futures, rates, and statistics.

2,729 gas

Black-Scholes option pricing

< 1e-12

Max abs. error on options pricing

100%

Test coverage · Solidity 0.8.35

0

Runtime dependencies

Full test coverage across Hardhat and Foundry property-based fuzz suites. MIT-licensed, no runtime dependencies.

What's inside

Benchmarks

Headline functions vs. the next-best on-chain implementation in each category:

FunctionDeFiMathNext bestMultiple
callOptionPrice2,72913,360 (Derivexyz)4.9×
putOptionPrice2,73913,363 (Derivexyz)4.9×
binaryCallPrice2,01816,218 (Haptic)8.0×
delta1,7248,621 (Derivexyz)5.0×
vega1,4367,490 (Derivexyz)5.2×
ln375518 (Solady)1.4×
sqrt245341 (Solady)1.4×
cbrt368550 (Solady)1.5×
stdNormCDF6602,794 (SolStat)4.2×

Full per-function tables in the defimath-compare README.

Testing

DeFiMath ships with two independent test layers. Each library function is the unit — its own describe block with a fixed taxonomy of sub-tests, so anyone auditing the suite can find the exact coverage for any function in seconds.

Hardhat correctness layer

604 tests validating against external JavaScript references (JS Math, math-erf, black-scholes, greeks, simple-statistics) at concrete points across the operational domain. Every function in every module follows the same five-category taxonomy:

  • behaviour — normal-case sweeps (~200 samples per test) validated against the JS reference
  • limits — minimum and maximum valid inputs, branch-transition boundaries, and near-revert edges
  • random — non-seeded fuzz coverage with Math.random()
  • failure — one test per named revert error in the contract
  • performance — one deterministic test per function asserting exact gas with assert.equal (fails on both regression AND improvement). Gas threshold is in the test name, so any change shows up in the PR diff.

Foundry property-fuzz layer

92 mathematical properties × 32,000 random runs each = 2,944,000 random executions per CI run. Validates the algebraic structure of the library, not just concrete points. Foundry automatically shrinks counterexamples on failure. Properties are organized into five categories:

  • Round-trips — composing a function with its inverse recovers the input within tolerance
  • Monotonicity — output ordering matches input ordering for functions that are mathematically monotone
  • Identities — algebraic equalities that must hold across the full input domain
  • Output bounds — every output lies within its mathematically valid range
  • Symmetries — sign or reflection symmetries hold under input negation

681

Total tests (Hardhat + Foundry)

2,944,000

Random executions per CI run

< 1 min

Full suite wall-time

Each module page has its own Testing section detailing per-function coverage. All code lives at test/ on GitHub — test/hardhat/ for the correctness layer, test/foundry/ for the properties.

Getting started

DeFiMath is published on npm as defimath-lib. All functions are internal pure, so the library compiles directly into your contract bytecode — no linker step and no runtime contract to deploy.

Hardhat / npm

npm install defimath-lib

Foundry

forge install defimath-lib=MerkleBlue/defimath

Then add to remappings.txt:

text
defimath-lib/=lib/defimath-lib/
Why the alias and the remapping?

The defimath-lib= install alias makes Foundry place the repo at lib/defimath-lib/ so the same defimath-lib/contracts/... import path works under both toolchains. The remapping then overrides Foundry's auto-detect, which would otherwise treat contracts/ as the src directory and produce defimath-lib/=lib/defimath-lib/contracts/ — colliding with the leading contracts/ in the import path.

Compiler requirements

  • Solidity ^0.8.31
  • EVM target osaka (Fusaka)
Why these requirements?

The library uses the clz Yul builtin (Solidity 0.8.31+) which emits the CLZ opcode introduced in Osaka — both the compiler version and EVM target are hard requirements.

Import and use

Pricing a European call option — every other module imports the same way.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.31;

import "defimath-lib/contracts/derivatives/Options.sol";

contract OptionsPricer {
    function priceCall(
        uint128 spot, uint128 strike, uint32 timeToExp,
        uint64 vol, uint64 rate
    ) external pure returns (uint256) {
        return DeFiMathOptions.callOptionPrice(spot, strike, timeToExp, vol, rate);
    }
}

Or composing math primitives directly — the 68-95-99.7 rule, on-chain:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.31;

import "defimath-lib/contracts/math/Math.sol";

contract Confidence {
    // P(-k < Z < k) = 2·Φ(k) - 1 — probability that a normally-distributed
    // value falls within k standard deviations of the mean (e.g., k=1 → ~68%,
    // k=2 → ~95%, k=3 → ~99.7%). The 68-95-99.7 rule on-chain.
    function withinKStdevs(int256 k) external pure returns (uint256) {
        return 2 * DeFiMath.stdNormCDF(k) - 1e18;
    }
}