put

Binary options

Computes the price of a binary cash-or-nothing put option using the Black-Scholes model.

Avg. gas

1,918

Max abs. error

2e-12

Signature

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

Parameters

NameTypeDescription
spotuint128Current spot price, 18-decimal fixed-point.
strikeuint128Strike price, 18-decimal fixed-point. Precision-tuned for the no-arbitrage band against spot — 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 rate, 18-decimal fixed-point.

Returns

NameTypeDescription
priceuint256Binary put price for unit payout in 18-decimal fixed-point — a discounted probability in [0, 1]. Scale externally for other payouts.

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_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.
  • Pays out 1 unit if the option finishes in-the-money (strike > spot), 0 otherwise. The returned price is the discounted probability of that — multiply by your notional for any other payout.
  • Volatility has no explicit revert — it's bounded only by its uint64 type (max ≈ 1.84e19, i.e. ~1840% annualized).
  • Fast-path on expiration: when timeToExp == 0, returns 1 if in-the-money (strike > spot), else 0.
  • Composes four DeFiMath primitives — ln, sqrtTime (specialized sqrt for years), expPositive (the discount factor), and stdNormCDF.
  • Symmetric counterpart of the binary call: same machinery with Φ(−d₂) in place of Φ(d₂). Pure internal function; no external calls, no storage.

How it works

A binary (cash-or-nothing) put pays a fixed unit if strike > spot at expiry. Under Black-Scholes its price is the discounted risk-neutral probability of that event:

Pbin=erTΦ(d2),d2=ln(S/K)+(rσ22)TσTP_{bin} = e^{-rT} \, \Phi(-d_2), \qquad d_2 = \frac{\ln(S/K) + \left(r - \tfrac{\sigma^2}{2}\right) T}{\sigma \sqrt{T}}

It reuses the same d₂ machinery as the binary call — Math.ln for ln(spot/strike), Math.sqrtTime for σ·√T, 1 / Math.expPositive(rT) for the discount factor — but evaluates Φ(−d₂) with Math.stdNormCDF. By put-call parity the two prices sum to the discount factor e^(−rT).

The price is a discounted probability, always in [0, 1], so the suite enforces an absolute error only — no relative bound. The 2e-12 max absolute error is enforced across a full sweep of strike, time, vol, and rate — head-to-head measurements against other libraries live in 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/BinaryOptions.sol";

uint256 price = BinaryOptions.put(
    1000e18,         // spot = $1,000
    950e18,          // strike = $950
    30 days,         // 30 days to expiry
    0.60e18,         // 60% annualized vol
    0.05e18          // 5% risk-free rate
);
// price ≈ 0.36e18  (~36% risk-neutral probability, discounted)