Trading math
Two trade primitives: discrete (buy or sell a single outcome) and distribution (allocate across many outcomes via a Gaussian). Both preserve the L₂ invariant.
Discrete buy
A trader spends c units of collateral to buy outcome i. The protocol mints a complete set of tokens (one of each outcome at $1) using the collateral, then executes the buy by moving along the hypersphere:
k' = k + c
x'ᵢ = √(k'² − Σⱼ≠ᵢ xⱼ²)
tokens_out = x'ᵢ − xᵢ
After the trade, all outcomes other than i are unchanged in x. Only xᵢ increases. The new norm is k', larger than before because new collateral was added.
Discrete sell
A trader returns t tokens of outcome i and receives collateral:
x'ᵢ = xᵢ − t
k' = √(Σⱼ x'ⱼ²)
collateral_out = k − k'
Same shape as the buy, just inverted. The norm shrinks; the difference is what the trader walks away with.
Distribution buy (the "draw a curve" trade)
This is the new primitive. The trader specifies a Gaussian (μ, σ) over a continuous range [a, b] divided into N bins. The system computes weights Wⱼ for each bin from the Normal PDF, then buys all N outcomes simultaneously in proportion to those weights.
Step 1: bin discretization
The center of bin j (zero-indexed) is:
centerⱼ = a + (2j+1)(b − a) / (2N)
The standardized z-score is:
zⱼ = (centerⱼ − μ) / σ
The unnormalized weight is the Normal PDF evaluated at zⱼ:
wⱼ = exp(−zⱼ² / 2)
Bins where |zⱼ| > 5 are clipped to weight 0. Then weights are scaled so they sum to a fixed integer S = 10⁹ (the protocol's fixed-point scale):
Wⱼ = wⱼ · S / Σ wⱼ
This gives an integer weight vector W with Σ Wⱼ = S - no floating point on-chain.
Step 2: solve for the trade size
Given total spend c, the protocol moves along the hypersphere from k to k' = k + c while distributing the trade across all bins in proportion to W. Define:
XW = Σⱼ xⱼ Wⱼ
W² = Σⱼ Wⱼ²
Solve the quadratic that comes from the L₂ invariant for the scalar λ:
λ = √(XW² + W²·(k'² − k²)) − XW
Tokens received per bin:
tokens_outⱼ = λ · Wⱼ / W²
The bin nearest the trader's μ gets the largest slice; bins in the tails get less. After the trade, the new state x'ⱼ = xⱼ + tokens_outⱼ lies exactly on the new hypersphere of radius k', preserving the invariant.
The full derivation of λ from the hypersphere constraint is in Appendix A of the math model.
Distribution sell
The trader returns T total tokens, allocated across bins in proportion to the same weight vector W:
tⱼ = T · Wⱼ / S
Capped at the trader's actual holding in each bin (tⱼ ← min(tⱼ, holdingⱼ)).
The new AMM state and refunded collateral:
x'ⱼ = xⱼ − tⱼ
k' = √(Σⱼ x'ⱼ²)
collateral_out = k − k'
Sanity check: invariant preserved
After every trade:
Σ x'ⱼ² = k'² (within INVARIANT_TOL = 256, see Constants)
A small slack of 256 absorbs rounding error from integer arithmetic. Trades that would exceed this slack revert.
Round-trip cost
Two trade fees of 30 bps each plus AMM slippage means a round-trip (buy + sell) costs at least 60 bps. This creates a natural bid-ask spread without an order book.
Where this is implemented
Closed-form solutions for all three operations live in the on-chain Rust program. The frontend uses the same formulas in TypeScript for the bet preview. Both sides use u64/u128 integer arithmetic - no floating point.