Decentralized P2P Escrow Β· Stellar Blockchain Β· MVP monorepo (monorepository)
dApp-SafeTrust is the MVP assembly monorepo β it brings together curated slices from
frontend-SafeTrustandbackend-SafeTrustinto a single runnable application. One command starts everything.
π Quick Start Β· ποΈ Architecture Β· π Structure Β· π§© Apps & Packages Β· π οΈ Development Β· π€ Contributing
SafeTrust is a decentralized platform for secure P2P transactions. It holds funds in tamper-proof blockchain escrow contracts on the Stellar network via the TrustlessWork API β no intermediaries, no hidden fees, full on-chain transparency.
The core MVP flow:
Tenant finds property β clicks PAY β connects Freighter wallet
β escrow deployed on Stellar β funds locked until agreement fulfilled
β owner receives funds on release Β· tenant recovers deposit on dispute
This repository is the integration layer that makes that flow runnable end-to-end.
dApp-SafeTrust uses a decoupled, API-first architecture. Hasura acts as the middleware β it auto-generates a GraphQL API from the database tables, eliminating hand-written REST controllers.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Stellar Blockchain β
β (TrustlessWork API) β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β HTTP (signed XDR)
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββ
β apps/api (Node.js) β
β Firebase Auth Β· Escrow Deploy Β· Webhook handlers β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β SQL
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββ
β infra/hasura (MIDDLEWARE) β
β Auto-generated GraphQL API Β· JWT validation β
β Tables: users Β· escrows Β· bid_requests Β· milestones β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β GraphQL (queries Β· mutations Β· subscriptions)
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββ
β apps/web (Next.js 14) β
β Apollo Client Β· Firebase Auth Β· Freighter Wallet β
β β
β /login β /dashboard β PAY β Escrow status live β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key principle: apps/web never talks to apps/api directly for data. All reads go through Hasura GraphQL. The API only handles write-heavy operations (auth sync, escrow deploy) that need business logic.
dApp-SafeTrust/
βββ apps/
β βββ web/ β Next.js 14 frontend (App Router)
β β βββ src/
β β β βββ app/
β β β β βββ login/ β /login page route
β β β β βββ register/ β /register page route
β β β β βββ dashboard/ β /dashboard page route
β β β βββ components/
β β β β βββ auth/ β Login.tsx Β· Register.tsx Β· wallet modals
β β β β βββ booking/ β BookingEscrowWrapper.tsx
β β β β βββ dashboard/ β EscrowsByStatus Β· EscrowTable Β· EscrowDashboard
β β β β βββ ui/ β shadcn/ui primitives (Button Β· Input Β· Cardβ¦)
β β β β βββ wallet/ β Freighter wallet connection
β β β βββ core/
β β β β βββ store/ β Zustand global auth state
β β β βββ graphql/
β β β β βββ documents/ β escrows.graphql Β· booking.graphql
β β β βββ lib/
β β β βββ apollo-client.ts β Apollo Client + authLink
β β β βββ firebase.ts β Firebase client SDK init
β β βββ codegen.ts β graphql-codegen config
β β βββ package.json β @safetrust/web
β β
β βββ api/ β Node.js + Express backend
β βββ webhook/
β β βββ prepare-escrow-contract.js β Hasura Action handler
β β βββ escrow-deploy.js β submit signed XDR to TrustlessWork
β β βββ webhooks.js β escrow status webhook receiver
β β βββ handlers/
β β βββ auth/
β β βββ auth-middleware.js β Firebase token verification
β β βββ sync-route.js β POST /api/auth/sync-user
β β βββ user-sync.js β upsert user into public.users
β βββ package.json β @safetrust/api
β
βββ infra/
β βββ hasura/ β MVP-only Hasura configuration
β βββ migrations/
β β βββ safetrust/ β safetrust tenant migrations only
β β βββ 1731908059919_create_uuid_extension/
β β βββ 1731908676359_create_users/
β β βββ 1731909024829_create_user_wallets/
β β βββ 1731909059420_create_trustless_work_escrows/
β β βββ 1731909059421_create_escrow_milestones/
β β βββ 1731909059422_create_trustless_work_webhook_events/
β β βββ 1732588166945_create_apartments/
β β βββ 1732865994413_create_bid_tables/
β β βββ <timestamp>_create_escrows_table/
β βββ metadata/
β β βββ base/ β Hasura base config (actions, cron triggers)
β β βββ tenants/
β β βββ safetrust/ β table tracking Β· permissions Β· relationships
β βββ seeds/
β βββ safetrust/
β βββ users_seed.sql
β βββ apartments_seed.sql
β βββ bid_requests_seed.sql
β
βββ packages/
β βββ types/ β shared TypeScript interfaces
β β βββ src/
β β βββ escrow.ts β EscrowStatus Β· EscrowTransaction Β· Milestone
β β βββ user.ts β User Β· UserWallet
β β βββ index.ts
β βββ graphql/ β codegen output (auto-generated, do not edit)
β βββ generated/
β βββ index.ts β typed Apollo hooks consumed by apps/web
β
βββ docker-compose.yml β starts postgres + hasura + api + web
βββ pnpm-workspace.yaml
βββ turbo.json
βββ .env.example
| Package | Description | Port |
|---|---|---|
apps/web |
Next.js 14 frontend β auth, dashboard, escrow views | 3001 |
apps/api |
Node.js backend β Firebase auth, escrow deploy, webhooks | 3000 |
infra/hasura |
Hasura GraphQL engine + PostgreSQL migrations | 8080 |
packages/types |
Shared TypeScript types consumed by both apps | β |
packages/graphql |
Generated Apollo hooks (output of codegen) | β |
| Tool | Version | Install |
|---|---|---|
| Docker + Docker Compose | latest | docs.docker.com |
| Node.js | β₯ 18 | nodejs.org |
| pnpm | β₯ 8 | npm install -g pnpm |
git clone https://github.com/safetrustcr/dApp-SafeTrust.git
cd dApp-SafeTrustcp .env.example .envOpen .env and fill in the required values:
# Firebase (get from Firebase Console β Project Settings β Service Accounts)
FIREBASE_PROJECT_ID=safetrust-890d0
FIREBASE_CLIENT_EMAIL=your-service-account@safetrust-890d0.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Firebase client-side (get from Firebase Console β Project Settings β General)
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=safetrust-890d0.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=safetrust-890d0
# TrustlessWork API (get from docs.trustlesswork.com)
TRUSTLESSWORK_API_URL=https://dev.api.trustlesswork.com
TRUSTLESSWORK_API_KEY=your-api-key
# Stellar (testnet addresses)
NEXT_PUBLIC_PLATFORM_ADDRESS=your-platform-stellar-address
NEXT_PUBLIC_USDC_ADDRESS=usdc-trustline-address-on-testnet
NEXT_PUBLIC_STELLAR_NETWORK="Test SDF Network ; September 2015"
# Hasura (keep defaults for local dev)
HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey
NEXT_PUBLIC_HASURA_GRAPHQL_URL=http://localhost:8080/v1/graphql
NEXT_PUBLIC_HASURA_WS_URL=ws://localhost:8080/v1/graphqldocker compose up -dThis starts four services in the correct order:
postgres β hasura (applies migrations + seeds) β api β web
| Service | URL | Expected |
|---|---|---|
| Frontend | http://localhost:3001 | Redirects to /login |
| Hasura Console | http://localhost:8080/console | Tables visible |
| API health | http://localhost:3000/health | { "status": "ok" } |
pnpm installpnpm devTurborepo starts apps/web and apps/api in parallel, respecting the dependency graph.
pnpm dev --filter @safetrust/web
pnpm dev --filter @safetrust/apiRequires Hasura to be running (docker compose up hasura -d):
pnpm codegen --filter @safetrust/webThis introspects the Hasura schema and writes typed Apollo hooks to packages/graphql/generated/index.ts.
pnpm buildTurborepo builds packages first (types β graphql), then apps.
pnpm testHasura automatically applies all migrations and seeds from infra/hasura/ on first start.
| Table | Purpose |
|---|---|
public.users |
Authenticated users (synced from Firebase) |
public.user_wallets |
Stellar wallet addresses per user |
public.apartments |
Property listings |
public.bid_requests |
Tenant interest / rental offers |
public.trustless_work_escrows |
Blockchain mirror β on-chain escrow state |
public.escrow_milestones |
Release schedule per escrow |
public.escrow_transactions |
SafeTrust business transaction log |
public.trustless_work_webhook_events |
Inbound events from TrustlessWork |
public.escrows |
Single-release security deposit escrows |
http://localhost:8080/console
Admin secret: myadminsecretkey
docker compose down -v # removes volumes
docker compose up -d # fresh start, migrations re-applied| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/health |
β | Service health check |
POST |
/api/auth/sync-user |
Bearer token | Sync Firebase user β public.users |
POST |
/prepare-escrow-contract |
Bearer token | Hasura Action: create escrow payload |
POST |
/api/escrow/deploy |
Bearer token | Submit signed XDR to TrustlessWork |
POST |
/webhooks/escrow_status_update |
β | Receive escrow status from TrustlessWork |
POST |
/webhooks/firebase/user-created |
HMAC | Firebase user creation webhook |
This repository is part of the Wave contributor program. Issues are batched into scoped sprints so contributors can work in parallel without blocking each other.
| Batch | Focus | Status |
|---|---|---|
| Batch 1 | apps/web/ structure β copy frontend slices, scaffold shell |
π Active |
| Batch 2 | apps/api/ slice + infra/hasura/ MVP migrations |
π Next |
| Batch 3 | Integration AβBβC β Firebase auth, GraphQL wiring, PAY button | π Planned |
Issues in Batch 1 may have unresolved imports. Replace them with:
// TODO: wire in Batch 2 β @/core/store/data
const useGlobalAuthenticationStore = () => ({ address: null });This keeps the build green while the dependent issue is in progress.
- Read the Contributing Guide
- Follow the Git Guidelines
- Include a Loom video in your PR showing before/after
- Link the issue your PR closes
| Repository | Purpose |
|---|---|
| frontend-SafeTrust | Full Next.js frontend (source for apps/web/ slices) |
| backend-SafeTrust | Full Node.js backend (source for apps/api/ slices) |
| landing-SafeTrust | Marketing landing page |
- TrustlessWork API Docs
- Hasura GraphQL Docs
- Stellar Developer Docs
- Freighter Wallet API
- Firebase Auth Docs
Built with π by the SafeTrust team Β· safetrustcr.vercel.app