Horus
Fully on Chain Prediction Markets (no order book)
Created on 21st February 2026
•
Horus
Fully on Chain Prediction Markets (no order book)
The problem Horus solves
Prediction markets today are either centralized (the operator picks the outcome) or limited to assets on a single chain. Horus solves both problems:
Multi-chain price markets for any token. Users can bet on whether any token with Uniswap liquidity — on Ethereum, Base, or any supported chain — will go up in 10 minutes. The market contract lives on Ethereum Sepolia, but the price oracle reads from tokens on other chains via the Uniswap API. This means you can create a prediction market for a Base memecoin while settling in USDC on Sepolia.
Auditable oracle with a path to trustlessness. The admin submits the price, but cannot fabricate it. Every market stores its oracle metadata on-chain — the API endpoint, source chain, pool address, and token address. Anyone can independently query the same Uniswap API endpoint and verify the submitted price matches. This metadata is also the exact input specification for a future zkTLS verifier, which would make resolution fully permissionless and provably correct without any admin involvement.
What users can do:
- Create markets — anyone with ≥10 USDC can create a 10-minute prediction market for any token (permissionless on the contract level)
- Trade — buy YES/NO tokens with USDC. Prices reflect crowd probability via a constant-product AMM (CPMM)
- Provide liquidity — earn 2% swap fees by adding USDC to the pool
- Claim winnings — after resolution, winning token holders redeem 1:1 for USDC
- Mint/Redeem — always mint 1 YES + 1 NO for 1 USDC, or redeem the pair back. Fully collateralized at all times.
Why it matters: Short-duration prediction markets on memecoins are a natural fit — high volatility, high engagement, fast feedback loops. Horus makes this possible across chains with an auditable oracle, moving the trust model from "trust the operator" to "verify the data source yourself."
Challenges I ran into
Decoupling the oracle from the market chain. V1 and V2 of the contract read the price directly from a Uniswap V3 pool on the same chain (slot0().tick). This meant markets could only exist for tokens with pools on the deployment chain. Moving to a submitted-price model (V3) required rethinking the entire resolution flow — the contract no longer reads the price itself, so we needed to store oracle metadata on-chain to keep the system auditable. Getting the right balance between "fast to build" and "architecturally sound for future zkTLS" took several iterations.
Uniswap API response format inconsistencies. The Uniswap Trade API returns price data in different formats depending on the routing path — sometimes quote.output.amount (raw bigint), sometimes quote.outputAmount, sometimes quote.quoteDecimals (human-readable float). We had to handle all three variants and normalize to a consistent 18-decimal int256 format for the contract. The API also returns 504 gateway timeouts under load, so we added retry logic with exponential backoff.
Multi-hop price routing. Many tokens (especially memecoins) don't have a direct USDC pool. The initial implementation failed silently for these tokens. We had to build a two-hop fallback (token → WETH → USDC) using two sequential quote calls, which introduced complexity around decimal handling — WETH uses 18 decimals while USDC uses 6.
USDC approval flow for permissionless creation. V2's factory pulled USDC from the admin wallet. V3 allows anyone to create a market, so the factory now pulls USDC from msg.sender. This required adding an explicit approve transaction before createMarket — a two-step flow that needed careful handling in both the API (for admin-created markets) and the frontend (for user-created markets).
Frontend crashes from undefined on-chain data. When the API failed to read on-chain data (e.g. during RPC timeouts), it returned market objects without yesReserve, noReserve, or price fields. The frontend called BigInt(undefined) and crashed. We had to add defensive fallbacks at both the API layer (return zero defaults on failure) and the frontend (guard every BigInt conversion).
Contract version migration. Upgrading from V2 to V3 ABIs across the entire stack (API routes, chain service, test scripts, frontend config) was error-prone. A single missed ABI reference would cause silent failures where the contract call returned unexpected data. We caught several of these only through the integration test suite.
Tracks Applied (2)
New France Village
Integrate the Uniswap API in your platform
Uniswap Foundation
Technologies used
