Developers

Run a crank

Checkpoints and settlement are permissionless. How to run the service that sends them.

Everything that keeps a market moving is permissionless: publishing checkpoints, settling positions, liquidating, and closing a frozen market. Tack runs a crank for every market it lists. Anyone can run another, and nothing it sends can move a trader's money anywhere the program would not.

What the crank does

Each cycle, against finalized state:

  1. Opens each maturity Tack's listing calls for that is not open yet, with list_market.
  2. Reads Phoenix's SOL slot and each market Tack lists.
  3. For each of them that is one interval behind Phoenix, publishes the next checkpoint. Every market's record goes out before any settlement.
  4. For each open position behind its market, sends settle with the next checkpoints, up to eight at a time, and repeats until it is caught up or closes. A market or position whose transaction fails is logged and skipped; the rest carry on.
  5. Records every transaction it signs before sending it, so an ambiguous RPC response can be reconciled against the chain later.

The crank never invents history. If Phoenix has moved on by more than one interval, it logs the gap and leaves the market for frozen finalization after the grace.

Costs

The crank's key pays Solana fees, the rent for each checkpoint account, about one checkpoint an hour per open market, and the rent for each market it lists, one a week. It earns nothing: Tack charges no fees and pays no bounty. The key has no privilege in the program; it is only a fee payer.

Run it

The crank is part of the Tack service in backend/. It runs alongside the indexer and API when enabled:

Shell
npm ci
npm run build
npm start
Shell
# backend/.env
DATABASE_URL=postgresql://…
SOLANA_RPC_URL=https://…
SOLANA_GENESIS_HASH=5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
TACK_PROGRAM_ID=…
CRANK_ENABLED=true
CRANK_KEYPAIR_PATH=/secrets/crank.json   # or CRANK_KEYPAIR=[…], the secret key's JSON array
TACK_LISTING=…   # Tack's listing account: listing, and governance reads in the API

npm start applies database migrations and starts the indexer, the API and, with CRANK_ENABLED=true, the crank. npm run crank runs one cycle and exits.

Deploying on Railway

Set the service root to tack/backend. The build runs prisma generate; the start command runs prisma migrate deploy, because the build cannot reach the database. Set DATABASE_URL to ${{Postgres.DATABASE_URL}}, let Railway provide PORT, and keep the crank key in a sealed CRANK_KEYPAIR variable, or on a volume with CRANK_KEYPAIR_PATH pointing at it. Railway's deploy check is GET /healthz, which answers while the process runs; GET /readyz answers 200 only while the index is current, for monitoring.