Katama·Docs
StatsWorkspace ↗

On-chain architecture

The system splits responsibilities between the VPS and Vercel so the treasury private key never leaves trusted infrastructure.

Component diagram

┌──────────────────┐   GET /api/blockchain/pending-batches    ┌──────────────┐
│ Vercel (Next.js) │ ────────────────────────────────────────▶│ VPS cron     │
│                  │                                          │ (signs txs)  │
│  /stats          │  ◀──────────── POST /mark-batched ───────│              │
│  /blockchain     │                                          └──────────────┘
│  HistoryTable    │                                                  │
│                  │                                                  ▼
└──────────────────┘                                          Base mainnet
        ▲                                                  KatamaCredits.sol
        │
        │  read blockchain_logs
        ▼
┌──────────────────┐
│ Postgres (VPS)   │
│ blockchain_logs  │
│ blockchain_stats │
└──────────────────┘

Daily flow

  1. 00:00 UTC — VPS cron fires node /root/projects/katama-blockchain/daily-batch.js.
  2. Script calls GET /api/blockchain/pending-batches?date=YYYY-MM-DD with the CRON_SECRET bearer token. Vercel aggregates yesterday's generations per user and writes blockchain_logs rows withstatus='pending'.
  3. For each pending row, the script claims it (POST /pending-batches flips it to broadcasting) and signs logUserDaily(...) on the contract.
  4. On confirmation, the script reports the TX hash back via POST /mark-batched. Vercel updates the row to confirmed and rolls up blockchain_platform_stats.
  5. Failed broadcasts retry up to 3× with backoff. After that, the row stays in failed with the error string for diagnosis.

Why this split

Treasury key on VPS only

The signing wallet's private key lives in /root/.katama-treasury.key with mode 600. It is never copied to Vercel, never logged, never echoed to stdout. Compromising Vercel leaks user data but not signing capability.

DB on VPS, Vercel reads remotely

Postgres runs locally on the VPS. The Vercel app connects to the VPS via the public IP on port 5432. The VPS-side signer connects to the same DB over localhost, so it sees the same data without an extra network hop.

CRON_SECRET as the only API trust boundary

The three blockchain endpoints — /api/blockchain/pending-batches, /api/blockchain/mark-batched, and /api/admin/migrate — all require a Bearer token equal to CRON_SECRET. No user session can reach them.

Idempotency

  • blockchain_logs has a unique index on (user_id, date). Re-running pending-batches the same day inserts nothing new; it returns the same pending rows.
  • KatamaCredits.sol stores batchKeyUsed[keccak256(userIdHash, date)] and reverts on duplicate calls. Even if the script somehow broadcasts the same batch twice, only one succeeds on-chain.
  • A confirmed row will not be re-rolled into blockchain_platform_stats because mark-batched short-circuits when the same logId+txHash arrives twice.

Files

PathRole
/root/projects/katama-blockchain/contracts/KatamaCredits.solSmart contract source
/root/projects/katama-blockchain/build/KatamaCredits.abi.jsonCompiled ABI
/root/projects/katama-blockchain/deploy.jsOne-shot Base deployment
/root/projects/katama-blockchain/daily-batch.jsCron entrypoint
web/src/lib/blockchain/index.tsShared helpers (hash, dates, links)
web/src/app/api/blockchain/*3 Vercel endpoints

Next: Smart contract →