← back to projects

Distro

Feb 2026 – Presentactive
Uniswap V4AMMPrediction MarketsGaussianSolidity

// the problem

Traditional prediction markets force discrete outcomes. But most real-world questions have continuous answers: not 'will ETH be above $3000?' but 'where will ETH be on March 30?' Binary markets lose information — they can't capture the difference between a trader who's 51% confident and one who's 99% confident in the same direction. More practically, binary markets need market makers willing to take the other side. Continuous Gaussian markets solve both problems.

// the design decision

The AMM maintains aggregate state f(x) = λ·φ(x) where φ is a Normal PDF(μ, σ). When a trader opens a position, they shift the state from f to g — their position is the difference g(x) − f(x), collateralized by the minimum of that difference. At resolution, payout = g(x*) − f(x*). The zero-sum property telescopes automatically: every winner is paid from losers' collateral. LPs provide a USDT/USDC pool but are never the counterparty to prediction positions — they earn fees from both AMM swaps and prediction activity via donate().

// key implementation detail

The hook is built on Uniswap V4. Swaps without hookData are normal stablecoin swaps. Swaps with hookData route to the prediction market via NoOp, bypassing the AMM entirely. The critical math challenge: verifying the minimum of g(x) − f(x) on-chain without unbounded iteration. We compute it off-chain and have the contract verify via four checks — first derivative zero, second derivative positive, side check (exactly one global min exists on the opposite side of g's mean from f's mean), and a dust threshold.
// L2 norm invariant check
// λ² = 2k²σ√π must hold after every trade
function verifyInvariant(
    int128 lambda, uint128 sigma, uint128 k_squared
) internal pure {
    // λ² = 2k²σ√π
    // Using PRBMath SD59x18 for precision
    int256 lhs = SD59x18.unwrap(lambda.pow(sd(2e18)));
    int256 rhs = int256(uint256(k_squared))
        .mul(int256(uint256(sigma)))
        .mul(SQRT_PI_X2); // 1_772453850905516027 * 2
    require(lhs == rhs, "Invariant violated");
}

// what i learned

Gaussian distributions on-chain require very careful fixed-point arithmetic. PRBMath SD59x18 handles it, but gas costs compound quickly. The min-point verification pattern — compute off-chain, verify on-chain — is a useful primitive for any optimization problem in smart contracts. The hardest part was convincing LPs to trust a novel invariant: the LP economics proof (strictly more revenue than competing stablecoin pools, zero prediction risk) took longer to get right than the hook itself.