BlackScholesLib
Black-Scholes option pricing implementation
The BlackScholesLib and BlackScholesWad libraries implement the Black-Scholes pricing model for European options. These libraries are the mathematical core of Diffusal's pricing system, calculating option prices and Greeks with high precision using 64.64 fixed-point arithmetic.
Overview
The Black-Scholes libraries provide:
| Library | Purpose |
|---|---|
| BlackScholesLib | Core pricing in 64.64 fixed-point format |
| BlackScholesWad | WAD adapter for external interface |
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ DiffusalOptionsQuoter │
│ (external interface) │
│ │ │
│ ▼ │
│ BlackScholesWad │
│ (WAD ↔ 64.64 conversion) │
│ │ │
│ ▼ │
│ BlackScholesLib │
│ (core 64.64 arithmetic) │
│ │ │
│ ▼ │
│ Math64x64Extended │
│ (ln, exp, sqrt, normalCdf) │
└─────────────────────────────────────────────────────────────────┘Key Concepts
Black-Scholes Formula
The Black-Scholes model prices European options. For the complete mathematical derivation and formula details, see Black-Scholes Model.
Call Option:
Put Option:
Option Greeks
Greeks measure option sensitivity to various parameters. See Black-Scholes: Greeks for complete formulas.
| Greek | Meaning | Range (Call) |
|---|---|---|
| Delta | Price sensitivity to spot | 0 to 1 |
| Gamma | Delta sensitivity to spot | Always positive |
| Vega | Price sensitivity to volatility | Always positive |
| Theta | Time decay (per year) | Usually negative |
| Rho | Sensitivity to interest rate | Positive (calls) |
Precision Model
Format Conversion
┌───────────────────────────────────────────────────────────────┐
│ Precision Hierarchy │
├───────────────────────────────────────────────────────────────┤
│ External Interface: WAD (1e18) │
│ 0.50e18 = 50% volatility │
│ 3000e18 = $3000 spot price │
├───────────────────────────────────────────────────────────────┤
│ Internal Math: 64.64 fixed-point (int128) │
│ Upper 64 bits = integer part │
│ Lower 64 bits = fractional part │
│ Range: roughly ±9.2e18 with ~18 decimal precision │
└───────────────────────────────────────────────────────────────┘Conversion Functions
// WAD → 64.64
function wadTo64x64(uint256 wad) internal pure returns (int128) {
return ((wad << 64) / 1e18).toInt256().toInt128();
}
// 64.64 → WAD (unsigned)
function from64x64ToWad(int128 x) internal pure returns (uint256) {
return (uint256(int256(x)) * 1e18) >> 64;
}
// 64.64 → WAD (signed)
function from64x64ToSignedWad(int128 x) internal pure returns (int256) {
// Handles negative values for Greeks
}BlackScholesLib (64.64)
Types
Params64x64
Input parameters for pricing:
struct Params64x64 {
int128 spot; // S - Current price of underlying
int128 strike; // K - Strike price
int128 rate; // r - Risk-free interest rate
int128 volatility; // σ - Annualized volatility
int128 timeToExpiry; // T - Time to expiration in years
}Greeks64x64
Option Greeks:
struct Greeks64x64 {
int128 delta; // ∂V/∂S - Rate of change with respect to spot
int128 gamma; // ∂²V/∂S² - Rate of change of delta
int128 vega; // ∂V/∂σ - Sensitivity to volatility
int128 theta; // ∂V/∂t - Time decay (per year)
int128 rho; // ∂V/∂r - Sensitivity to interest rate
}PriceResult64x64
Complete pricing result:
struct PriceResult64x64 {
int128 price; // Option price
int128 d1; // d1 intermediate value
int128 d2; // d2 intermediate value
Greeks64x64 greeks; // Option Greeks
}Core Functions
calculateD1D2
Calculates the d1 and d2 values:
function calculateD1D2(Params64x64 memory p)
internal pure returns (int128 d1, int128 d2)Implementation:
// σ√T
int128 sqrtT = Math64x64Extended.sqrt(p.timeToExpiry);
int128 volSqrtT = p.volatility.mul(sqrtT);
// ln(S/K)
int128 ratio = p.spot.div(p.strike);
int128 logRatio = Math64x64Extended.ln(ratio);
// (r + σ²/2)T
int128 volSquaredHalf = p.volatility.mul(p.volatility).mul(HALF);
int128 rateAdjustedT = (p.rate.add(volSquaredHalf)).mul(p.timeToExpiry);
// d1 = [ln(S/K) + (r + σ²/2)T] / (σ√T)
d1 = (logRatio.add(rateAdjustedT)).div(volSqrtT);
// d2 = d1 - σ√T
d2 = d1.sub(volSqrtT);priceCall
Prices a European call option with full Greeks:
function priceCall(Params64x64 memory p)
internal pure returns (PriceResult64x64 memory result)Formula:
pricePut
Prices a European put option with full Greeks:
function pricePut(Params64x64 memory p)
internal pure returns (PriceResult64x64 memory result)Formula:
priceCallOnly / pricePutOnly
Gas-optimized pricing without Greeks calculation:
function priceCallOnly(Params64x64 memory p) internal pure returns (int128 optionPrice)
function pricePutOnly(Params64x64 memory p) internal pure returns (int128 optionPrice)Use case: When only the price is needed (e.g., getOptionQuote()).
BlackScholesWad (WAD Adapter)
Types
ParamsWad
struct ParamsWad {
uint256 spot; // S - Current price (WAD)
uint256 strike; // K - Strike price (WAD)
uint256 rate; // r - Risk-free rate (WAD, 0.05e18 = 5%)
uint256 volatility; // σ - Volatility (WAD, 0.50e18 = 50%)
uint256 timeToExpiry; // T - Time in years (WAD, 0.25e18 = 3 months)
}GreeksWad
struct GreeksWad {
int256 delta; // Delta (WAD, range -1e18 to 1e18)
int256 gamma; // Gamma (WAD)
int256 vega; // Vega (WAD)
int256 theta; // Theta (WAD, per year)
int256 rho; // Rho (WAD)
}PriceResultWad
struct PriceResultWad {
uint256 price; // Option price (WAD)
GreeksWad greeks; // Greeks (WAD)
}Pricing Functions
priceCall / pricePut
Full pricing with Greeks:
function priceCall(ParamsWad memory p)
internal pure returns (PriceResultWad memory result)
function pricePut(ParamsWad memory p)
internal pure returns (PriceResultWad memory result)priceCallOnly / pricePutOnly
Gas-optimized pricing:
function priceCallOnly(ParamsWad memory p) internal pure returns (uint256 priceWad)
function pricePutOnly(ParamsWad memory p) internal pure returns (uint256 priceWad)Pricing Example
Input Parameters
ParamsWad memory params = ParamsWad({
spot: 3000e18, // $3000
strike: 3200e18, // $3200
rate: 0.05e18, // 5% risk-free rate
volatility: 0.60e18, // 60% annualized volatility
timeToExpiry: 0.25e18 // 3 months (0.25 years)
});Call Option Price
PriceResultWad memory result = BlackScholesWad.priceCall(params);
// result.price ≈ 197.42e18 ($197.42 per contract)
// result.greeks.delta ≈ 0.423e18 (42.3%)
// result.greeks.gamma ≈ 0.0008e18
// result.greeks.vega ≈ 573.2e18
// result.greeks.theta ≈ -385.6e18 (per year)
// result.greeks.rho ≈ 273.4e18Interpretation
| Greek | Value | Meaning |
|---|---|---|
| Delta = 0.423 | 42.3% | 0.423 option increase |
| Gamma = 0.0008 | Delta increases by 0.08% per $1 spot move | |
| Vega = 573.2 | 1% vol increase → $5.73 price increase | |
| Theta = -385.6/365 | -$1.06/day | Option loses ~$1.06/day to time decay |
| Rho = 273.4 | 1% rate increase → $2.73 price increase |
Integration Points
Depends On
| Library | Purpose |
|---|---|
| Math64x64Extended | Low-level math (ln, exp, sqrt, normalCdf) |
| Constants | WAD, 64.64 constants |
Used By
| Contract | Purpose |
|---|---|
| DiffusalOptionsQuoter | All option pricing |
| DiffusalLiquidationEngine | Mark prices for liquidation |
| MarginEngine | Stress scenario pricing |
Gas Considerations
Cost Breakdown
| Operation | Approx. Gas | Notes |
|---|---|---|
normalCdf | ~20k | Most expensive (polynomial approximation) |
ln | ~5k | Natural logarithm |
exp | ~5k | Exponential |
sqrt | ~3k | Square root |
| Full price with Greeks | ~100k | 4x normalCdf + other ops |
| Price only (no Greeks) | ~60k | 2x normalCdf |
Optimization
Use priceOnly() variants when Greeks aren't needed:
// Gas optimized: ~60k gas
uint256 price = BlackScholesWad.priceCallOnly(params);
// Full calculation: ~100k gas
PriceResultWad memory result = BlackScholesWad.priceCall(params);Security Considerations
Numerical Precision
The 64.64 format provides ~18 decimal digits of precision:
- Safe range: Prices and volatilities in practical ranges
- Overflow risk: Very large spot/strike ratios (>10^9)
- Underflow risk: Very small time to expiry or volatility
Edge Cases
| Scenario | Handling |
|---|---|
| Zero volatility | Will revert (division by zero in d1/d2) |
| Zero time to expiry | Will revert (division by zero) |
| Very deep ITM/OTM | May lose precision near 0 or 1 |
| Negative price result | Clamped to 0 (shouldn't occur for valid inputs) |
Input Validation
The libraries assume valid inputs. The DiffusalOptionsQuoter validates:
- Non-zero volatility
- Non-expired options
- Non-zero spot and strike prices
Code Reference
Source:
packages/contracts/src/utils/BlackScholesLib.sol— Core 64.64 implementationpackages/contracts/src/utils/BlackScholesWad.sol— WAD adapter
Key Constants
// From Constants.sol (64.64 format)
int128 constant ONE_64X64 = 0x10000000000000000; // 1.0
int128 constant TWO_64X64 = 0x20000000000000000; // 2.0
int128 constant HALF_64X64 = 0x8000000000000000; // 0.5
// WAD
uint256 constant WAD = 1e18;Related
- Black-Scholes (Math) — Mathematical background
- Math64x64Extended — Underlying math library
- DiffusalOptionsQuoter — External pricing interface
- Options Greeks — Detailed Greeks explanation