callOptionPrice

Options

Computes 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

solidity
function callOptionPrice(
    uint128 spot,
    uint128 strike,
    uint32  timeToExp,
    uint64  volatility,
    uint64  rate
) internal pure returns (uint256 price)

Parameters

NameTypeDescription
spotuint128Current spot price, 18-decimal fixed-point. Must satisfy MIN_SPOT < spot < MAX_SPOT (1e-6 < spot < 1e15).
strikeuint128Strike price, 18-decimal fixed-point. Must lie within [spot/5, spot·5] — the no-arbitrage band the function is precision-tuned for.
timeToExpuint32Time to expiration in seconds. Must satisfy timeToExp < MAX_EXPIRATION (63,072,000 s ≈ 2 years). timeToExp == 0 is allowed (handled as expired).
volatilityuint64Annualized implied volatility, 18-decimal fixed-point (e.g. 60% → 6e17).
rateuint64Annualized risk-free rate, 18-decimal fixed-point. Must satisfy rate < MAX_RATE (4e18 = 400%).

Returns

NameTypeDescription
priceuint256Call option price in 18-decimal fixed-point. Always ≥ 0.

Bounds

BoundValue
MIN_SPOT1e-6 smallest allowed spot price (1e12)
MAX_SPOT1e15 largest allowed spot price (1e33)
MAX_STSP_RATIO5× (strike must lie within [spot/5, spot·5])
MAX_EXPIRATION2 years (63,072,000 seconds)
MAX_RATE400% 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 uint64 type (max ≈ 1.84e19, i.e. ~1840% annualized). Practical inputs stay well below that ceiling; the MIN_VOL_IV / MAX_VOL_IV constants in the source apply only to the impliedVolatility solver, not the pricer.
  • Fast-path on expiration: when timeToExp == 0, returns intrinsic value max(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 internal function; 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:

C=SΦ(d1)KerTΦ(d2)C = S \cdot \Phi(d_1) - K \, e^{-rT} \cdot \Phi(d_2)
d1=ln(S/K)+(r+σ22)TσT,d2=d1σTd_1 = \frac{\ln(S/K) + \left(r + \tfrac{\sigma^2}{2}\right) T}{\sigma \sqrt{T}}, \qquad d_2 = d_1 - \sigma \sqrt{T}

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

ErrorTrigger
SpotLowerBoundErrorspot ≤ MIN_SPOT
SpotUpperBoundErrorspot ≥ MAX_SPOT
StrikeLowerBoundErrorstrike · 5 < spot
StrikeUpperBoundErrorspot · 5 < strike
TimeToExpiryUpperBoundErrortimeToExp ≥ MAX_EXPIRATION
RateUpperBoundErrorrate ≥ MAX_RATE

Example

solidity
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)