@ludus/prediction-markets
The prediction markets SDK. Provides LMSR automated market makers, market creation from game templates, oracle resolution, position tracking, settlement, claim management, and compliance services.
Installation
Section titled “Installation”npm install @ludus/prediction-marketsLogarithmic Market Scoring Rule — automated market maker with bounded loss.
Cost function: C(q) = b * ln(Sum e^(qi/b))
import { LMSR } from '@ludus/prediction-markets';
const lmsr = new LMSR(100, 3); // b=100, 3 outcomes
// Current shares per outcomeconst shares = [0, 0, 0];
// Get implied probability (all outcomes start equal)lmsr.getPrice(shares, 0); // ~0.333lmsr.getAllPrices(shares); // [0.333, 0.333, 0.333]
// Cost to buy 10 shares of outcome 0const cost = lmsr.getCost(shares, 0, 10); // ~3.33
// After buying, prices shiftshares[0] += 10;lmsr.getPrice(shares, 0); // ~0.369 (higher after buying)
// Platform's bounded risklmsr.maxLoss(); // b * ln(N) = 100 * ln(3) ≈ 109.86
// Total cost paid into the marketlmsr.cost(shares);PriceCalculator
Section titled “PriceCalculator”Convenience wrapper for price quotes and trade simulations:
import { PriceCalculator } from '@ludus/prediction-markets';import type { PriceQuote, TradeQuote } from '@ludus/prediction-markets';LiquidityManager
Section titled “LiquidityManager”Manages market liquidity seeding and withdrawal:
import { LiquidityManager, StubLiquidityProvider } from '@ludus/prediction-markets';import type { LiquidityProvider } from '@ludus/prediction-markets';Outcome Types
Section titled “Outcome Types”Four outcome definitions:
import type { BinaryOutcome, // Yes/No — "Will Agent X win?" CategoricalOutcome, // One of N — "Which agent wins?" ScalarOutcome, // Numeric range — "How many rounds?" ConditionalOutcome, // Depends on another market OutcomeDefinition, // Union of all four OutcomeOption, // { id, label, metadata? } ResolvedOutcome, // Final result after game ends} from '@ludus/prediction-markets';
// Type guardsimport { isBinary, isCategorical, isScalar, isConditional, getOutcomeCount, buildOutcomeOptions, validateOutcomeDefinition,} from '@ludus/prediction-markets';Market Templates
Section titled “Market Templates”Templates auto-create markets for each game type:
import type { MarketTemplate, GameOutcomeTemplate } from '@ludus/prediction-markets';
// Template example:// { templateId: 'winner', name: 'Match Winner', outcomeType: 'CATEGORICAL',// autoCreate: true, resolverFn: 'winner', priority: 1 }OutcomeRegistry
Section titled “OutcomeRegistry”Registers game-specific outcome templates:
import { OutcomeRegistry } from '@ludus/prediction-markets';
const registry = new OutcomeRegistry();registry.register('konquista', templates);
const autoTemplates = registry.getAutoCreateTemplates('konquista');MarketFactory
Section titled “MarketFactory”Creates prediction markets from game outcome templates:
import { MarketFactory } from '@ludus/prediction-markets';import type { AgentInfo } from '@ludus/prediction-markets';
const factory = new MarketFactory(outcomeRegistry, { vigBps: 300, // 3% vig claimDeadlineMs: 30 * 24 * 60 * 60 * 1000, // 30 days defaultLiquidityParam: 100, maxLiquidityParam: 500,});
const players: AgentInfo[] = [ { agentId: 'agent-1', name: 'Caesar' }, { agentId: 'agent-2', name: 'Hannibal' },];
// Create all auto-create markets for a gameconst markets = factory.createMarketsForGame('game-123', 'konquista', players);
// Create a single market from a specific templateconst market = factory.createMarket('game-123', 'konquista', template, players);MarketService
Section titled “MarketService”Orchestrates trading, state transitions, and position tracking:
import { MarketService, InMemoryMarketStore } from '@ludus/prediction-markets';import type { MarketStore, TradeResult } from '@ludus/prediction-markets';
const service = new MarketService(new InMemoryMarketStore());
// Save and query marketsawait service.saveMarket(market);const m = await service.getMarket('market-id');const gameMarkets = await service.getMarketsForGame('game-123');
// Open a market for tradingawait service.openMarket('market-id', lockTimeMs);
// Buy shares (with slippage protection)const trade: TradeResult = await service.buy('market-id', 'user-1', 0, 10, 5.0);// { marketId, userId, outcomeIndex, amount, cost, newShares, newPrices }
// Sell shares (with slippage protection)await service.sell('market-id', 'user-1', 0, 5, 1.0);
// Get current pricesconst prices = await service.getPrices('market-id'); // [0.45, 0.32, 0.23]
// Position queriesconst shares = service.getPositionShares('user-1', 'market-id', 0);const positions = service.getUserMarketPositions('user-1', 'market-id');Market State Machine
Section titled “Market State Machine”CREATED → OPEN → LOCKED → RESOLVED → SETTLED ↓ ↓ VOIDED DISPUTEDimport { MarketStateMachine } from '@ludus/prediction-markets';import type { Market, MarketState, MarketConfig } from '@ludus/prediction-markets';import { DEFAULT_MARKET_CONFIG } from '@ludus/prediction-markets';GameOracle
Section titled “GameOracle”Bridges the Game Engine to market resolution. Implements EventSink from @ludus/game-engine:
import { GameOracle, ValidationService, OutcomeMapper, OracleEventEmitter } from '@ludus/prediction-markets';import type { OracleConfig, ValidationResult, MarketResolution, ResolutionResult } from '@ludus/prediction-markets';import { DEFAULT_ORACLE_CONFIG } from '@ludus/prediction-markets';
const oracle = new GameOracle( { autoLockOnGameStart: true, autoResolve: true, requireValidation: true }, marketService, outcomeResolver, outcomeRegistry, validationService, outcomeMapper,);
// Plug into the game event systememitter.addSink(oracle);
// Manual APIawait oracle.lockMarketsForGame('game-123');const result: ResolutionResult = await oracle.resolveGame('game-123', gameResult);await oracle.voidGameMarkets('game-123', 'Technical failure');Oracle Event Flow
Section titled “Oracle Event Flow”game_startevent received — locks all OPEN markets for that gamegame_overevent received — validates replay, resolves each market’s outcome, transitions to RESOLVED
Oracle Events
Section titled “Oracle Events”Subscribe to oracle lifecycle events:
import { OracleEventEmitter } from '@ludus/prediction-markets';import type { OracleEvent, OracleEventType, OracleEventHandler } from '@ludus/prediction-markets';
// Event types: 'markets_locked' | 'validation_started' | 'validation_complete'// | 'resolution_started' | 'resolution_complete' | 'resolution_failed' | 'markets_voided'OutcomeResolver
Section titled “OutcomeResolver”Maps game results to market outcomes using game-specific adapters:
import { OutcomeResolver } from '@ludus/prediction-markets';import type { ResolverFunction, GameResolverAdapter } from '@ludus/prediction-markets';Settlement
Section titled “Settlement”PayoutCalculator
Section titled “PayoutCalculator”Calculates payouts after market resolution:
import { PayoutCalculator } from '@ludus/prediction-markets';import type { PayoutResult } from '@ludus/prediction-markets';ClaimManager
Section titled “ClaimManager”Handles user claims with deadline enforcement:
import { ClaimManager, InMemoryClaimStore } from '@ludus/prediction-markets';import type { ClaimStore, ClaimStatus, Claim } from '@ludus/prediction-markets';Positions
Section titled “Positions”PositionManager
Section titled “PositionManager”Tracks user positions across markets:
import { PositionManager } from '@ludus/prediction-markets';import type { UserPosition, PositionSummary } from '@ludus/prediction-markets';PositionValuation
Section titled “PositionValuation”Real-time position valuation based on current market prices:
import { PositionValuation } from '@ludus/prediction-markets';import type { MarketValuation } from '@ludus/prediction-markets';Compliance
Section titled “Compliance”GeoFenceService
Section titled “GeoFenceService”Jurisdictional access control:
import { GeoFenceService, JurisdictionRegistry, StubGeoIPResolver } from '@ludus/prediction-markets';import type { GeoFenceConfig, GeoFenceResult, GeoIPResolver, JurisdictionCode } from '@ludus/prediction-markets';import { DEFAULT_GEOFENCE_CONFIG } from '@ludus/prediction-markets';ConflictOfInterestGuard
Section titled “ConflictOfInterestGuard”Prevents agents from betting on their own games:
import { ConflictOfInterestGuard, StubAgentOwnershipResolver, StubGameParticipantResolver } from '@ludus/prediction-markets';import type { ConflictCheckResult, AgentOwnershipResolver, GameParticipantResolver } from '@ludus/prediction-markets';ComplianceMiddleware
Section titled “ComplianceMiddleware”Combines geo-fencing and conflict-of-interest checks:
import { ComplianceMiddleware } from '@ludus/prediction-markets';import type { TradeContext, ComplianceConfig } from '@ludus/prediction-markets';import { DEFAULT_COMPLIANCE_CONFIG } from '@ludus/prediction-markets';Error Types
Section titled “Error Types”| Error | When |
|---|---|
InvalidOutcomeError | Outcome index out of range |
InvalidShareAmountError | Share amount is zero or negative |
InsufficientSharesError | Selling more shares than held |
SlippageExceededError | Actual cost exceeds maxCost or refund below minRefund |
InvalidStateTransitionError | Invalid market state transition |
MarketNotFoundError | Market ID not in store |
MarketNotOpenError | Attempting to trade on a non-open market |
MarketNotResolvedError | Attempting to settle a non-resolved market |
MarketAlreadyResolvedError | Market already resolved |
ClaimDeadlineExpiredError | Claim window has closed |
AlreadyClaimedError | User already claimed payout |
NoWinningPositionError | User has no winning position |
UnknownGameTypeError | Game type not in outcome registry |
UnknownTemplateError | Template not found for game type |
NoMarketsForGameError | No markets exist for the game |
OutcomeMappingError | Could not map resolved outcome to market index |
OracleResolutionError | Oracle resolution failed |
ValidationFailedError | Replay validation failed |
ValidationTimeoutError | Validation took too long |
GeoFenceBlockedError | Jurisdiction blocked |
ConflictOfInterestError | Agent betting on own game |