callOptionPrice
OptionsComputes the Black-Scholes price of a European call option in 18-decimal fixed-point, at ~2,729 gas.
Gas
2,729
Max abs. error
5.6e-12
Signature
function callOptionPrice(
uint128 spot,
uint128 strike,
uint32 timeToExp,
uint64 volatility,
uint64 rate
) internal pure returns (uint256 price)Parameters
| Name | Type | Description |
|---|---|---|
| spot | uint128 | Current spot price, 18-decimal fixed-point. Must satisfy MIN_SPOT < spot < MAX_SPOT (1e-6 < spot < 1e15). |
| strike | uint128 | Strike price, 18-decimal fixed-point. Must lie within [spot/5, spot·5] — the no-arbitrage band the function is precision-tuned for. |
| timeToExp | uint32 | Time to expiration in seconds. Must satisfy timeToExp < MAX_EXPIRATION (63,072,000 s ≈ 2 years). timeToExp == 0 is allowed (handled as expired). |
| volatility | uint64 | Annualized implied volatility, 18-decimal fixed-point (e.g. 60% → 6e17). |
| rate | uint64 | Annualized risk-free rate, 18-decimal fixed-point. Must satisfy rate < MAX_RATE (4e18 = 400%). |
Returns
| Name | Type | Description |
|---|---|---|
| price | uint256 | Call option price in 18-decimal fixed-point. Always ≥ 0. |
Bounds
| Bound | Value |
|---|---|
| MIN_SPOT | 1e-6 smallest allowed spot price (1e12) |
| MAX_SPOT | 1e15 largest allowed spot price (1e33) |
| MAX_STSP_RATIO | 5× (strike must lie within [spot/5, spot·5]) |
| MAX_EXPIRATION | 2 years (63,072,000 seconds) |
| MAX_RATE | 400% annual (4e18) |
Behavior
- Validates all five inputs against module-wide constants and reverts with a typed error on any violation.
- Volatility has no explicit revert — it's bounded only by its
uint64type (max ≈1.84e19, i.e. ~1840% annualized). Practical inputs stay well below that ceiling; theMIN_VOL_IV/MAX_VOL_IVconstants in the source apply only to the impliedVolatility solver, not the pricer. - Fast-path on expiration: when
timeToExp == 0, returns intrinsic valuemax(spot − strike, 0)without running the pricer. - Composes four DeFiMath primitives — ln,
sqrtTime(specialized sqrt for years),expPositive(rate is non-negative by validation), and stdNormCDF — each independently gas-tuned and validated. - Pure
internalfunction; no external calls, no storage. Inlined into the caller's bytecode at compile time. - Symmetric counterpart: putOptionPrice uses identical input validation and the same d₁/d₂ machinery — substituting
Φ(−d₁)/Φ(−d₂)for the call'sΦ(d₁)/Φ(d₂).
How it works
callOptionPrice implements the closed-form Black-Scholes formula for a European call:
Every transcendental in the formula maps to a DeFiMath primitive: σ·√T uses DeFiMath.sqrtTime (a specialized square root tuned for time-in-years inputs), ln(spot/strike) uses DeFiMath.ln, the discount factor e^(−rT) is computed as 1 / DeFiMath.expPositive(rT) (since the input bounds guarantee rT ≥ 0, we skip the negative-input reciprocal branch), and the two normal CDFs use DeFiMath.stdNormCDF.
The annualization step converts timeToExp (seconds) to a year fraction by dividing by SECONDS_IN_YEAR, then scales volatility by √T once and reuses the result through d₁, d₂, and the integral bounds. The +1 on scaledVol is a defensive bump to keep the division in d₁ well-defined even for zero-vol edge cases.
The final assembly computes spot · Φ(d₁) − discountedStrike · Φ(d₂) and clamps the result at zero — Black-Scholes can produce slightly negative values (on the order of 10⁻¹²) due to rounding in the rounded primitives when the option is far out of the money. The clamp guarantees the function never returns a nonsensical negative price. The 5.6e-12 max absolute error is benchmarked at spot = $1,000 across a full sweep of strike, time, vol, and rate — reproducible from defimath-compare.
Errors
| Error | Trigger |
|---|---|
| SpotLowerBoundError | spot ≤ MIN_SPOT |
| SpotUpperBoundError | spot ≥ MAX_SPOT |
| StrikeLowerBoundError | strike · 5 < spot |
| StrikeUpperBoundError | spot · 5 < strike |
| TimeToExpiryUpperBoundError | timeToExp ≥ MAX_EXPIRATION |
| RateUpperBoundError | rate ≥ MAX_RATE |
Example
import "defimath-lib/contracts/derivatives/Options.sol";
uint256 price = DeFiMathOptions.callOptionPrice(
1000e18, // spot = $1,000
980e18, // strike = $980
60 days, // 60 days to expiry
0.60e18, // 60% annualized vol
0.05e18 // 5% risk-free rate
);
// price ≈ 99.4e18 (about $99.40 per option)