Skip to content

jamallwinn/dark-oracle

Repository files navigation

Dark Oracle

Zero-Knowledge Verified Prediction Markets on Chainlink CRE

Solidity TypeScript Next.js Chainlink CRE ZK Proofs Base Sepolia Tests License

Chainlink Convergence 2026 Hackathon | Prediction Markets Track


Live App

https://dark-oracle-pred-market-176028355587.us-central1.run.app

Demo Video (5:12)

Watch the full narrated demo — includes frontend walkthrough + CRE workflow simulation with all 7 pipeline steps


The Problem

Prediction markets hold $1.2B+ in TVL, yet users have zero mathematical proof that resolution is honest. Polymarket relies on economic incentives (UMA token holder voting). Kalshi relies on institutional trust (a company decides). Both assume honesty rather than proving it. Oracle manipulation is invisible theft with no recourse.

The Solution

Dark Oracle replaces trust with proof. Chainlink CRE fetches price data from 3 independent APIs across a Decentralized Oracle Network with BFT consensus. A Groth16 zero-knowledge proof cryptographically binds the market ID, outcome, data sources, and timestamp together — tamper with any input and the on-chain pairing check fails. Double verification: DON cryptographic signature + on-chain ZK proof. Anyone can verify. Nobody can manipulate.

"Polymarket trusts that nobody will dispute the result. Kalshi trusts that the company is honest. Dark Oracle trusts math."


Architecture

                          +-----------------------+
                          |      React dApp       |
                          |   (Next.js 16 + wagmi)|
                          +-----------+-----------+
                                      |
                                      v
                          +-----------+-----------+
                          |  DarkOracleMarket.sol |
                          |     (Base Sepolia)    |
                          +-----------+-----------+
                                      ^
                                      | onReport (DON-signed)
                          +-----------+-----------+
                          | KeystoneForwarder     |
                          +-----------+-----------+
                                      ^
                          +-----------+-----------+
                          |   Chainlink CRE DON   |
                          |  7-step resolution     |
                          +-----------+-----------+
                           /          |          \
                          v           v           v
                   +-----------+ +---------+ +-----------+
                   | CoinGecko | | Binance | | Coinbase  |
                   +-----------+ +---------+ +-----------+
                                      |
                                      v
                          +-----------+-----------+
                          |  External ZK Prover   |
                          |  (Groth16 proof gen)   |
                          +-----------+-----------+
                                      |
                                      v
                          +-----------+-----------+
                          | DarkOracleVerifier.sol|
                          |  BN254 pairing check  |
                          |     (236k gas)        |
                          +-----------------------+

Flow: CRE DON fetches prices from 3 sources -> calculates consensus -> calls external prover for Groth16 proof -> delivers DON-signed report to contract -> on-chain BN254 pairing verification -> market resolved.


Key Features

  • Multi-source data aggregation — CoinGecko, Binance, and Coinbase fetched independently via CRE
  • Real Groth16 ZK proof verification — 771-constraint circuit, BN254 pairing check on-chain (236k gas)
  • 7-screen React dApp with Proof Inspector page for visual ZK verification
  • Parimutuel market model with USDC collateral and proportional payouts
  • CRE 7-step resolution pipeline — compiled to WASM, simulation-verified
  • Bypass mode toggle — testing vs production, currently disabled (real Groth16 active)
  • Double verification — DON cryptographic signature + on-chain ZK proof must both pass

Tech Stack

Layer Technology
Smart Contracts Solidity 0.8.19, Foundry, OpenZeppelin (ReentrancyGuard, Ownable)
ZK Circuits Circom 2.1, Groth16, BN254 curve, snarkjs, Poseidon hashing
CRE Workflow Chainlink CRE SDK, TypeScript, WASM (Javy-compiled)
Prover Service Express.js, snarkjs, Docker
Frontend Next.js 16, React 19, wagmi v2, RainbowKit 2.2, Tailwind v4
Chain Base Sepolia (84532)

Deployed Contracts (Base Sepolia)

Contract Address Verified
MockUSDC 0x1a3065F54a56760aB45499Eb166eE9D3b997fd49 Yes
DarkOracleVerifier 0xF0029EC0836173806b3c26C383C55436b41959BC Yes
DarkOracleMarket 0xE79Aff29c29D3CfD93e1eF647Ba4220f0e6CF5b2 Yes

bypassVerification is false — real Groth16 pairing verification is active on-chain.


Quick Start

# Clone
git clone https://github.com/jamallwinn/dark-oracle.git
cd dark-oracle

# Smart Contracts
cd contracts
forge build
forge test -v          # 87/87 tests pass

# Frontend
cd frontend
npm install
npm run dev            # http://localhost:3000

# ZK Circuit (optional — artifacts included)
cd circuits
./build.sh             # Compile circuit + trusted setup

# Prover Service (optional)
cd prover-service
npm install
npm start              # http://localhost:3001

Project Structure

dark-oracle/
├── contracts/                  # Solidity smart contracts (Foundry)
│   ├── src/
│   │   ├── DarkOracleMarket.sol      # Core market lifecycle + parimutuel payouts
│   │   ├── DarkOracleVerifier.sol    # Groth16 BN254 on-chain verifier
│   │   ├── MockUSDC.sol              # Testnet ERC-20 (6 decimals)
│   │   └── interfaces/               # IDarkOracleVerifier
│   ├── test/                          # 87 unit tests (69 market + 18 verifier)
│   └── script/                        # Foundry deploy scripts
├── circuits/                   # Circom ZK circuit
│   ├── resolution_proof.circom       # 771 constraints, 3-source threshold proof
│   └── build.sh                      # Compile + trusted setup + test
├── prover-service/             # Express + snarkjs REST API
│   ├── src/                          # /health, /prove endpoints
│   ├── test/                         # 7 integration tests
│   └── Dockerfile                    # Container deployment
├── workflows/                  # Chainlink CRE resolution workflow ★
│   └── dark-oracle-resolve/
│       ├── main.ts                   # 7-step pipeline (447 lines) ★
│       ├── config.staging.json       # Data sources + contract addresses
│       └── workflow.yaml             # CRE deployment config
├── frontend/                   # Next.js 16 React dApp
│   └── src/
│       ├── app/                      # 5 routes (/, /create, /market/[id], /market/[id]/proof)
│       ├── hooks/                    # 11 wagmi hooks
│       ├── components/               # MarketCard, PositionForm, ClaimButton, ProofInspector
│       ├── config/                   # Contract ABIs + addresses
│       └── lib/                      # Formatting + utility helpers
├── video/
│   └── output/
│       └── dark-oracle-demo-v4-full.mp4  # 5:12 narrated demo
├── Dockerfile                  # Cloud Run deployment
└── project.yaml                # CRE global config

Test Results

Component Tests Status
Smart Contracts (Forge) 87/87 PASS
Frontend TypeScript (tsc --noEmit) 0 errors PASS
Frontend ESLint 0 errors PASS
Frontend Production Build 5 routes PASS
E2E Lifecycle (Base Sepolia) 11/11 steps PASS
Groth16 Verification (on-chain, bypass=false) Valid proof: true PASS
Groth16 Negative Test (invalid proof) Returns false PASS
Prover Service (proof gen) ~800ms PASS
CRE Workflow Simulation Compile + simulate PASS

Demo Video

Watch the full narrated demo (5:12)

The video is split into two sections:

Part 1 — Frontend Walkthrough (0:00–3:11)

  1. Landing page with live market cards and implied probability prices
  2. How It Works — 4-step resolution pipeline visualization
  3. Create Market with 3 independent data sources
  4. Resolved market with on-chain proof hash
  5. Proof Inspector — ZK public inputs, proof hash, and live on-chain re-verification (236k gas)

Part 2 — CRE Workflow Simulation (3:11–5:12)

  1. cre workflow simulate running all 7 pipeline steps in terminal
  2. Live API calls to CoinGecko, Binance, Coinbase
  3. Consensus calculation and threshold comparison
  4. Groth16 proof generation (1,176ms)
  5. DON report signing (ECDSA + keccak256)
  6. On-chain write with verifyProof() — ecAdd, ecMul, ecPairing

CRE Integration Details

Dark Oracle uses 7+ Chainlink CRE capabilities across a single resolution workflow:

# CRE Capability Usage
1 CronTrigger Hourly resolution checks for pending markets
2 HTTPClient (source 1) Fetch BTC price from CoinGecko API
3 HTTPClient (source 2) Fetch BTC price from Binance API
4 HTTPClient (source 3) Fetch BTC price from Coinbase API
5 HTTPClient (prover) POST to external ZK prover for Groth16 proof generation
6 EVMClient (read) Call getPendingResolutions() on DarkOracleMarket
7 Consensus DON-wide agreement on fetched data via report signing
8 Report Signing DON cryptographic signature on encoded report
9 writeReport Deliver signed report to onReport() via KeystoneForwarder

CRE Workflow Pipeline (7 Steps)

