Chainflow is a production-style Web3 backend built with NestJS, Prisma, and Ethers.js.
It implements:
🔐 User Authentication (JWT)
👛 Wallet Management
⛽ Transaction Preparation (Gas Estimation)
📡 Non-Custodial Signed Transaction Relay
📊 Transaction Lifecycle Tracking
📘 Swagger API Documentation
This project demonstrates real-world backend architecture for Web3 applications.
Chainflow follows a secure non-custodial pattern:
User registers & logs in (JWT issued)
User adds wallet address
Backend prepares transaction
Frontend signs transaction
Backend validates and broadcasts
Backend waits for receipt & stores result
Private keys never touch the backend.
| Layer | Technology |
|---|---|
| Framework | NestJS |
| Language | TypeScript |
| Blockchain | ethers.js v6 |
| Database | Prisma ORM |
| Auth | JWT (Passport) |
| Docs | Swagger |
| Network | Ethereum / Sepolia |
Chainflow uses JWT-based authentication.
Register POST /auth/register
Body:
{
"email": "user@example.com",
"password": "strongpassword"
}Login POST /auth/login
Returns:
{
"access_token": "jwt_token_here"
}Use JWT in headers:
Authorization: Bearer
👛 Wallet Management
Generate Nonce GET /wallet/nonce Returns:
{
"message": "Sign this message to verify your wallet ownership.Nonce: 5e27809bc546799e53681ab84fcc6ab1"
}Verify Wallet GET /wallet/verify Body:
{
"address": "0x...",
"signature": "0x..."
}Response:
{
"message": "Wallet verified successfully"
}Get Wallet GET /wallet Returns:
{
"address": "0x..."
}Get Balance GET /wallet/balance Returns:
{
"balance": "1000000000000000000"
}Associates wallet with authenticated user.
⛽ Transaction Flow 1️⃣ Prepare Transaction POST /transfer/estimate
Body:
{
"from": "0x...",
"to": "0x...",
"amount": "100000000000000000"
}Response:
{
"gas": "21000",
"amount": "100000000000000000",
"total" : "100000000000021000"
}User signs using these parameters on frontend.
2️⃣ Execute Signed Transaction POST /transfer/transfer
Body:
{
"signature": "0x..."
}Backend:
Decodes raw tx
Validates signer
Broadcasts via RPC
Waits for receipt
Stores transaction in DB
Response:
{
"txHash": "...",
"gas": "...",
"fee": "...",
"blockNumber": "...",
"status": "success"
}Swagger UI available at:
All endpoints are documented using @nestjs/swagger.
- id
- password (hashed)
- id
- userId
- address
- createdAt
- id
- userId
- nonce
- expiresAt
- createdAt
- id
- userId
- from
- to
- amount
- createdAt
1️⃣ Clone
git clone https://github.com/darrendc26/chainflow.git
cd chainflow2️⃣ Install
npm install3️⃣ Setup Environment Create .env:
DATABASE_URL="file:./dev.db"
JWT_ACCESS_TOKEN_SECRET="your_access_token_secret" JWT_REFRESH_TOKEN_SECRET="your_refresh_token_secret"
SEPOLIA_RPC_URL="your_rpc_url" PRIVATE_KEY="optional_for_testing"
4️⃣ Run Prisma
npx prisma migrate dev
npx prisma generate5️⃣ Start Server
npm run start:devSwagger available at: http://localhost:3000/api
- JWT authentication guard
- Wallet ownership validation via signature recovery
- Nonce verification to prevent replay attacks
- ChainId enforcement to avoid cross-network misuse
- EIP-1559 fee support
- BigInt-safe handling of blockchain values