n0paths

§11–§12 · code

From browser math to Solidity.

What changes when the formulas on the method page move from double-precision TypeScript to a metered, fixed-point EVM, and the interface the resulting engine would expose.


§11

EVM implementation notes

Every formula on this page runs today in TypeScript, in a browser, in 64-bit floating point. Porting it to Solidity changes three things.

Fixed-point arithmetic

The EVM has no native floating point.[8] Every quantity in Table 1 and every intermediate in equations (4)–(9) would need to be represented as a scaled integer and carried through exp, ln, and the normal CDF using a fixed-point math library, at some cost in both gas and precision relative to the double-precision numbers computed client-side on this page.

The normal CDF, on-chain

This page’s Φ(x) uses the rational erfc approximation from Numerical Recipes[7], evaluated in double precision. The same rational-polynomial structure ports to fixed-point Solidity in principle; it has not been implemented or gas-profiled here.

View functions, not transactions

price() and greeks() in §12 are declared view: they read oracle state and return a number without writing anything.[10] That is what makes them callable, for free, by another contract in the middle of its own transaction — the composability property motivating §1.

Gas cost

Each of exp, ln, and Φ is a handful of arithmetic operations rather than a loop over paths — the entire appeal of §4 is that this cost does not scale with a path count N the way §2’s does. What that cost actually is, measured in gas, on a real deployment: measurement pending.


§12

Engine API

Proposed interface for the on-chain engine — not yet deployed. It exposes exactly the three outputs described in §1’s motivation (price, Greeks, margin) as view functions over the six inputs from Table 1, plus a position size for margin(). The long-term goal is for this to be consumable as a primitive: any protocol that needs a deterministic, reproducible price for this instrument calls the engine directly, on-chain, rather than running its own off-chain pricing service.

interface IPricingEngine {
    struct MarketParams {
        uint256 spot;          // 1e18 fixed-point, from oracle
        uint256 strike;
        uint256 timeToExpiry;  // seconds until expiry
        uint256 volatility;    // 1e18 fixed-point, annualized
        int256  riskFreeRate;  // 1e18 fixed-point
        int256  carry;         // 1e18 fixed-point, dividend / funding
    }

    struct Greeks {
        int256 delta;
        int256 vega;
    }

    /// Deterministic price of one unit of the instrument.
    /// Same MarketParams in → same price out. Always.
    function price(MarketParams calldata params) external view returns (uint256);

    /// Numerical sensitivities, computed on-chain by finite difference
    /// on price(). Documented as numerical, not closed-form.
    function greeks(MarketParams calldata params) external view returns (Greeks memory);

    /// Margin requirement for a given position size under this engine's
    /// pricing model.
    function margin(MarketParams calldata params, uint256 positionSize)
        external
        view
        returns (uint256);
}

notes

  1. [7]Bound on the erfc approximation: |error| < 1.2×10⁻⁷ over the full real line. See Press, Teukolsky, Vetterling & Flannery, Numerical Recipes in C, 2nd ed., §6.2.
  2. [8]Solidity has no native floating point. Fixed-point libraries (e.g. PRBMath, ABDKMath64x64) represent a real number as an integer scaled by a fixed factor, commonly 10¹⁸ (“wei-scale”) or 2⁶⁴, and implement exp/ln as rational or binary-exponent approximations over that integer representation.
  3. [10]A Solidity `view` function reads contract state but cannot modify it, so calling it from another contract requires no transaction, consumes no gas when called off-chain (e.g. from a wallet or another chain's light client via a static call), and cannot be front-run in the way a state-changing call can.