Turn unpaid invoices into instant capital. Settle in USDC on-chain.
Live Demo: https://factor-fi.vercel.app
FactorFi is a DeFi protocol that tokenizes B2B invoices as ERC-721 NFTs and enables on-chain factoring. Sellers mint verified invoices, investors fund them at a discount for real-world yield, and repayments are settled in USDC — bypassing traditional banking delays entirely.
Network: Ethereum Sepolia Testnet
Contract Address: 0x9c800E293EaA50316B104E44E2CE15925C22804E
API keys are never exposed to the frontend. The React client communicates exclusively through a custom Node.js backend proxy.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ React Frontend │ │ Node.js Backend │ │ External APIs │
│ (Vite + Ethers) │──────▶│ (Express Proxy) │──────▶│ Stripe & Pinata │
└────────┬────────┘ └────────┬────────┘ └─────────────────┘
│ │
│ (MetaMask TX) │ (Resend Email)
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Smart Contract │ │ Corporate │
│ (Sepolia EVM) │ │ Buyer Wallet │
└─────────────────┘ └─────────────────┘
- Invoice Tokenization — Mint verified invoices as immutable ERC-721 NFTs.
- Anti-Double Financing — Smart contract permanently logs Web2 invoice IDs to prevent duplicate minting.
- Secure Backend Proxy — Node.js backend handles Stripe API calls, Pinata IPFS uploads, and Resend emails. The frontend never touches secret keys.
- Two-Step Escrow Settlement — Buyers repay into escrow, investors claim yield separately. Trustless and verifiable.
- Investor Marketplace — Browse, filter, and fund unfunded invoices at a discount.
- Rate Limiting & Input Sanitization — API routes are rate-limited (100 req / 15 min) and all inputs are regex-validated before processing.
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Tailwind CSS v4, Ethers.js v6 |
| Backend | Node.js, Express, TypeScript, Resend API |
| Blockchain | Solidity ^0.8.20, OpenZeppelin (ERC721, SafeERC20, ReentrancyGuard) |
| Storage & Verification | Pinata (IPFS), Stripe Invoicing API |
- Node.js ≥ 18
- MetaMask browser extension
- A testnet wallet with Sepolia ETH + test USDC
Note: Running locally requires your own
STRIPE_SECRET_KEY,PINATA_JWT, andRESEND_API_KEY. If you just want to try the app, use the Live Demo instead.
git clone https://github.com/Namanjs/FactorFi.git
cd FactorFiFrontend (frontend/.env)
| Variable | Description |
|---|---|
VITE_API_BASE |
URL of the backend proxy (default: http://localhost:3001) |
Backend (backend/.env)
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY |
Stripe API secret key for invoice verification |
PINATA_JWT |
Pinata JWT token for IPFS uploads |
RESEND_API_KEY |
Resend API key for buyer notification emails |
FRONTEND_URL |
Deployed frontend URL (used for CORS) |
You must run both servers simultaneously.
1. Start the Backend Proxy
cd backend
npm install
npm run dev2. Start the Frontend (In a new terminal)
cd frontend
npm install
npm run devThe frontend will be available at http://localhost:5173 and the backend will run on http://localhost:3001.
cd frontend
npm run build
npm run preview├── InvoiceEscrow.sol # Solidity smart contract
├── DOCUMENTATION.md # Technical & business docs
├── README.md
│
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── ErrorBoundary.tsx # React error boundary
│ │ │ ├── Navbar.tsx # Global nav with wallet connection
│ │ │ └── Footer.tsx # Site footer
│ │ ├── lib/
│ │ │ ├── constants.ts # Contract addresses & ABIs
│ │ │ └── WalletContext.tsx # Global wallet state
│ │ ├── pages/
│ │ │ ├── Home.tsx # Landing page
│ │ │ ├── Borrow.tsx # Seller — verify & mint invoices
│ │ │ ├── Invest.tsx # Investor marketplace
│ │ │ ├── Portfolio.tsx # Portfolio & yield tracking
│ │ │ └── NotFound.tsx # 404 page
│ │ ├── App.tsx # Router + WalletProvider
│ │ └── main.tsx # Entry point
│ ├── package.json
│ └── vite.config.ts
│
└── backend/
├── src/
│ └── server.ts # Express API proxy
└── package.json
The InvoiceEscrow.sol contract handles:
mintInvoice()— Seller creates an invoice NFT with face value, discounted price, due date, and buyer wallet addressfundInvoice()— Investor pays the discounted price in USDC; 1% protocol fee routes to the treasury, 99% goes to the sellerrepayInvoice()— The designated buyer deposits the face value into the smart contract escrowclaimYield()— The investor withdraws their payout after the buyer has repaid the escrow
Built by Naman Agarwal.
MIT