SafeTrust is a decentralized P2P escrow platform targeting the hospitality and tourism sector. Powered by the Stellar blockchain via the TrustlessWork API, it replaces traditional deposit systems for hotels, vacation rentals, and booking platforms with trustless smart contracts that hold funds on-chain, release payments automatically on checkout confirmation, and handle disputes through transparent on-chain arbitration giving both guests and hosts a secure, verifiable alternative to legacy payment intermediaries. πβ¨
π Trustless Technology: Secure and block deposits without intermediaries. πΎ Blockchain-Powered Transparency: Immutable, auditable, and verifiable transactions. π± Crypto-Payment Support: Manage cryptocurrency payments safely and efficiently. β Automated Refunds: Streamlined processes ensure refunds and payment releases happen automatically.
π οΈ Trustless Escrow: Funds are securely held in blockchain-based escrow accounts until all terms are met.
π Blockchain Transparency: Every transaction is logged on the blockchain for full visibility and accountability. π
π° Crypto Payments: Supports irreversible and secure cryptocurrency payments while reducing risks of fraud or disputes.
π Trustline Process: Verified trustlines between parties add an extra layer of transaction security. π
π€ Automated Refund System: Ensures funds are automatically released based on the terms of the agreement, with no manual intervention required.
- Create Escrow: The renter creates a secure escrow account. ποΈ
- Fund Escrow: The deposit is funded by the renter. π΅
- Rental Agreement: Terms are agreed upon and stored on the blockchain. π
- Completion or Cancellation: Funds are released based on contract outcomes. π―
- Node.js v18 or later π₯οΈ
- A Stellar blockchain wallet β Freighter is recommended π
- Trustless Work API access (docs here) π
- A Firebase project with Email/Password authentication enabled (Firebase Console) π₯
π§© This repo runs standalone.
frontend-SafeTrustdoes not requirebackend-SafeTrustto be running locally. It connects directly to a live Hasura GraphQL endpoint and to Firebase β both are remote services reachable over the network, not local processes you need to start. See Architecture: Standalone vs. Monorepo below for the full explanation.
1οΈβ£ Fork and clone the repository
git clone https://github.com/<your_user>/frontend-SafeTrust
cd frontend-SafeTrust
git remote add upstream https://github.com/safetrustcr/frontend-SafeTrust2οΈβ£ Install dependencies
npm install3οΈβ£ Set up environment variables
cp .env.example .env.localThen open .env.local and fill in each value β follow the Environment Variables section below step by step. Do not commit .env.local; it is already covered by .gitignore.
4οΈβ£ Start the development server
npm run dev β² Next.js 15.5.15
- Local: http://localhost:3000
- Network: http://192.168.x.x:3000
- Environments: .env
β Starting...
β Ready in 4s
This repo runs on port 3000 by default. You only need to override the port with npm run dev -- --port 3001 if you are also running landing-SafeTrust locally at the same time β see Port Conventions below.
Every environment variable lives in .env.local (never committed to git). Use .env.example as the template β copy it first, then fill in each block below one at a time.
These six values come from Firebase Console β Project Settings β Your apps β Web app β SDK setup and configuration β Config, and are required for Login, Register, and session auth to work:
NEXT_PUBLIC_FIREBASE_API_KEY=<your apiKey>
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=<your-project-id>.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=<your-project-id>
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=<your-project-id>.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=<your messagingSenderId>
NEXT_PUBLIC_FIREBASE_APP_ID=<your appId>βΉοΈ These are public, browser-safe values β Firebase ships them to the client by design, and the
NEXT_PUBLIC_prefix is what makes Next.js expose them to the bundle. The real security boundary is Firebase Security Rules, not secrecy of these values. They are not the Firebase Admin SDK private key, which belongs only inbackend-SafeTrustand must never appear here.
Make sure Email/Password sign-in is enabled in Authentication β Sign-in method for Register and Login to work. π Firebase Auth docs
NEXT_PUBLIC_API_URL=https://api.trustlesswork.com
NEXT_PUBLIC_API_KEY=<your_trustlesswork_api_key>
NEXT_PUBLIC_TRUSTLESS_API_URL=https://api.trustlesswork.com
NEXT_PUBLIC_TRUSTLESS_API_URL_DEV=https://dev.api.trustlesswork.com
NEXT_PUBLIC_TRUSTLESS_NETWORK=testnet- Obtain
NEXT_PUBLIC_API_KEYfrom your TrustlessWork dashboard - Always use
testnetforNEXT_PUBLIC_TRUSTLESS_NETWORKin local development β never point local dev atmainnet
NEXT_PUBLIC_HASURA_GRAPHQL_URL=<your Hasura GraphQL endpoint>/v1/graphqlThis points to a Hasura GraphQL endpoint β typically the shared SafeTrust Hasura instance, reachable over the network. You do not need to clone, run, or Dockerize backend-SafeTrust to develop on this repo; just point this variable at a working Hasura URL and the frontend talks to it directly.
π
HASURA_GRAPHQL_ADMIN_SECRETmust never be set in this repository. The frontend authenticates against Hasura via a Firebase JWT, not the admin secret. The admin secret grants unrestricted read/write access to the entire database and belongs only inbackend-SafeTrust's server-side environment β never in aNEXT_PUBLIC_*variable, never in.env.localhere, and never committed anywhere. Seesrc/config/apollo.tsfor how the JWT-based auth header is attached to GraphQL requests.If you ever see
NEXT_PUBLIC_HASURA_ADMIN_SECRETor similar in a.envfile in this repo, treat it as a security incident β remove it and rotate the secret inbackend-SafeTrustimmediately.
# Firebase Client SDK (public, browser-safe β see section 1 above)
NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSy...
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project-id.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789012
NEXT_PUBLIC_FIREBASE_APP_ID=1:123456789012:web:abcdef123456
# TrustlessWork API (Optional, don't need it yet)
NEXT_PUBLIC_API_URL=https://api.trustlesswork.com
NEXT_PUBLIC_API_KEY=your_trustlesswork_api_key
NEXT_PUBLIC_TRUSTLESS_API_URL=https://api.trustlesswork.com
NEXT_PUBLIC_TRUSTLESS_API_URL_DEV=https://dev.api.trustlesswork.com
NEXT_PUBLIC_TRUSTLESS_NETWORK=testnet
# Hasura GraphQL (a reachable endpoint β backend-SafeTrust does NOT need to run locally; NO admin secret here, ever)
NEXT_PUBLIC_HASURA_GRAPHQL_URL=https://your-hasura-instance.example.com/v1/graphqlSafeTrust ships as three separate repositories, but they can be run in two different ways depending on what you're working on:
| Setup | What runs | When to use it |
|---|---|---|
frontend-SafeTrust standalone (this repo) |
Only npm run dev here. Connects to a remote/shared Hasura GraphQL endpoint and Firebase. No local backend, no Docker. |
UI work, component development, dashboard features β most contributor tasks |
dApp-SafeTrust monorepo |
Both frontend and backend (Hasura, Postgres, webhook service) run together via the monorepo's own tooling | Full-stack work that touches schema, mutations, or webhook behavior |
backend-SafeTrust standalone |
Only the backend (Hasura + Postgres + webhook via Docker Compose), run independently | Backend-only contributors who don't need the UI |
For this repo (frontend-SafeTrust), you only need:
- The six Firebase env vars (section 1 above)
- The TrustlessWork API vars (section 2 above)
- A working
NEXT_PUBLIC_HASURA_GRAPHQL_URLpointing at a reachable Hasura instance (section 3 above) npm run dev
You do not need to clone or run backend-SafeTrust to work on this repo. If you want a fully local, isolated backend instead of the shared instance, you can still clone backend-SafeTrust separately and point NEXT_PUBLIC_HASURA_GRAPHQL_URL at http://localhost:8080/v1/graphql β but that's optional, not a requirement to get this repo running.
This only matters if you're running multiple SafeTrust repos at the same time on the same machine (for example, frontend-SafeTrust alongside landing-SafeTrust). If you're only running this repo, npm run dev on its default port (3000) is all you need.
| Repo | Port | Start command |
|---|---|---|
landing-SafeTrust |
3000 |
npm run dev |
frontend-SafeTrust (this repo) |
3000 (default) β use 3001 only if landing-SafeTrust is also running |
npm run dev or npm run dev -- --port 3001 |
backend-SafeTrust (optional, local backend) |
4000 (webhook), 8080 (Hasura) |
docker compose up -d |
If you start this repo on the default port while landing-SafeTrust is already running on 3000, your browser may silently load the landing page instead of the dApp β and any runtime errors you see will actually belong to the landing repo, not this one.
- Frontend: TypeScript, Next.js 15, Tailwind CSS
- Auth: Firebase Authentication (Email/Password, Google OAuth)
- GraphQL: Apollo Client 4, Hasura GraphQL Engine
- Blockchain: Stellar, TrustlessWork API
- Wallet: Freighter, Albedo, LOBSTR
This project uses Jest, React Testing Library, and Cypress for comprehensive testing.
npm test # unit and integration tests
npm run test:e2e # E2E tests (Cypress)
npm run test:coverage # coverage report- Unit and integration tests live in
__tests__directories or as.test.ts(x)files next to the code they test - E2E tests live in
cypress/e2e/ - API requests are mocked via Mock Service Worker (MSW) β handlers in
mocks/handlers.ts
π Join SafeTrust today and revolutionize the way you manage P2P transactions! π