Files
hosted-gateway/README.md
Claude 5b2888aade fix: reservation leak, spoofable delivery envelopes, and Decimal wei rendering
Seven bugs found by auditing the billing and PSS paths.

1. Reservations were never released on ack/delivery timeout. Both failure
   paths in gateway/context.ts marked the GatewayJob terminal *before* calling
   releaseReservation, and releaseReservation bailed out on exactly those
   statuses — so every failed job permanently inflated the tenant's
   reservedXbzzWei and shrank their available balance. Replace the status check
   with GatewayJob.reservationReleasedAt as an explicit compare-and-set marker,
   which makes the release exactly-once regardless of ordering, and give
   settleXbzz the same guard so a job that was released locally and claimed
   on-chain anyway can't decrement the reservation twice. The migration returns
   the xBZZ already stuck on existing accounts.

2. job_ack / job_deliver were only checked for a valid signature, never for
   *whose* signature. Anyone who learned a routing id could sign their own
   job_deliver, pointing at a chunk encrypted to the gateway's (published) PSS
   key, and hand the tenant an arbitrary completion. Drop any envelope whose
   `from` isn't the provider the job was posted to.

3. BigInt(decimal.toString()) throws on any wei value >= 1e21 (1000 xBZZ),
   because decimal.js switches to exponential notation there. That took out
   GET /accounts/me and, worse, wedged the claim watcher's settle loop. Route
   every Decimal→string conversion through toFixed().

4. A cancelJob failure at the ACK deadline left the job with no timer at all,
   so the chat request hung forever holding a semaphore slot and a reservation.
   Fall through to the delivery deadline instead.

5. `?limit=abc` reached Prisma as `take: NaN` (500). Clamp and fall back.

6. A fractional max_tokens made BigInt() throw; a negative one budgeted a
   negative reservation. Validate at the schema and defend in the estimator.

7. model.<entity>.delete() announced the deletion on the queue before
   performing it, so a failed delete still told consumers the row was gone.

Verified against a real Postgres: the reservation lifecycle (release-after-
terminal, settle-after-release, concurrent release/settle, idempotent settle)
and the migration's repair of leaked reservations on pre-fix data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mfkh741kNCZeBdk4xyM9qR
2026-08-07 07:28:09 +00:00

2.0 KiB

Hosted T4T Gateway

Multi-tenant frontend for the Token4Token inference network. Users sign up with Google / email, get 50 free virtual xBZZ, and call OpenAI-compatible endpoints without touching a wallet, Bee node, or Gnosis RPC.

Custody model: one operator wallet handles all on-chain transactions and Swarm operations. Tenants are off-chain ledger entries denominated in xBZZ. Providers see one on-chain client address (the operator's), not per-tenant addresses.

See docs in t4t/ for the wider design context.

Stack

  • Bun + Elysia (HTTP)
  • viem (Gnosis Chain bindings) — shared with t4t-container
  • bee-js (Swarm) — shared with t4t-container
  • Prisma + Postgres (multi-tenant ledger)
  • BullMQ + Redis (queues + distributed locks + operator-wallet nonce)

The gateway engine code (provider selection, chain I/O, PSS routing, ECIES envelope) is vendored from t4t/container/src/ into src/t4t/. See src/t4t/VENDORED.md for the drift policy.

Quick start

cp .env.example .env
# fill in OPERATOR_PRIVATE_KEY, REGISTRY/ESCROW/XBZZ addresses, JWT_SECRET_KEY

docker compose up -d postgres redis bee
bun install
bunx prisma migrate deploy
bun run dev:api
# in another shell:
bun run dev:worker

Layout

src/
  api.ts               # Elysia HTTP entry
  worker.ts            # BullMQ workers + claim watcher
  db.ts                # model.<entity> CUD wrappers (write + enqueue)
  env.ts               # zod-validated process.env
  auth/                # JWT, Google OAuth, email signup
  users/, accounts/, apiKeys/, pricing/, gateway/, chain/
  lib/                 # shared coercion helpers (Decimal → wei string, query params)
  queue/               # connection, registry, lock, processor base, service
  t4t/                 # VENDORED from t4t-container
prisma/schema.prisma
test/                  # E2E specs