wad-ray-math
v1.0.0
Published
TypeScript BigInt implementation of Aave's wad/ray fixed-point arithmetic. Zero dependencies. Matches on-chain Solidity precision exactly.
Maintainers
Readme
wad-ray-math
TypeScript BigInt implementation of Aave's WadRayMath and PercentageMath. Zero dependencies. Matches on-chain Solidity precision exactly.
Every DeFi protocol backend needs to replicate on-chain fixed-point math off-chain. This package makes that a proper dependency instead of a copy-paste.
Install
npm install wad-ray-mathUsage
import { wadMul, wadDiv, rayMul, wadToRay, WAD, RAY } from "wad-ray-math";
// Multiply 1.5 * 2.0 in wad (18-decimal) precision
wadMul(1_500000000000000000n, 2_000000000000000000n);
// => 3000000000000000000n (3.0 WAD)
// Divide in ray (27-decimal) precision
rayDiv(3n * RAY, 2n * RAY);
// => 1.5 RAY
// Convert between scales
wadToRay(WAD); // => RAY (1e18 -> 1e27)All operations use round-half-up, identical to Aave's Solidity libraries.
Scales
| Scale | Decimals | Constant | Used for |
| ------------ | -------- | ------------------- | --------------------------------- |
| WAD | 18 | WAD = 1e18 | Token amounts |
| RAY | 27 | RAY = 1e27 | Interest rates, liquidity indexes |
| Percentage | 4 (bps) | PERCENTAGE_FACTOR | Basis points (10000 = 100%) |
API
| Function | Formula | Notes |
| -------------------- | -------------------------------------------------- | --------------------------- |
| wadMul(a, b) | (a * b + HALF_WAD) / WAD | Round half up |
| wadDiv(a, b) | (a * WAD + b / 2) / b | Throws if b == 0 |
| rayMul(a, b) | (a * b + HALF_RAY) / RAY | Round half up |
| rayDiv(a, b) | (a * RAY + b / 2) / b | Throws if b == 0 |
| wadToRay(a) | a * 1e9 | 1e18 → 1e27 |
| rayToWad(a) | (a + 0.5e9) / 1e9 | 1e27 → 1e18, round half up |
| percentMul(v, pct) | (v * pct + 0.5e4) / 1e4 | pct in basis points |
| percentDiv(v, pct) | (v * 1e4 + pct / 2) / pct | Throws if pct == 0 |
| min(a, b) | smaller of a, b | — |
| max(a, b) | larger of a, b | — |
| abs(a) | \|a\| | — |
Constants
WAD, HALF_WAD, RAY, HALF_RAY, WAD_RAY_RATIO, HALF_WAD_RAY_RATIO, PERCENTAGE_FACTOR, HALF_PERCENTAGE_FACTOR, MAX_UINT256.
Errors
The math functions operate on uint256 semantics, just like the Solidity originals:
DivisionByZeroError— thrown on division by zero.OverflowError— thrown when an input is negative, exceedsuint256, or when an intermediate product would overflowuint256(mirroring on-chain reverts).
import { wadDiv, DivisionByZeroError } from "wad-ray-math";
try {
wadDiv(WAD, 0n);
} catch (e) {
if (e instanceof DivisionByZeroError) {
// handle
}
}Why?
- Zero dependencies — native BigInt, nothing else.
- Exact match — same rounding and the same overflow/zero reverts as Aave's Solidity.
- Dual format — ships both ESM and CommonJS.
- Type-safe — full TypeScript with bundled declarations.
Development
npm install
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run test:coverage
npm run build # tsup -> dist (cjs + esm + d.ts)License
MIT
