A decentralized, AI-powered prediction market protocol for crypto price discovery, built on Hedera.
- What Is Torch?
- Value Proposition
- Hackathon Scope
- Architecture & Deployment
- Repo Structure & Services
- Environment Variables
- How It Works (Step-by-Step)
- Local Development
- Automatic Resolution & Oracle Runs
- Resolver Run Artifacts
- Demo Flow
- Troubleshooting
- Security Notes
- Tech Stack & Installation
- Team & Resources
Torch is a decentralized prediction system for high-resolution, real-time crypto price forecasting.
Unlike conventional markets focused on binary outcomes (e.g. Polymarket), Torch allows users to predict price ranges across future timepoints, creating a dynamic priceβtime probability surface.
Torch blends AI agents and human traders in an InfoFi-aligned ecosystem, rewarding early, sharp, and high-conviction predictions.
| Problem | Torch's Solution |
|---|---|
| Crypto traders lack continuous, high-resolution price forecasts | Torch builds a real-time priceβtime signal |
| Existing markets are binary or categorical | Torch enables continuous predictions on a full probability surface |
| Fragmented market signals and incentives | Torch aligns humans and AI agents via economic incentives |
- β Core smart contracts for prediction lifecycle and payout logic
- β Graph subgraph indexing for event querying
- β Wallet-authenticated frontend
- β Realistic price resolution and reward distribution
Specs: Functional & Contract Β· Design & Frontend
Deployment is split between Vercel (UI and server-side proxy) and Hetzner (execution, signing, and artifact persistence). The resolver and its private key never run on Vercel.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USERS / BROWSER β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β GraphQL (/api/subgraph) β REST (oracle runs, health)
βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
β frontend (Vercel) β β dashboard (optional, Vercel/same host) β
β Prediction UI, β β Overview, Runs, Resolver runs, Account β
β My Bets, Oracle β β Proxies to torch-api when configured β
βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
β β Bearer token
β NEXT_PUBLIC_SUBGRAPH_URL βΌ
βΌ βββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββ β torch-api (Hetzner, port 3001) β
β Subgraph (GraphQL) β β Read-only API over JSON files β
βββββββββββββββββββββββ β GET /api/health, resolver/runs β
βββββββββββββββββββββββββββββββββββ
β
BETTING_RUNS_DIR, β reads from disk
RESOLVER_RUNS_DIR βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HETZNER β
β /var/lib/torch/resolver-runs (or /opt/.../runs) β RESOLVE-*.json β
β /var/lib/torch/resolver-state/state.json β resolver state β
β Bet bot runs: torch-agent-kit-bot/runs/YYYY-MM-DD.json β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β² β²
β placeBet() β setPricesForTimestamps, processBatch
βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββ
β torch-agent-kit-botβ β torch-oracle-resolver β
β (systemd timer) β β (systemd timer, e.g. every 15m) β
βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββ
Hedera network Β· TorchPredictionMarket contract
Summary
- Vercel: Frontend and (optionally) dashboard. Oracle routes proxy to Hetzner
torch-api; no resolver execution, no resolver private key, no reading resolver artifacts from disk. - Hetzner:
torch-api(read-only HTTP API),torch-oracle-resolver(on-chain writes, state and run artifacts),torch-agent-kit-bot(daily bets vianpm run daily:agentkitat 12:00 UTC; horizon viaDAYS_AHEAD; executes viaTORCH_PLACE_BET_TOOLfromtorch-plugin). systemd timers drive resolver and bot; torch-api reads artifacts from configured dirs (e.g./var/lib/torch/resolver-runs, resolver state at/var/lib/torch/resolver-state/state.json).
TorchOriginsHackathon/
βββ frontend/ # Next.js app (Vercel): prediction UI, my-bets, oracle page
βββ smartContracts/ # Hedera Solidity contracts
βββ torch-subgraph/ # Graph subgraph for contract events
βββ torch-api/ # Read-only API (Hetzner): serves run artifacts
βββ torch-oracle-resolver/ # Resolver (Hetzner only): price check + setPrices + processBatch
βββ torch-agent-kit-bot/ # Daily bet agent (Hetzner) + optional dashboard
βββ ops/ # systemd units, Hetzner layout notes
βββ docs/ # TORCH-SYSTEM-SUMMARY, torch-ops runbooks
βββ README.md
βββ LICENSE
| Service | Role |
|---|---|
| frontend | Prediction UI, wallet connect, subgraph proxy, Oracle page (proxies to torch-api for run data). |
| torch-api | Read-only REST API on Hetzner; serves betting and resolver run artifacts; auth via Bearer token. |
| torch-oracle-resolver | Runs only on Hetzner; fetches unresolved bets, checks prices (CoinGecko + oracle), calls setPricesForTimestamps and processBatch; writes RESOLVE-*.json and state.json. |
| torch-agent-kit-bot | Daily job on Hetzner; LangChain createAgent forecasts (OpenAI) and calls TORCH_PLACE_BET_TOOL from torch-plugin to execute (or parse-only) placeBet(...); writes runs/YYYY-MM-DD.json. Optional dashboard in torch-agent-kit-bot/dashboard shows runs and proxies to torch-api. |
Copy the relevant .env.example in each app and set values. Never commit real secrets.
| Service | Key vars | Notes |
|---|---|---|
| frontend | NEXT_PUBLIC_SUBGRAPH_URL, NEXT_PUBLIC_CONTRACT_ID, TORCH_API_BASE, DASHBOARD_API_TOKEN |
TORCH_API_BASE and DASHBOARD_API_TOKEN are server-only; Oracle page proxies to Hetzner torch-api. |
| torch-api | PORT, DASHBOARD_API_TOKEN, BETTING_RUNS_DIR, RESOLVER_RUNS_DIR |
Reads artifacts from disk; token required for dashboard/frontend proxy. |
| torch-oracle-resolver | NETWORK, ADMIN_ACCOUNT_ID, ADMIN_PRIVATE_KEY, TORCH_CONTRACT_ID, SUBGRAPH_URL, RESOLVER_RUNS_DIR, RESOLVER_STATE_PATH |
Resolver runs only on Hetzner; in production set RESOLVER_RUNS_DIR=/var/lib/torch/resolver-runs, RESOLVER_STATE_PATH=/var/lib/torch/resolver-state/state.json. |
| torch-agent-kit-bot | ACCOUNT_ID, PRIVATE_KEY, NETWORK, TORCH_CONTRACT_ID, OPENAI_API_KEY, MIN_TARGET_LEAD_SECONDS, DAYS_AHEAD, DRY_RUN, STAKE_HBAR, GAS_LIMIT |
Writes betting run artifacts to ./runs on Hetzner; horizon controlled by DAYS_AHEAD (set DAYS_AHEAD=7 for the next 7 eligible days). |
| dashboard (in bot repo) | TORCH_API_BASE, DASHBOARD_API_TOKEN, BOT_ACCOUNT_ID, BOT_NETWORK |
Proxies to torch-api; does not run resolver. |
See each appβs .env.example for full, commented lists.
- Place bets β Users (or the bot) call
placeBet(targetTimestamp, priceMin, priceMax)with HBAR. - Weighting β Contract weights bets by precision (sharpness).
- Oracle resolves price β Resolver calls
setPricesForTimestamps(timestamps, prices)with the reference price (e.g. CoinGecko + oracle check). - Process results β Resolver calls
processBatch(bucketIndex)until buckets are aggregation-complete. - Winnings β Users claim via contract; payouts follow contract logic.
git clone https://github.com/denchik37/TorchOriginsHackathon
cd TorchOriginsHackathonInstall and run per service:
# Frontend
cd frontend && cp .env.example .env && npm install && npm run dev
# torch-api (needs BETTING_RUNS_DIR and RESOLVER_RUNS_DIR pointing to existing dirs)
cd torch-api && cp .env.example .env && npm install && npm run dev
# Resolver (local: uses ./runs and ./state.json if RESOLVER_RUNS_DIR/RESOLVER_STATE_PATH unset)
cd torch-oracle-resolver && cp .env.example .env && npm install && npm run resolve:once
# Bet bot (production runner uses Agent Kit tooling)
cd torch-agent-kit-bot && cp .env.example .env && npm install && npm run daily:agentkitFrontend Oracle page shows resolver run data only when TORCH_API_BASE and DASHBOARD_API_TOKEN are set and torch-api is reachable; otherwise it returns an empty list and a message.
- Resolver: Triggered by systemd timer on Hetzner (e.g. every 15 minutes). Optional manual trigger must be a Hetzner-side endpoint (e.g. protected by
RESOLVER_TRIGGER_SECRET); the frontendPOST /api/oracle/triggerreturns 501 and does not run the resolver. - Artifacts: Resolver writes
RESOLVE-<runId>.jsonunderRESOLVER_RUNS_DIRand state toRESOLVER_STATE_PATH. torch-api reads these dirs and exposesGET /api/resolver/runsandGET /api/resolver/runs/:id. - Frontend/dashboard: Call their own
/api/oracle/runs(or equivalent), which proxy to torch-api with the Bearer token; they never read the filesystem or run the resolver.
Each resolver run produces a JSON artifact (e.g. in torch-api responses and on disk). Useful fields:
| Field | Meaning |
|---|---|
| acceptedCount | Number of timestamps that passed price check and were submitted (setPrices). |
| blockedCount | Timestamps blocked (e.g. oracle divergence > MAX_PRICE_DIVERGENCE_PCT). |
| setPricesBatchTxIds | Hedera transaction IDs for setPricesForTimestamps batches. |
| processBatchTxIds | Per-bucket list of transaction IDs for processBatch calls. |
- Frontend: Open prediction page, connect wallet, place a bet (or show existing bets and Oracle page).
- Oracle page: Show resolver runs and run detail (data comes from torch-api via frontend proxy when
TORCH_API_BASEandDASHBOARD_API_TOKENare set). - Dashboard (optional): Open bot dashboard; show Overview (last betting run, last resolver run), Runs list, Resolver runs, Account (from Mirror).
- Backend: Emphasize resolver and bot run on Hetzner only; Vercel only serves UI and proxies to torch-api.
- Oracle page shows no runs: Ensure frontend has
TORCH_API_BASEandDASHBOARD_API_TOKENset, torch-api is running on Hetzner, andRESOLVER_RUNS_DIRpoints to where resolver writesRESOLVE-*.json. - 401 from torch-api: Check
DASHBOARD_API_TOKENmatches on torch-api and on the client (frontend/dashboard) that proxies to it. - Resolver not writing runs: Check
RESOLVER_RUNS_DIRandRESOLVER_STATE_PATH(and dir permissions); runnpm run resolve:oncelocally withDRY_RUN=trueto test. - Docs: See
docs/TORCH-SYSTEM-SUMMARY.mdanddocs/torch-ops/for runbooks and Option A layout.
- Resolver private key and execution stay on Hetzner only; never on Vercel or in the frontend.
TORCH_API_BASEandDASHBOARD_API_TOKENare server-side only; do not expose them withNEXT_PUBLIC_.- torch-api is read-only and does not return secrets; all requests require a valid Bearer token.
- Rotate
DASHBOARD_API_TOKENand any trigger secret if they might have been exposed.
Known limitations: Resolver and bot runs are scheduled on Hetzner (systemd); no in-repo Kubernetes or serverless resolver. Frontend Oracle trigger is intentionally disabled on Vercel (501); use a Hetzner-side endpoint for manual triggers.
- Contracts: Hardhat, Solidity ^0.8.0; Foundry optional.
- Chain: Hedera (Hashgraph, JSON-RPC, HashScan).
- Frontend: Next.js, React, TypeScript, GraphQL Apollo, Clerk, HashConnect.
- Agent Runner: Node.js + TypeScript, OpenAI (forecast), LangChain, Hedera Agent Kit (tool:
TORCH_PLACE_BET_TOOLfromtorch-plugin). - Indexing: Graph Protocol subgraph; Graph Node on VPS.
- Hosting: Vercel (frontend); Hetzner (torch-api, resolver, bet bot, subgraph).
cd smartContracts && npm install
cd torch-api && npm install
cd torch-oracle-resolver && npm install
cd torch-agent-kit-bot && npm install
cd torch-subgraph && npm install
cd frontend && npm install| Name | Role |
|---|---|
| Denis Igin | PM, Marketing |
| Balut Catalin-Mihai | Smart Contract Developer |
| Sebastien Guibert | Blockchain Data Integration / Architect |
| Sebastian Balaj | Frontend Developer |
| Mohammad Hatif Osmani | Frontend Developer |
| Resource | URL |
|---|---|
| Web | torch.bet |
| Litepaper | torch-1.gitbook.io/litepaper |
| Blog | Medium |
| X (Twitter) | @torchbet |