Inspiration

Prediction markets like Polymarket surface collective intelligence more accurately than polls or pundits, but no equivalent exists for Singapore-specific events. We built HEAP to bring a production-grade, blockchain-settled prediction market to the Singapore context.

What it does

HEAP is a limit-order prediction market platform where users connect a MetaMask wallet, deposit USDC on Polygon Amoy testnet, and trade YES/NO shares on event outcomes. Five independent TypeScript microservices handle authentication (sessions via Redis, MetaMask ECDSA wallet linking), order management (collateral reservation, idempotent order creation), CLOB trade matching (price-time priority against a Redis order book), market data (live prices, order book depth, positions), and trade settlement (balance updates, on-chain payouts, UMA oracle resolution). A scheduler service runs four EventBridge-backed jobs: market expiry every minute, oracle result checks every five minutes, blockchain transaction confirmation every minute, and ledger reconciliation every fifteen minutes.

How we built it

  • Runtime: Node.js + TypeScript across all services, each independently runnable
  • Storage: MongoDB for durable state (orders, trades, balances, positions, outbox events), Redis for hot order book (sorted sets for bid/ask price levels), session store, and distributed locks
  • Async pipeline: SQS FIFO queue (matching-order-queue.fifo) for serialised order mutations per market-outcome pair; trade-settlement-queue for downstream settlement; blockchain-transaction-queue for on-chain writes, all simulated locally via LocalStack
  • Reliability: Transactional outbox pattern: services write events to MongoDB outbox-events collection inside atomic multi-document transactions; a publisher loop reads and forwards to SQS with retry
  • Blockchain: Polygon Amoy testnet (chain ID 80002), smart contracts in /contracts, Alchemy as RPC provider, UMA oracle for market resolution
  • Infrastructure: Docker dev containers for reproducible local environments, LocalStack for AWS service simulation

Challenges we ran into

  • Atomic multi-collection writes: Coordinating balance deduction, order creation, ledger entry, and outbox event publish inside a single MongoDB transaction without partial state was the hardest constraint to get right
  • FIFO ordering: The matching engine must process orders for the same market-outcome strictly in sequence, solved with SQS FIFO messageGroupId keyed to marketid:outcome Idempotency everywhere: Every mutating operation carries an idempotency key stored in Redis (TTL 24h–7d) to handle SQS redeliveries safely without double-spending or duplicate trades
  • LocalStack parity: Replicating EventBridge scheduler behaviour and SQS FIFO semantics locally with LocalStack required careful queue provisioning in the scheduler bootstrap

What we learned

  • How distributed systems handle consistency without two-phase commit: the outbox pattern is the practical answer
  • Order book mechanics: bid/ask sorted sets, price-time priority, partial fill accounting, maker/taker distinction
  • Why FIFO queues with message group IDs matter when multiple services mutate shared state concurrently
  • Blockchain integration complexity: RPC providers, transaction lifecycle (pending → broadcasted → confirmed → failed), and oracle dispute windows

What's next for HEAP Polymarket

  • Deploy to AWS ECS (ap-southeast-1) with Application Load Balancer routing, behind CloudFront and WAF as designed
  • Migrate from Polygon Amoy testnet to Polygon mainnet with real USDC
  • Add frontend UI to the existing /ui service beyond the current dev scaffold
  • Expand market categories beyond the seeded set to cover Singapore-specific events (elections, NDR, sports)
  • Implement the Lambda reconciliation jobs for order book, balance, and blockchain drift detection

Built With

Share this project:

Updates

Submission history