HashX

⏳ HashX: A permissionless Optimistic Oracle on Hedera built using Timelocked puzzles.

HashX

Created At

ETHOnline 2025

Project Description

HashX is an app for creating and resolving prediction markets with accuracy with the help of privacy-preserving voting on Hedera EVM. Votes are encrypted using BabyJubJub-based ECDH and AES-256-CTR, then revealed via a timelock puzzle or automatically by a server-held key. Rewards are distributed using Merkle proofs.

Features

  • Verifier Secret Key is generated upon Oracle Creation, Public Parameters for solving the SK is published Onchain (RSA modulus $N$, base $a$, iterations $t$)
  • Encrypted voting with EIP‑712 typed signatures → ephemeral keys → AES-encrypted ballot
  • Votes are calculated per user basis, Rewards are calculated as per amount staked.
  • Voters can not prove what they have voted until the vote is resolved.
  • Hedera EVM integration (Testnet) with RainbowKit.
  • HBAR staking via HBARLockingContract to obtain voting power. This converts HBAR to WHBAR utilizing WHBAR.sol contract.
  • Solver gets certain percentage (default $5%$) of the Oracle value.
  • Oracle rewards among voters are distributed via Merkle proofs.
  • Postgres DB for fetching markets metadata and serving proofs.

Contracts (addresses on Hedera Testnet)

  • HBAR_LOCKING_CONTRACT_ADDRESS: 0xde368C3DCac4E5096f2D2b8AF7Be70277c43b144
  • CREATEVOTE_FACTORY_ADDRESS: 0x90Fe5e610A12D2Aa0374e5CEA373bc4CdC103Cbc
  • PREDICT_MARKET_FACTORY_ADDRESS: 0x0118250132B55af4Ca1659dA51Bf7430245C1A03
  • ABIs: see ABI/
  • Factory contracts are verified on Hashscan.

Tech stack

  • App: Next.js (app router), React 19, Tailwind, Zustand, TanStack Query
  • Web3: wagmi v2, viem, RainbowKit, SIWE
  • Crypto: @zk-kit/baby-jubjub, AES-256-CTR, bigint-mod-arith
  • DB: Postgres (Neon)

Using the app

  1. Connect wallet. The UI will prompt to add/switch to Hedera Testnet if needed.
  2. Stake HBAR (Stake tab) to gain voting power.
  3. Create Oracle (Start Creating):
    • Set rewards, start/end time, and choose resolution mode (auto vs manual puzzle).
    • The app records marketId and oracle contractAddress.
  4. Create Market: Provide initial liquidity and parameters, then submit.
  5. Vote: Pick option, Generate Signature, then Submit Vote.
  6. Resolve: After end, click Verify Result (runs decrypt + finalize) and then Claim Rewards.

How it's Made

  • • Tech stack

    • App: Next.js (App Router) 16, React 19 (React Compiler), Tailwind v4, Radix UI, Lucide, Sonner, Next Themes, TanStack Query, Zustand.
    • Wallet/Web3: wagmi v2, viem, RainbowKit (SSR), SIWE.
    • Crypto: @zk-kit/baby-jubjub (ECDH), AES‑256‑CTR, bigint-mod-arith.
    • Contracts: Solidity (OpenZeppelin), Hedera EVM (Testnet).
    • Data/Infra: Postgres (Neon serverless), Drizzle ORM, Hedera Mirror Node API.
    • Build: Turbopack, TypeScript, ESLint 9.
  • • High-level architecture

    • Smart contracts:
      • HBARLockingContract stakes HBAR and wraps to WHBAR, tracks deposits, transfers stake to protocol and back for rewards.
      • CreateVote oracle: stores public parameters for the timelock puzzle, accepts encrypted votes (userPublicKey, bytes option, amount), verifies solver secret, finalizes with a Merkle root, and enables claimRewards.
      • PredictionMarket + PredictionMarketToken: AMM-like market with YES/NO tokens, initial liquidity, probability-based pricing, and settlement driven by the CreateVote oracle outcome. Factories deploy both oracle and market.
    • Server “actions” (Next.js server components):
      • DB via Neon + Drizzle stores oracle public params, optional server-held secret, market metadata, and Merkle proofs.
      • Finalization flow decrypts votes off-chain (after end), builds Merkle trees, simulates, then sends on-chain finalizeVote with a server wallet (env PRIVATE_KEY).
    • Frontend:
      • RainbowKit + wagmi configure Hedera Testnet, SIWE auth; EIP‑712 typed message signing for vote attestations.
      • Zustand stores reflect balances, transaction hashes; TanStack Query for async data.
  • • Privacy-preserving vote encryption

    • Users generate an ephemeral BabyJubJub key by hashing their EIP‑712 vote signature + fresh randomness, mod curve order.
    • ECDH with the oracle’s BabyJubJub public key derives a shared secret; votes are encrypted with AES‑256‑CTR (constant IV is acceptable here because keys are per‑vote and unique).
    • On-chain, the vote is stored as bytes mapped to the ephemeral public key, keeping the voter’s choice hidden.
  • • Timelock puzzle (delayed reveal)

    • On oracle creation, server generates an RSA modulus N (JWK), sets base a=2 and difficulty t. Compute b = a^(2^t mod φ(N)) mod N, hash b and XOR with the secret key to publish skLocked.
    • Anyone can later recover the secret via repeated squaring (computing a^(2^t) mod N), unmask skLocked, and submit it on-chain; or in “server mode” the backend reveals SK after end.
    • Contract double-hashes the expected secret to prevent preimages and rewards the solver (~10%) via the locking contract.
  • • Finalization and distribution

    • Backend queries Mirror Node for blocks bracketing start/end timestamps; fetches VoteCast logs via viem.
    • Decrypts each vote with the recovered (or server-held) SK; tallies options; adds losing-side stake to rewards.
    • Uses @openzeppelin/merkle-tree to build Standard Merkle Trees for winners; stores proofs in Postgres.
    • Simulates finalizeVote, then sends it with winnerMerkleTreeRoot and added rewards. Users claim on-chain by submitting their Merkle proof.
  • • Partner tech and how it helped

    • Hedera EVM + Mirror Node: fast finality and easy block range lookup by timestamp for off-chain log collection.
    • Neon Postgres + Drizzle: serverless, simple schema-first DX; storing oracle params and Merkle proofs for the UI.
    • RainbowKit + wagmi + viem: reliable multi-wallet UX, typed EIP‑712 flows, and robust simulation/tx sending.
  • • Notable hacky bits

    • Ephemeral JJJ keys derived from typed signatures + randomness for unlinkable, per‑vote encryption.
    • RSA timelock via repeated squaring implemented in both server action and CLI scripts (src/scripts/solve_puzzle.ts), with XOR masking of SK.
    • Using Mirror Node timestamps → block numbers to bound event fetching precisely.
    • Hard-coded on-chain operator for oracle admin actions in CreateVote to simplify hackathon operations.
    • AES‑CTR with a fixed IV is safe here due to per‑vote one‑time keys; simpler than managing nonces while preserving privacy.
background image mobile

Join the mailing list

Get the latest news and updates