Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SafeSend 🛡️

SafeSend is a secure, premium simulated wallet built using the PERN stack (PostgreSQL, Express + TypeScript, React + TypeScript + Tailwind) that implements a 60-Second Undo Shield and Nominee-Gated Approvals for transactions.

It protects users from accidental transfers, high-velocity fraud spikes, and concurrent double-spend race conditions using robust row-level database locking and a dual-ledger auditing design.


Key Features

  1. ₹50,000 Seed Balance: Every new user starts with ₹50,000 seeded by the SYSTEM user transaction.
  2. 60-Second Undo Shield: Transfers below the safety limit (default ₹10,000) are placed on hold. A circular visual countdown ticks on the screen. The sender can hit "Undo" to instantly cancel the transfer and refund the funds. If the timer expires, the worker captures the payment.
  3. Nominee-Gated Approvals:
    • Transfers exceeding the user's custom safety limit require nominee approval.
    • High-velocity checks flag a user if they perform 5+ transfers in 10 minutes or send > ₹5,000 to a new recipient, forcing nominee approval regardless of the safety limit.
    • Real-time popups notify nominees via Socket.io. If they do not approve within 24 hours, the transfer automatically expires and is refunded.
  4. Idempotency Protection: All /transfer requests are safeguarded using UUID idempotency keys.
  5. Thread-Safe Row-Level Locking: Raw Postgres locking (SELECT ... FOR UPDATE) protects user accounts against concurrent wallet double-spends.
  6. Immutable Ledger Entries: Double-entry ledger audit trail tracks all actual settled debit and credit movements.

Technical Stack & Architecture

flowchart TD
    subgraph Frontend [React Web Client]
        UI[Vite App / Tailwind CSS]
        SC[Socket.io-Client]
        AC[Auth Context]
    end

    subgraph Backend [Express Server]
        API[Express Controllers / Routing]
        Auth[JWT + Bcrypt Middleware]
        PP[PaymentProvider - SimulatedWallet]
        Queues[BullMQ Queue Manager]
        Sockets[Socket.io Server Hub]
    end

    subgraph Infrastructure [Docker compose]
        DB[(PostgreSQL Database)]
        Cache[(Redis Cache & Queue Store)]
    end

    UI <-->|HTTP API / JSON| API
    SC <-->|WebSocket Events| Sockets
    API -->|Raw SQL Transactions| DB
    PP -->|Row Locking| DB
    Queues <-->|Jobs / Tasks| Cache
    API -->|Queue Jobs| Queues
Loading

Database Schema (Prisma)

  • User: Holds wallet metadata, password hashes, balanceCache (cached balance), and safetyLimit. Relationships track configuration of the Nominee (nominee and nomineeOf).
  • Transaction: Records transfer state (PENDING, REQUIRES_APPROVAL, COMPLETED, CANCELLED, REJECTED, EXPIRED), idempotency keys, and scheduled settlement timestamps (settlesAt).
  • LedgerEntry: Immutable accounting records (DEBIT/CREDIT) written during actual settlement captures.

Concurrency Safety & Load Test

SafeSend implements Row-Level Locking (SELECT ... FOR UPDATE) in Postgres transactions to guarantee that even under heavy concurrent attacks, the wallet balance can never be double-spent.

A custom concurrency script (scripts/load-test.ts) simulates 100 concurrent requests of ₹600 each (total ₹60,000 requested) on a single sender account with a ₹50,000 starting balance:

Load Test Results

Scenario Row Locking Successes Failures Final Balance Ledger Audit Status
Without Row-Level Locking DISABLED 6 94 ₹48,200 ₹50,000 ✅ PROTECTED (Stale updates overwritten)
With Row-Level Locking ENABLED 10 90 ₹44,000 ₹50,000 ✅ PROTECTED (Strict transaction order)

Note

  • Under DISABLED locking, concurrent database transactions overwrite each other's cache updates based on stale balance reads, leading to lost updates (only ₹1,800 total deducted instead of ₹3,600).
  • Under ENABLED locking, Postgres queues transaction locks sequentially, assuring correct state transitions, preventing race conditions, and correctly rejecting transfers once the sender's balance falls below the requested ₹600.

Setup & Running Locally

Prerequisites

  • Docker & Docker Compose
  • Node.js (v20+)

1. Boot up Infrastructure (PostgreSQL & Redis)

SafeSend runs Postgres on host port 5433 and Redis on host port 6380 to prevent conflicts with pre-existing local instances:

npm run db:up

2. Install Project Dependencies

Install dependencies for both folders from the project root:

npm run install-all

3. Setup Database Schema

Generate the Prisma client and push the schema to PostgreSQL:

cd backend
npx prisma generate
npx prisma db push

4. Run the Servers Concurrently

Start the Express server backend and the React Vite dev server concurrently from the root directory:

npm run dev
  • Frontend will be accessible at: http://localhost:5173
  • Backend API will run on: http://localhost:3000

Running Tests

E2E Integration Suite

SafeSend uses Jest + Supertest to run tests covering instant limits, 60s shields, nominee approval flow, and high velocity flags:

cd backend
npm run test:e2e

Concurrency Load Test

Run the concurrency load test to observe row-level locking behavior:

cd backend
npm run test:concurrency

SafeSend

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages