DeFiMath [![License: MIT][license-badge]][license]

August 5, 2026 · View on GitHub

Tests npm version npm downloads Solidity

Gas-optimized Solidity library for DeFi math. Black-Scholes option pricing at 2,582 gas, with a broad set of primitives across math, interest rates, statistics, and derivatives.

DeFiMath is a pure-Solidity library of DeFi math primitives. 40+ functions across four modules: low-level math, derivatives, interest rates, and statistics. No external runtime dependencies. MIT-licensed.

Why DeFiMath

  • Unlocks new use cases. Gas-efficient enough to make real-time options pricing, on-chain IV solving on every quote, and risk-adjusted vault fees economically viable. Use cases that were previously off-chain workarounds now fit in a single transaction.
  • Breadth. 40+ primitives spanning math (exp, ln, sqrt), derivatives (Black-Scholes & Black-76 + Greeks, binary options, IV solver), interest rates (compound, present value, IRR, YTM), and statistics (volatility, Sharpe, VaR, CVaR, max drawdown).
  • Pure Solidity. ~16KB published, zero runtime dependencies, easy to audit.
  • Validated precision. Sub-5e-12 relative error on options pricing. Every math primitive carries an explicit, enforced error bound — from 2e-18 (sqrt) to 1e-12 (pow) — measured as relative error where the result is ≥ 1 and absolute error near a root or for bounded functions like stdNormCDF and erf; see the per-function tables below. Validated against simple-statistics, black-scholes, greeks, and math-erf reference libraries.

Benchmarks

Every function is benchmarked against existing on-chain implementations. A representative comparison:

FunctionDeFiMathNext bestMultiple
call2,58213,360 (Derivexyz)5.2×
put2,59213,363 (Derivexyz)5.2×
call1,91316,218 (Haptic)8.5×
delta1,6618,621 (Derivexyz)5.2×
vega1,3737,490 (Derivexyz)5.5×
ln390518 (Solady)1.3×
sqrt197384 (Solady)1.9×
cbrt340550 (Solady)1.6×
stdNormCDF6183,103 (SolStat)5.0×

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

Install

Hardhat / npm

npm install defimath-lib

Foundry

forge install defimath-lib=MerkleBlue/defimath

Then add to remappings.txt:

defimath-lib/=lib/defimath-lib/

The defimath-lib= install alias plus this remapping make the same import "defimath-lib/contracts/derivatives/BlackScholes.sol" line work under both Foundry and Hardhat. Without the remapping, Foundry auto-detects contracts/ as the src directory and produces defimath-lib/=lib/defimath-lib/contracts/, which collides with the leading contracts/ segment in the import path.

Either way, your project must target Solidity ^0.8.31 and evmVersion: "osaka" (Fusaka). The library uses the clz Yul builtin (added in Solidity 0.8.31) which emits the CLZ opcode introduced in Osaka — both the compiler version and EVM target are hard requirements.

Usage

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

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

contract OptionsExchange {
    function quote(
        uint128 spot, uint128 strike, uint32 timeToExp,
        uint64 vol, uint64 rate
    ) external pure returns (uint256 callPx, uint256 putPx) {
        callPx = BlackScholes.call(spot, strike, timeToExp, vol, rate);
        putPx  = BlackScholes.put(spot, strike, timeToExp, vol, rate);
    }
}

All values use 18-decimal fixed-point (1e18 = 1.0). Time is in seconds. See module docs for full parameter conventions.

Functions

Math primitives — Math (Math.sol)

FunctionGasMax abs errorMax rel errorDescription
exp2893.0e-162.2e-14Exponential function e^x
ln3901.0e-151.6e-15Natural logarithm
log24061.0e-151.6e-15Base-2 logarithm
log104061.0e-151.6e-15Base-10 logarithm
pow7611.0e-141.0e-12Power function x^a
sqrt1971.0e-182.0e-18Square root
cbrt3401.0e-162.0e-13Cube root
expm12955.0e-162.2e-14e^x − 1 (precision-preserving for small x)
log1p4941.0e-153.0e-15ln(1 + x) (precision-preserving for small x)
stdNormCDF6183.0e-15Standard normal CDF Φ(x)
erf6492.0e-15Error function
mulDiv155exactexact(a · b) / d with full 512-bit intermediate precision
mul130exactexact(a · b) / 1e18 — fixed-point multiply with denominator baked in
abs17exactexactBranchless |int256| (handles int256.min cleanly)
min23exactexactBranchless minimum of two uint256
max23exactexactBranchless maximum of two uint256
clamp78exactexactClamp x into [lo, hi] (composed max then min)
avg21exactexactOverflow-safe (a + b) / 2 via (a & b) + ((a ^ b) >> 1)

Figures are the error bounds the test suite enforces — the constants in constants/Constants.mjs, asserted against a JS / decimal.js reference across each function's full documented domain. The metric follows the result magnitude: relative where |result| ≥ 1, absolute where |result| < 1. Relative error is undefined at a function's root (ln at x = 1, expm1/log1p at x = 0), where any nonzero error divides by ~0 — absolute is the meaningful bound there. Both are published wherever the suite bounds both. marks a metric the suite does not bound: erf and stdNormCDF are bounded in [−1, 1] and [0, 1] so only absolute is meaningful. sqrt's absolute bound of 1.0e-18 is exactly 1 wei — it is correctly rounded below 1. log2, log10 and log1p inherit ln's bounds. exact denotes integer-arithmetic functions with no approximation error.

Derivatives — BlackScholes, Black76, BinaryOptions, Futures

Black-Scholes (BlackScholes.sol) — European options, spot / lognormal:

