Developer Documentation

DarkSightDeveloper Docs

Build privacy-preserving prediction markets with zero-knowledge proofs on Solana

⚠️

Status: Pre-Alpha Implementation

The DarkSight protocol is in active development. Core circuits with complete constraint logic, SDK with real cryptographic implementations (circomlibjs), comprehensive test suites, and research foundations are implemented and available on GitHub. CI/CD pipelines ensure code quality. Package names, method signatures, and costs are subject to change as implementation progresses. This documentation represents the current API design and architecture.

Getting Started

Installation

The DarkSight SDK source code is available on GitHub. Clone the repository to get started:

git clone https://github.com/DarkSightTeam/darksight-protocol.git

The SDK source code is available on GitHub. The package is configured as @darksight/sdkbut is currently in pre-alpha. You can use the source code directly from the repository or install locally.

cd sdk && npm install

The repository contains three main components:

  • /circuits - Zero-knowledge proof circuits (Circom)
  • /sdk - TypeScript SDK with Merkle tree and crypto primitives
  • /research - Formal proofs and privacy simulations

Quick Start

Once released, you will initialize the SDK with your Solana wallet connection:

import { DarkSightSDK } from '@darksight/sdk';
import { Connection, Wallet } from '@solana/web3.js';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet = new Wallet(/* your wallet */);

const sdk = new DarkSightSDK({
  connection,
  wallet,
  network: 'mainnet-beta'
});

// Initialize the SDK
await sdk.initialize();

Note: The SDK implementation is available in the /sdk directory of the repository. This API matches the current implementation.

Prerequisites

  • Node.js 18+ or Bun runtime
  • Solana wallet (Phantom, Solflare, or programmatic wallet)
  • Basic understanding of Solana development
  • Familiarity with TypeScript/JavaScript

Architecture Overview

Core Components

DarkSight is built on Solana using zero-knowledge proofs (Groth16 SNARKs) and Light Protocol's ZK Compression. The architecture consists of three main circuits, all implemented and available on GitHub:

Deposit Circuit

Handles shielded pool deposits with Merkle tree insertion proofs. Includes proper nullifier derivation and temporal mixing constraints.

Public: deposit_amount, new_root, timestamp

Private: secret, nullifier, merkle_path

Position Update Circuit

Manages private position updates and trade execution with full AMM invariant enforcement, slippage protection, and authorization checks.

Public: market_id, new_pool_state, price_impact

Private: position_before, position_after, trade_amount

Withdrawal Circuit

Processes withdrawals with nullifier proofs to prevent double-spending. Includes recipient binding and proper Merkle path verification.

Public: nullifier, amount, recipient

Private: position, merkle_path, secret

Privacy Guarantees

DarkSight ensures privacy through multiple layers:

  • Synthetic Activity: Protocol-generated cover traffic ensures privacy from user #1, eliminating the bootstrapping paradox.
  • Temporal Mixing: Operations are batched with randomized processing delays (1-24 hours) to prevent timing correlation attacks.
  • ZK Compression: Reduces on-chain costs to ~$0.01 per trade while maintaining full privacy guarantees.

State Management

The protocol uses a Sparse Merkle Tree (depth-32) to store all shielded positions. Only the Merkle root is stored on-chain, with individual positions stored in compressed state. This enables:

  • Support for up to 2³² concurrent positions
  • 100x cost reduction vs. uncompressed storage
  • Client-side witness generation (no trusted server)

SDK & API Reference

Core Classes

DarkSightSDK

Main SDK class for interacting with the DarkSight protocol.

class DarkSightSDK {
  constructor(options: DarkSightSDKOptions)
  async initialize(): Promise<void>
  async deposit(amount: number): Promise<DepositResult>
  async createMarket(options: CreateMarketOptions): Promise<Market>
  async createPosition(options: CreatePositionOptions): Promise<Position>
  async withdraw(options: WithdrawOptions): Promise<WithdrawResult>
  async getMarkets(options?: GetMarketsOptions): Promise<Market[]>
  async getPositions(options?: GetPositionsOptions): Promise<Position[]>
  onMarketUpdate(marketId: string, callback: Function): () => void
  async disconnect(): Promise<void>
}

Market

Represents a prediction market with its current state and odds.

interface Market {
  id: string
  question: string
  outcomes: string[]
  currentOdds: Record<string, number>
  totalLiquidity: number
  volume24h: number
  resolutionDate: Date
  status: 'active' | 'resolved' | 'cancelled'
  resolvedOutcome?: string
}

Position

Represents a private position in a market.

interface Position {
  id: string
  marketId: string
  outcome: string
  amount: number
  commitment: string // Poseidon commitment
}

Proof Generation

ZK proofs are generated client-side using WebAssembly. The SDK handles proof generation automatically. The circuit implementations are available in the /circuits directory of the repository:

// Proof generation is handled automatically in our current design:
const sdk = new DarkSightSDK({
  connection,
  wallet,
  proofConfig: {
    wasmPath: '/path/to/prover.wasm',
    timeout: 10000, // 10 seconds
    useWorker: true // Use web worker for non-blocking proof generation
  }
});

Proof generation is expected to take 2-3 seconds on modern devices. For mobile, native libraries are planned for sub-1 second generation. See the circuits repository for implementation details.

Integration Guides

Creating a Market

Create a new prediction market with initial liquidity:

const market = await sdk.createMarket({
  question: 'Will Bitcoin reach $100K by end of 2025?',
  outcomes: ['Yes', 'No'],
  resolutionDate: new Date('2025-12-31'),
  initialLiquidity: 10000, // SOL
  description: 'Optional market description',
  category: 'crypto'
});

console.log('Market created:', market.id);

Placing a Private Position

Create a private position without revealing your trade size or direction:

// First, deposit funds into the shielded pool
const depositResult = await sdk.deposit(1000); // 1000 SOL

// Create a private position
const position = await sdk.createPosition({
  marketId: market.id,
  outcome: 'Yes',
  amount: 500 // SOL
});

// Position is completely private - only you know the details
console.log('Position commitment:', position.commitment);

Querying Markets

Fetch market data and current odds:

// Get all active markets
const markets = await sdk.getMarkets({
  status: 'active',
  limit: 50,
  offset: 0
});

// Find specific market by ID
const market = markets.find(m => m.id === marketId);

// Current odds are public
console.log('Yes odds:', market?.currentOdds['Yes']);
console.log('No odds:', market?.currentOdds['No']);
console.log('24h volume:', market?.volume24h);

Withdrawing Funds

Withdraw funds from the shielded pool using zero-knowledge proofs:

// Get your positions for a market
const positions = await sdk.getPositions({
  marketId: market.id,
  outcome: 'Yes'
});

// Withdraw funds (zero-knowledge proof verifies ownership)
const withdrawResult = await sdk.withdraw({
  amount: winningsAmount,
  recipient: wallet.publicKey
});

console.log('Withdrawal signature:', withdrawResult.signature);
console.log('Nullifier:', withdrawResult.nullifier);

Examples

Complete Trading Flow

Example of SDK usage (pre-alpha implementation):

import { DarkSightSDK } from '@darksight/sdk';
import { Connection, Keypair } from '@solana/web3.js';

async function tradeExample() {
  // Initialize SDK
  const connection = new Connection('https://api.mainnet-beta.solana.com');
  const wallet = Keypair.generate(); // In production, use actual wallet
  
  const sdk = new DarkSightSDK({
    connection,
    wallet,
    network: 'mainnet-beta'
  });
  
  await sdk.initialize();
  
  // 1. Deposit funds
  const deposit = await sdk.deposit(1000);
  console.log('Deposited:', deposit.amount);
  
  // 2. Find a market
  const markets = await sdk.getMarkets({ status: 'active' });
  const market = markets[0];
  
  // 3. Create private position
  const position = await sdk.createPosition({
    marketId: market.id,
    outcome: 'Yes',
    amount: 500
  });
  
  console.log('Position created:', position.id);
  console.log('Current odds:', market.currentOdds);
  
  // 4. Wait for market resolution...
  // (In production, you'd listen for resolution events)
  
  // 5. Withdraw winnings
  const withdraw = await sdk.withdraw({
    amount: 750, // Your winnings
    recipient: wallet.publicKey
  });
  
  console.log('Withdrawn:', withdraw.amount);
}

tradeExample().catch(console.error);

React Integration

React hook example for SDK integration. See /sdk/examples in the repository for more examples:

import { useEffect, useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';
import { DarkSightSDK } from '@darksight/sdk';

export function useDarkSight() {
  const { publicKey, signTransaction } = useWallet();
  const [sdk, setSdk] = useState<DarkSightSDK | null>(null);
  
  useEffect(() => {
    if (!publicKey) return;
    
    const connection = new Connection('https://api.mainnet-beta.solana.com');
    const sdkInstance = new DarkSightSDK({
      connection,
      wallet: { publicKey, signTransaction },
      network: 'mainnet-beta'
    });
    
    sdkInstance.initialize().then(() => setSdk(sdkInstance));
    
    return () => {
      sdkInstance?.disconnect();
    };
  }, [publicKey, signTransaction]);
  
  return sdk;
}

// Usage in component
function TradingComponent() {
  const sdk = useDarkSight();
  const [markets, setMarkets] = useState([]);
  
  useEffect(() => {
    if (!sdk) return;
    sdk.getMarkets().then(setMarkets);
  }, [sdk]);
  
  // ... rest of component
}

Reference

Type Definitions

SDKConfig

interface SDKConfig {
  connection: Connection
  wallet: Wallet
  network: 'mainnet-beta' | 'devnet' | 'testnet'
  proofConfig?: ProofConfig
  rpcEndpoint?: string
}

MarketFilters

interface MarketFilters {
  status?: 'active' | 'resolved' | 'all'
  category?: string
  resolutionDate?: { from?: Date; to?: Date }
  minVolume?: number
  limit?: number
  offset?: number
}

OracleSource

type OracleSource = 
  | 'chainlink'      // Tier 1: Objective markets
  | 'uma'           // Tier 2: Subjective markets
  | 'committee'     // Tier 3: Hybrid markets

Error Handling

The SDK throws typed errors for better error handling:

import { 
  DarkSightError,
  InsufficientBalanceError,
  MarketNotFoundError,
  ProofGenerationError,
  NetworkError
} from '@darksight/sdk';

try {
  await sdk.createPosition({ marketId, outcome, amount });
} catch (error) {
  if (error instanceof InsufficientBalanceError) {
    console.error('Not enough balance in shielded pool');
  } else if (error instanceof ProofGenerationError) {
    console.error('Failed to generate ZK proof:', error.message);
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
  }
}

Events & Subscriptions

The SDK will support subscribing to real-time market updates:

// Subscribe to market updates
sdk.onMarketUpdate(marketId, (update) => {
  console.log('Odds updated:', update.currentOdds);
  console.log('New volume:', update.volume24h);
});

// Subscribe to position updates
sdk.onPositionUpdate((position) => {
  console.log('Position updated:', position.id);
});

// Cleanup
sdk.removeAllListeners();

Costs & Limits

OperationEstimated Cost
Deposit~$0.01
Trade~$0.005 + 0.1%
Withdraw~$0.008
Market Creation~$0.05

Note: Costs are estimates based on current Solana fee structures and ZK Compression. Actual costs may vary.

Planned minimum position size: 0.1 SOL. Maximum position size: No limit (subject to market liquidity).