1. CronTrigger fires (hourly)
2. EVMClient reads getPendingResolutions() from contract
3. HTTPClient fetches prices from 3 independent APIs
4. Calculate consensus: average, threshold comparison, confidence score
5. HTTPClient POSTs to external ZK prover → receives Groth16 proof
6. ABI-encode report: [marketId, outcome, resolvedValue, timestamp,
   confidence, sourceCount, proofA, proofB, proofC, publicInputs]
7. DON signs report → writeReport → onReport() on-chain

Why External ZK Prover?

QuickJS (CRE's WASM sandbox) cannot run nested WASM modules. snarkjs requires WASM for proof generation. Solution: external prover microservice called via HTTPClient, with self-verification before returning the proof.


How Verification Works

The ZK circuit (resolution_proof.circom, 771 constraints) creates a Groth16 proof that binds together:

Public Input Purpose
marketId Which market this resolves
outcome YES (1) or NO (0)
dataSourcesHash Poseidon hash of source IDs — proves which data was used
resolutionTimestamp When the data was fetched

Verification Flow

1. CRE nodes fetch prices from 3 independent APIs
2. Consensus determines outcome: average >= threshold → YES, else → NO
3. External prover generates Groth16 proof (~800ms)
   - Binds: marketId + outcome + sources + timestamp
   - Uses Poseidon hashing for source commitment
   - Threshold comparison: sum >= threshold * numSources (avoids field division)
4. Proof delivered on-chain in DON-signed report
5. DarkOracleVerifier.sol verifies BN254 elliptic curve pairing
   - ecAdd (precompile 0x06)
   - ecMul (precompile 0x07)
   - ecPairing (precompile 0x08)
   - Cost: 236,483 gas
6. Both DON signature AND ZK proof must pass → market resolves
7. proofHash stored on-chain permanently — anyone can re-verify

If the proof is invalid, the pairing check fails and the market does not resolve. Tested on-chain: valid proofs return true, modified proofs return false.


Honest Comparison

Dark Oracle Polymarket Kalshi
Resolution trust Cryptographic (ZK proof) Economic (dispute/vote) Institutional (CFTC)
Proof of honesty On-chain ZK proof (verifiable) Economic bonds (challengeable) Legal filings (trust-based)
Resolution speed Automatic at resolution time Hours-days (dispute window) Hours (manual)
Verifiability Anyone, on-chain, any time UMA token holders only CFTC filings only
Liquidity Testnet MVP Deep ($B+ volume) Deep (regulated)
Market types Binary YES/NO Binary + multi-outcome Binary events
Order book Parimutuel pool CLOB (limit orders) CLOB

Dark Oracle leads on trust model, resolution speed, and public verifiability. Competitors lead on liquidity, market variety, and regulatory status.


E2E Lifecycle (Verified on Base Sepolia)

Full create -> bet -> resolve -> verify -> claim tested on-chain:

Step Description Gas
1 Create market 151,971
2 Mint testnet USDC 34,180
3 Approve USDC 29,231
4 Place YES position (10 USDC) 116,837
5 onReport (DON-signed resolution) 124,115
6 Claim winnings (+10 USDC returned) 56,484

All on-chain state verified: auto-transition (H-5), public input binding (C-2), outcome mapping (H-4), payout math.


Security

  • ReentrancyGuard on claimWinnings (OpenZeppelin)
  • Collateral whitelist — only approved tokens accepted
  • Public input bindingpublicInputs[0] must match marketId, publicInputs[1] must match outcome
  • Custom errors — 22 gas-efficient error types (no string reverts)
  • Emergency resolution — owner-only 24h-delayed fallback
  • Position close guard — rejects positions after resolution time
  • Proof self-verification — prover service verifies proof locally before returning
  • Code review: 6 audit rounds, all Critical and High findings resolved

Hackathon Submission

Hackathon Chainlink Convergence 2026
Track Prediction Markets
Deadline March 1, 2026
Differentiator Only submission combining ZK proofs + Chainlink CRE for verifiable market resolution

Chainlink Files Index

All Chainlink CRE integration code:

File Description
workflows/dark-oracle-resolve/main.ts Primary CRE workflow — 7-step resolution pipeline (447 lines)
workflows/dark-oracle-resolve/workflow.yaml CRE workflow settings (staging/production)
workflows/dark-oracle-resolve/config.staging.json Data sources, contract addresses, prover URL
workflows/dark-oracle-resolve/package.json @chainlink/cre-sdk v1.0.9 dependency
project.yaml CRE global project configuration
secrets.yaml CRE secrets configuration

License

MIT

About

Zero-Knowledge Verified Prediction Markets on Chainlink CRE — Groth16 proofs, 3-source data aggregation, automated resolution on Base Sepolia

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors