Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitBond

Backend for GitBond — treasury, stablecoin and tokenized-asset operations driven from GitHub workflows. Serverless Python functions on Vercel, Postgres (Supabase) for state, wallet signature for auth.

This repository holds the backend and the wallet sign-in script. The marketing site is deployed separately.


What is actually here

Area State
45 HTTP endpoints implemented, unit-tested against a mocked database
Postgres schema — 34 tables, 23 views 13 migrations + seed
Double-entry ledger enforced by triggers, not by application code
Wallet sign-in (EIP-4361) implemented, secp256k1 recovery written from scratch, no dependencies
Group chat + SSE stream implemented, windowed to fit the function time limit
Autobranch code generation not functional — see Limitations
On-chain execution not implemented by design — see Limitations

Tests: tests/ — five suites, all green. They run against an in-memory double of PostgREST that also enforces the database triggers, so a balance rule broken in SQL fails the Python test.


Design notes

Balances are derived, never stored. There is no balance column on a vault, an account or a project. A balance is the sum of confirmed entries in the ledger. Money moves only by inserting a transaction header, then entries that sum to zero per asset, then flipping the header to confirmed. Four triggers guard this: entries are append-only, nothing can be added to a confirmed transaction, an unbalanced transaction fails at COMMIT, and no internal account may go negative. Only one synthetic account — the one modelling the outside world — is allowed a negative balance, so that a deposit from outside still nets to zero.

These are triggers and CHECK constraints rather than row-level security, because RLS is bypassed by the service key while triggers are not. Even with full database access, the only way to change a balance is to write a balanced, immutable transaction that stays in the history.

Idempotency. Endpoints that move money accept a request twice without moving it twice. Where the client sends an operation token, the guarantee is permanent — a repeat returns the original transaction hash. Where it does not, a content key over the parameters plus a unique index catches both retries and races. A partially applied transaction resumes rather than restarts.

Server-Sent Events on serverless. A function cannot hold a connection open indefinitely, so /api/group/stream serves a bounded window and closes itself before the platform would cut it mid-frame. Clients reconnect and catch up through a monotonic cursor over an outbox table, so nothing is lost across the gap.


Limitations

Stated plainly, because they are deliberate.

No blockchain. Vault operations are accounting entries. Addresses and transaction hashes are derived deterministically from the operation and stored as strings; nothing is broadcast to any network. GET /api/vault/key answers 410 Gone — no key material is stored anywhere in the schema, so there is nothing for it to return.

Autobranch cannot write to GitHub. POST /api/autogit/push and /deploy answer 501. They would need a GitHub App with write access, which this deployment does not have. They return an error rather than a plausible-looking repository URL.

No model behind the assistant. /api/autogit/chat and /improve say so instead of pretending to have edited files.

Statistics carry over. /api/stats includes counters from an earlier deployment whose history does not exist in this database. They live in a single stats_carryover row rather than being faked as individual records, and every other number is computed from real rows.


Running it

Requires a Supabase project and a Vercel deployment.

# 1. apply the schema
psql "$DATABASE_URL" -f db/migrations/001_foundation.sql   # ... through 013
psql "$DATABASE_URL" -f db/seed.sql

# 2. environment variables on Vercel
SUPABASE_URL          # Supabase → Settings → Data API
SUPABASE_SERVICE_KEY  # Supabase → Settings → API keys → service_role
SESSION_SECRET        # python3 -c "import secrets; print(secrets.token_urlsafe(48))"
GROUP_ADMIN_SECRET    # any long random string
SIWE_DOMAIN           # the domain the site is served from

# 3. tests
python3 tests/test_auth.py
python3 tests/test_vault.py
python3 tests/test_group.py
python3 tests/test_public_api.py
python3 tests/smoke_test.py

Every missing variable produces a 503 naming the variable, never a silent failure.

requirements.txt is intentionally empty — the shared library is standard-library only, so a broken dependency cannot take down every function at once.


Layout

api/
  _lib/           shared helpers — responses, errors, auth, Supabase client, address derivation
  auth/           EIP-4361 sign-in: nonce, verify, me, logout
  vault/          treasury operations, all of them ledger writes
  group/          chat, moderation, SSE stream
  autogit/        Autobranch endpoints
  ...             stats, tokens, prices, transactions, projects, repos, rwa
db/
  migrations/     13 files, ordered
  seed.sql        reference data
  SCHEMA.md       diagram, table notes, endpoint-to-table map
docs/
  API_SPEC.md     recovered contract for all 54 endpoints the frontend calls
tests/            five suites
web/
  gitbond-wallet.js   wallet sign-in for the static frontend

License

MIT

About

Backend for GitBond — treasury and tokenized-asset operations driven from GitHub workflows. Serverless Python, Postgres, wallet sign-in.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages