call

Black-76

Computes the price of a European call option on a future using the Black-76 model.

Avg. gas

2,552

Max abs. error

1.3e-10

when price < 1

Max rel. error

5e-12

when price ≥ 1

Signature

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

Parameters

NameTypeDescription
futureuint128Current future price in 18-decimal fixed-point format.
strikeuint128Strike price, 18-decimal fixed-point. Precision-tuned for the no-arbitrage band against the future — see Bounds.
timeToExpuint32Time to expiration in seconds. timeToExp == 0 is allowed (handled as expired).
volatilityuint64Annualized implied volatility, 18-decimal fixed-point (e.g. 60% → 6e17).
rateuint64Annualized risk-free (discount) rate, 18-decimal fixed-point. The future already embeds the cost of carry.

Returns

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

Bounds

BoundValue
MIN_FUTURE1e-6 smallest allowed future price (1e12)
MAX_FUTURE1e15 largest allowed future price (1e33)
MAX_STSP_RATIO5× (strike must lie within [future/5, future·5])
MAX_EXPIRATION32 years (1,009,152,000 seconds)
MAX_RATE400% annual (4e18)

Behavior

  • Validates all five inputs against module-wide constants and reverts with a typed error on any violation.
  • Prices options on a future, not spot: d₁ carries no rate term and the whole payoff is discounted by e^(−rτ), since the future already embeds the cost of carry.
  • Fast-path on expiration: when timeToExp == 0, returns intrinsic value max(future − strike, 0) without running the pricer.
  • Composes four DeFiMath primitives — ln, sqrtTime (specialized sqrt for years), expPositive (the discount factor), and stdNormCDF.
  • Equivalent to e^(−rτ) · BlackScholes.call(spot = F, rate = 0) — use Black-Scholes instead when the underlying is a spot asset.
  • Pure internal function; no external calls, no storage. Inlined into the caller's bytecode at compile time.

How it works

call implements the closed-form Black-76 formula for a European call on a future:

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

Unlike Black-Scholes, d₁ has no rate term — the future already carries the cost of carry. σ·√T uses Math.sqrtTime, ln(future/strike) uses Math.ln, and the two normal CDFs use Math.stdNormCDF. The whole bracket is discounted once by e^(−rT) via Math.expPositive(rT) (input bounds guarantee rT ≥ 0).

The suite enforces a 5e-12 relative bound where the price is ≥ 1 and a 1.3e-10 absolute bound for the sub-$1 (deep-OTM) tail, both at future = $1,000 across a full sweep of strike, time, vol, and rate — head-to-head measurements against other libraries live in defimath-compare.

Errors

ErrorTrigger
FutureLowerBoundErrorfuture ≤ MIN_FUTURE
FutureUpperBoundErrorfuture ≥ MAX_FUTURE
StrikeLowerBoundErrorstrike · 5 < future
StrikeUpperBoundErrorfuture · 5 < strike
TimeToExpiryUpperBoundErrortimeToExp ≥ MAX_EXPIRATION
RateUpperBoundErrorrate ≥ MAX_RATE

Example

solidity
import "defimath-lib/contracts/derivatives/Black76.sol";

uint256 price = Black76.call(
    1000e18,         // future = $1,000
    1050e18,         // strike = $1,050
    90 days,         // 90 days to expiry
    0.60e18,         // 60% annualized vol
    0.05e18          // 5% discount rate
);
// price ≈ 96.9e18  (about $96.90 per option)