Skip to content
All posts
· 3 min read

Building NextOutcome: Polymarket, Native on iOS

swiftswiftuiiosnextoutcome

Polymarket lives in a browser. I built NextOutcome to put it on iOS properly — SwiftUI feeds, Swift Charts, live WebSocket order books, no web views anywhere. Watch-only today, trading on the roadmap. Three problems made it worth writing about.

Order books that never die

The connection will drop; the book must come back on its own. Each subscription is one AsyncStream whose producer owns the whole connect/reconnect loop — when the SwiftUI view disappears, the stream's onTermination cancels the task and the socket tears itself down. Reconnects use exponential back-off with jitter:

MarketSocket.swift
/// 0.5s, 1s, 2s … capped at 30s, with ±20% jitter so
/// clients don't reconnect in lockstep.
private func backoffNanos(_ attempt: Int) -> UInt64 {
    let base = min(30.0, 0.5 * pow(2.0, Double(attempt - 1)))
    let jittered = base * Double.random(in: 0.8...1.2)
    return UInt64(jittered * 1_000_000_000)
}

The jitter is the part people skip: without it, every client reconnects at the same instant after a server blip — in waves. The ±20% spreads the herd.

A World Cup on a globe

The hub's Map tab is a draggable SceneKit globe where each nation's win odds float over the country. Input: the "World Cup winner" futures market, one outcome per nation. The surprise problem was clustering — South America stacks its contenders along one meridian and the pills pile up. Fix: a small relaxation pass that pushes overlapping pills apart with bounded drift, so Brazil's odds still hover over Brazil. The builder is a pure function (market in, pills out), so it's unit-tested without touching SceneKit.

Architecture that says no

Clean Architecture in vertical slices, ~18 SPM targets. Two rules pay rent: Presentation never imports Data (wire-format changes never touch view files), and the Trading module — order signing, wallet proxy — is never linked by the read-only app. Not a feature flag: the binary physically can't sign anything. In this space, "can't" beats "doesn't."


Code's public: github.com/sokpichdev/NextOutcome, no API keys needed. Screenshots on the landing page.