Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CharityGuard

A donation platform that scores every charitable transaction for fraud risk before it settles, and enforces the same threshold twice — once in the API, once on-chain. Charities are checked against an imported IRS Exempt Organizations extract; donations whose score crosses the flag threshold are held by the smart contract until an owner releases them.

license node solidity

Features

  • Weighted risk scoring — a deterministic rule engine in transactionController.detectFraud combines EIN validity, IRS presence, amount anomaly, donor wallet history, charity-name pattern matching and transaction velocity into a 0–1 score.
  • EIN verification against imported IRS dataverificationService looks the EIN up in the irsorgs collection and derives a trust score from IRS status, deductibility and foundation codes.
  • Trust levels that move with behaviourupdateTrustMetrics only reacts once a charity has 10+ transactions, then promotes to whitelisted or drops to blacklisted based on completion ratio and average fraud score. The 10-transaction floor exists so a single donation cannot whitelist an unknown organisation.
  • On-chain escrow for flagged donations — the contract transfers funds immediately when the score is below the flag threshold and holds them otherwise, so the fraud decision has an effect that cannot be undone by editing the database.
  • Token auth with rotation — access token plus a stored refresh token (RefreshToken model) and a TokenBlacklist, with Google OAuth as an alternative sign-in.
  • Layered HTTP hardening — helmet with an explicit CSP, express-mongo-sanitize, xss-clean, hpp, a general rate limiter on /api and a stricter one on /api/transactions.
  • Admin surface — flagged transaction review, user suspension/ban, activity logs with chart aggregation, export endpoints, and Recharts analytics in the React UI.

Architecture

React (CRA + MUI)                       Express API                     Ethereum
─────────────────                       ───────────                     ────────
Donate / Search   ──POST /api/transactions──>  detectFraud()
                                                 |  weights: EIN .35, IRS .25,
                                                 |  amount .15, new wallet .10,
                                                 |  name pattern .09, velocity .06,
                                                 |  recipient .20 (capped at 1.0)
                                                 v
                                          score >= 0.65 -> "flagged"
                                                 |
useBlockchain (MetaMask) ──makeDonation(charity, name, EIN, score*100)──>
                                                                CharityGuardDonations
                                                                  <= 30  VERIFIED, funds sent
                                                                  <  65  PENDING,  funds sent
                                                                  >= 65  FLAGGED,  funds held
                                                                         until verifyDonation()
MongoDB: Transaction · Nonprofit · IRSOrg · User · RefreshToken · TokenBlacklist · ActivityLog
Directory Contents
backend/controllers/ Fraud engine, transaction/auth/user/nonprofit handlers
backend/services/ verificationService (EIN + trust), analyticsService, blockchainService
backend/middleware/ auth, security, validation, errorHandler
backend/scripts/ importIrsData.js, seed-admin.js, demo/dataset loaders
blockchain/ CharityGuardContract.sol — a single self-contained contract
charityguard-frontend/src/ Pages, components, useBlockchain, useAdminAuth, MUI theme

Quickstart

There is no .env.example committed; the variables below are the ones the code reads.

# 1. API
cd backend
npm install
cat > .env <<'EOF'
NODE_ENV=development
PORT=3001
MONGODB_URI=mongodb://localhost:27017/charityguard
JWT_SECRET=<at least 32 characters>
JWT_EXPIRES_IN=7d
FRONTEND_URL=http://localhost:3000
# optional: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, STRIPE_SECRET_KEY,
#           RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX_REQUESTS, LOG_LEVEL
EOF

ADMIN_PASSWORD=<8+ chars> npm run seed:admin   # creates the first admin account
npm run dev                                    # nodemon, http://localhost:3001

# 2. Web app
cd ../charityguard-frontend
npm install
cat > .env <<'EOF'
REACT_APP_API_URL=http://localhost:3001
REACT_APP_API_BASE_URL=http://localhost:3001/api
REACT_APP_CONTRACT_ADDRESS=<deployed contract address>
REACT_APP_INFURA_KEY=<infura project id, used to add Sepolia to MetaMask>
EOF
npm start                                      # http://localhost:3000

MONGODB_URI is validated by Joi at startup, but config/db.js and the standalone scripts also accept MONGO_URI; scripts/importIrsData.js reads MONGO_URI only.

IRS data import. Place the IRS Exempt Organizations Business Master File CSVs in backend/data/irs/, then run node scripts/importIrsData.js. It streams in batches of 500, tolerates duplicate EINs, and creates a unique index on ein at the end. The script requires csv-parser, which is not in package.json — install it first.

Contract. blockchain/CharityGuardContract.sol is plain Solidity 0.8.19 with no Hardhat or Foundry config in the repo. Compile and deploy it with your own toolchain, then put the address in REACT_APP_CONTRACT_ADDRESS.

API

Selected routes; auth is a bearer access token unless marked public.

Method Endpoint Notes
GET /health 200 only when Mongo is connected, otherwise 503
POST /api/auth/register · login · refresh · logout · google Rate-limited; refresh tokens rotate
GET /api/auth/me Current user
POST /api/transactions Runs the fraud engine and persists the result
GET /api/transactions · /flagged · /:hash · /:id/details · /donor/:address Paginated and sortable where listed
GET /api/transactions/stats/fraud · /export Aggregates and export
PATCH /api/transactions/:id/status · POST /bulk-update Review actions
GET /api/nonprofits/search?q=&state=&limit= · /stats · /:id Public IRS lookup
GET/POST /api/nonprofits/registered List public, register authenticated
PATCH /api/nonprofits/registered/:id/status · /trust · POST /flag Admin only
GET/PATCH /api/users, /:id/status, /:id/details, /export Admin only
GET/PUT /api/users/wallet/:address (+ /donations, /favorites/:ein) Public wallet profile
GET/POST /api/activity-logs (+ /recent, /stats?days=) Authenticated; write is admin

Submitting a donation for scoring:

curl -X POST http://localhost:3001/api/transactions \
  -H 'Content-Type: application/json' \
  -d '{ "transactionHash": "0xabc123", "nonprofitName": "Example Relief Fund",
        "nonprofitEIN": "53-0196605", "donorAddress": "0x742d35Cc...",
        "recipientAddress": "0xCharityWallet", "amount": 0.75, "blockNumber": 18456789 }'

The response carries fraudScore, the list of riskFlags that fired, and an aiAnalysis object explaining each one in prose — the engine is rule-based, so every score decomposes into the checks that produced it.

Tech stack

Layer Technology
Frontend React 18, TypeScript 4.9, MUI 5, Recharts, ethers 6, Transak SDK, CRA
Backend Node.js ≥18, Express 4, Mongoose 8, Joi, Winston
Contract Solidity 0.8.19
Auth / payments JWT with refresh rotation, Google OAuth2, bcryptjs, Stripe

Testing

cd backend
npm test        # jest --coverage
npm run lint    # eslint

backend/tests/ holds a Supertest integration suite for registration, login, logout and health, plus unit tests for the analytics risk bands, insight generation and the fraud engine's new-donor and amount-outlier paths. The GitHub Actions workflow runs a node --check syntax sweep, ESLint and npm audit; it does not currently run the test suite.

License

MIT

About

Donation platform that scores charity transactions with a weighted rule engine and escrows flagged donations in a Solidity contract

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages