Docs

Self-Hosting

The full BlindMarkets stack — gateway, coordinator, observer, and reference solver — can run on any machine with Docker. This page walks through deploying it yourself, pointed at the contracts already on Sepolia.


What you're running

gateway

Rust API server. Accepts intents, manages the database, relays to solvers.

coordinator

Rust scheduler. Opens and closes batch windows on-chain every 30 seconds.

observer

Rust indexer. Watches Starknet for settlement events and updates the database.

postgres

Database for intents, batches, and audit history.

redis

Rate limit counters and nonce windows. Lost on restart — no persistent state.

The frontend is a separate Next.js app deployed on Vercel. It talks to the gateway over HTTP — you only need to point it at your gateway URL.


Prerequisites

  • Docker and Docker Compose installed
  • A funded Starknet Sepolia account (for the coordinator and gateway to send transactions)
  • The repo cloned locally

1. Clone and configure

bash
git clone https://github.com/winsznx/blindmarkets
cd blindmarkets
cp .env.compose.example .env

Open .env and fill in:

  • GATEWAY_API_KEY — any random string, e.g. openssl rand -hex 32
  • GATEWAY_ACCOUNT_ADDRESS and GATEWAY_ACCOUNT_PRIVATE_KEY — your Starknet account
  • COORDINATOR_ACCOUNT_ADDRESS and COORDINATOR_PRIVATE_KEY — your Starknet account (can be the same for testnet)

Everything else — contract addresses, RPC URL, event keys — is already filled in with the Sepolia deployment values.

Keep your private key out of git

The .env file is in .gitignore by default. Never commit it. Use openssl rand -hex 32 to generate a strong API key.

2. Register your gateway

The gateway account must be registered in the GatewayRegistry contract before it can relay intents. Run this once:

bash
sncast --account your_account invoke \
  --network sepolia \
  --contract-address 0x0572569d692b6711f7da40d9d196bccf56b703cf8dafe03580aa713e974557b0 \
  --function register_gateway \
  --calldata YOUR_GATEWAY_ADDRESS YOUR_GATEWAY_PUBLIC_KEY

To get your public key: sncast account list — look for the public key field next to your account.


3. Start the stack

bash
docker compose up --build

First build takes a few minutes — Rust compiles from source. After that, rebuilds are much faster because Docker caches the dependency layer.

Services come up in order: postgres and redis first, then gateway, then coordinator and observer once the gateway is healthy.

Local URLs

Gateway APIhttp://localhost:3000
Health checkhttp://localhost:3000/health
PostgreSQLlocalhost:5432
Redislocalhost:6379

4. Point the frontend at your gateway

In your Vercel project settings (or your local frontend/.env.local), set:

.env.local
GATEWAY_URL=http://localhost:3000       # or your public URL
GATEWAY_API_KEY=your-api-key
GATEWAY_API_KEY_HEADER=X-API-KEY

Deploying on Railway

The easiest way to run the backend publicly is Railway. Create a project, add PostgreSQL and Redis plugins, then add three services from the same GitHub repo:

ServiceRAILWAY_DOCKERFILE_PATH
gatewaybackend/gateway/Dockerfile
coordinatorbackend/coordinator/Dockerfile
observerbackend/observer/Dockerfile

Set env vars from your .env in each service's Variables tab. For coordinator and observer, replace GATEWAY_URL with http://gateway.railway.internal:3000.

Replace DATABASE_URL and REDIS_URL with Railway's reference syntax: ${{Postgres.DATABASE_URL}} and ${{Redis.REDIS_URL}}.

Internal networking saves egress costs

Using gateway.railway.internal:3000 instead of the public URL routes traffic internally within Railway. This avoids egress charges and is faster.

Running a solver

The reference solver in solver-reference/ demonstrates the full solver loop: polling the gateway for open batches, computing a solution, and submitting it on-chain. To run it:

bash
# Add to docker-compose.yml services or run directly:
SOLVER_ACCOUNT_ADDRESS=0x... \
SOLVER_ACCOUNT_PRIVATE_KEY=0x... \
GATEWAY_URL=http://localhost:3000 \
GATEWAY_API_KEY=your-key \
cargo run --release -p blindmarkets-solver

Bond required before a solver can submit

A solver must have a bond deposited in the SolverBond contract before it can submit solutions. The minimum bond is 1 STRK. See the SolverBond contract on Voyager to deposit.