FunctionGasMax abs errorMax rel errorDescription
call2,5821.3e-105e-12European call price
put2,5921.3e-105e-12European put price
delta1,6611.2e-13First derivative w.r.t. spot (
gamma1,4333.2e-155e-12Second derivative w.r.t. spot
theta3,1011.9e-125e-12Time decay (per day)
vega1,3734e-135e-12Sensitivity to volatility
impliedVolatility11,668 / 11,7432e-61.0e-6IV via Newton-Raphson (call / put)

Black-76 (Black76.sol) — European options on a future:

FunctionGasMax abs errorMax rel errorDescription
call2,5521.3e-105e-12European call on a future
put2,5651.3e-105e-12European put on a future
delta1,9151.2e-13First derivative w.r.t. future (
gamma1,7043.2e-155e-12Second derivative w.r.t. future
theta3,2551.9e-125e-12Time decay (per day)
vega1,6594e-135e-12Sensitivity to volatility
impliedVolatility11,760 / 11,8022e-61.0e-6IV via Newton-Raphson (call / put)

Binary options (BinaryOptions.sol) — cash-or-nothing, unit payout:

FunctionGasMax abs errorMax rel errorDescription
call1,9132e-12Cash-or-nothing call
put1,9182e-12Cash-or-nothing put
delta1,7171e-13Binary delta (signed)
gamma1,8591e-15Binary gamma (signed)
theta3,1611e-14Binary theta (per day)
vega1,8051e-14Binary vega (signed)

Futures (Futures.sol):

FunctionGasMax abs errorMax rel errorDescription
futurePrice4001.2e-92e-12spot · e^(rt)

Bounds enforced by the test suite — the MAX_*_ERROR_* constants in constants/Constants.mjs. Black-Scholes uses the same dual metric as the math primitives: relative where |result| ≥ 1, absolute where < 1 — so each function carries a rel bound plus an abs bound for its sub-1 tail (e.g. deep-OTM prices below $1). delta ∈ [−1, 1] is abs-only, and impliedVolatility is a round-trip whose rel bound is its Newton-Raphson convergence target. Option prices are on a $1,000 spot, theta per day, vega per 1% vol. Black-76 (options on a future) mirrors Black-Scholes exactly — same dual metric and per-function conventions, on a $1,000 future. Binaries (unit payout, every value ≤ 1) are abs-only. Futures price scales with spot, so the bound is relative (2e-12, scale-invariant); the absolute figure is quoted at a $1,000 spot.

Interest & rates — Rates (Rates.sol)

FunctionGasMax abs errorMax rel errorDescription
compoundInterest4255.4e-14Continuous compounding: P · e^(rt)
presentValue4775.4e-14Discounting: FV · e^(−rt)
logReturn6001.6e-15ln(currentPrice / previousPrice)
continuousToDiscrete3751e-15e^apr − 1 (APR → APY)
discreteToContinuous5741e-15ln(1 + apy) (APY → APR)
yieldToMaturity7365.4e-14Zero-coupon YTM (closed form)
internalRateOfReturn16k–47k1e-9IRR via Newton-Raphson (cost scales with cashflow count)

Bounds enforced by the test suite — the constants in constants/Constants.mjs. Compounding and discounting inherit exp's relative bound, logReturn inherits ln's. The two rate conversions are bounded absolutely (1e-15) because they run a Taylor branch through their root at r = 0, where relative error is undefined. internalRateOfReturn is bounded by its Newton-Raphson convergence tolerance.

Statistics — Statistics (Statistics.sol)

FunctionGasMax abs errorMax rel errorDescription
geometricMean2842.2e-14sqrt(a · b) — Uniswap V2 invariant
mean6,980 @ 30 elem1e-15Arithmetic mean
stdDev15,252 @ 30 elem2.2e-14Sample std. dev. (Bessel-corrected)
weightedAverage15,687 @ 30 elem1e-15Σ(v·w) / Σ(w)
historicalVolatility25,820 @ 30 prices2.2e-14Annualized vol from log returns
sharpeRatio25,958 @ 30 prices2.2e-14Risk-adjusted return
maxDrawdown15,470 @ 30 prices1e-15Peak-to-trough decline
valueAtRisk34,531 @ 30 prices2.2e-14NumPy-compatible linear interpolation
conditionalValueAtRisk31,889 @ 30 prices2.2e-14Expected shortfall (left tail mean)

Bounds enforced by the test suite — the constants in constants/Constants.mjs. All results are ≥ 1 in practice, so relative error is the metric throughout. 1e-15 marks arithmetic-only aggregation (essentially exact, at IEEE 754 machine epsilon); 2.2e-14 covers the multi-step paths (variance → vol → Sharpe) that accumulate rounding. valueAtRisk is validated against simple-statistics.

Testing

Two independent layers:

  • Hardhat — 740 tests validating against external JavaScript references (Math, math-erf, black-scholes, greeks, simple-statistics) at concrete points across the operational domain, plus strict-equality gas-regression assertions on every performance test.
  • Foundry — 114 mathematical properties × 32,000 random runs each = 3,648,000 random executions per CI run. Validates the algebraic structure (round-trips, monotonicity, identities, output bounds, symmetries) with automatic counterexample shrinking.

854 total tests. Run with npm test. Sources live at test/hardhat/ and test/foundry/. Per-module test breakdowns on the Documentation page.

Precision

Every function is validated against trusted JavaScript reference implementations: black-scholes, greeks, math-erf, and simple-statistics. Per-function error figures appear in the tables above; the full benchmark suite — including head-to-head precision vs. competing libraries — lives in defimath-compare.

License

MIT.