Skip to content

safetrustcr/dApp-SafeTrust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

234 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SafeTrust Logo

dApp-SafeTrust

Decentralized P2P Escrow Β· Stellar Blockchain Β· MVP monorepo (monorepository)

License: MIT pnpm Turborepo Next.js Hasura Stellar


dApp-SafeTrust is the MVP assembly monorepo β€” it brings together curated slices from frontend-SafeTrust and backend-SafeTrust into a single runnable application. One command starts everything.


πŸš€ Quick Start Β· πŸ—οΈ Architecture Β· πŸ“ Structure Β· 🧩 Apps & Packages Β· πŸ› οΈ Development Β· 🀝 Contributing


πŸ” What is SafeTrust?

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.


πŸ—οΈ Architecture

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.


πŸ“ Project Structure

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

🧩 Apps & Packages

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) β€”

πŸš€ Quick Start

Prerequisites

Tool Version Install
Docker + Docker Compose latest docs.docker.com
Node.js β‰₯ 18 nodejs.org
pnpm β‰₯ 8 npm install -g pnpm

1. Clone the repository

git clone https://github.com/safetrustcr/dApp-SafeTrust.git
cd dApp-SafeTrust

2. Configure environment variables

cp .env.example .env

Open .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/graphql

3. Start everything

docker compose up -d

This starts four services in the correct order:

postgres β†’ hasura (applies migrations + seeds) β†’ api β†’ web

4. Verify

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" }

πŸ› οΈ Development

Install dependencies

pnpm install

Run all apps in dev mode

pnpm dev

Turborepo starts apps/web and apps/api in parallel, respecting the dependency graph.

Run a single app

pnpm dev --filter @safetrust/web
pnpm dev --filter @safetrust/api

Generate GraphQL types

Requires Hasura to be running (docker compose up hasura -d):

pnpm codegen --filter @safetrust/web

This introspects the Hasura schema and writes typed Apollo hooks to packages/graphql/generated/index.ts.

Build all apps

pnpm build

Turborepo builds packages first (types β†’ graphql), then apps.

Run tests

pnpm test

πŸ—„οΈ Database

Hasura automatically applies all migrations and seeds from infra/hasura/ on first start.

Core tables (MVP)

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

Access Hasura Console

http://localhost:8080/console
Admin secret: myadminsecretkey

Reset database

docker compose down -v        # removes volumes
docker compose up -d          # fresh start, migrations re-applied

πŸ”Œ API Endpoints

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

🌊 Contributing

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.

Issue Batches

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

Stub convention

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.

Before opening a PR


πŸ”— Related Repositories

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

πŸ“š Resources


Built with πŸ” by the SafeTrust team Β· safetrustcr.vercel.app

About

Interface for a decentralized platform enabling secure and trusted P2P transactions with cryptocurrency.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors