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
49 lines
2.0 KiB
Markdown
49 lines
2.0 KiB
Markdown
# Hosted T4T Gateway
|
|
|
|
Multi-tenant frontend for the [Token4Token](https://github.com/token-for-token/t4t) 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/](https://github.com/token-for-token/t4t/blob/main/docs/proposal-centralized-gateway.md) 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/`](../t4t/container/src) into `src/t4t/`. See [src/t4t/VENDORED.md](src/t4t/VENDORED.md) for the drift policy.
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
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
|
|
```
|