Inspiration
Over 63 million MSMEs in India alone have more than ₹10 Lakh Crore locked in unpaid B2B invoices at any given time. When a small supplier delivers goods to a corporate giant, they're forced into Net-90 day payment terms — and traditional banks reject 80% of their loan applications. Legacy factoring companies charge predatory 15%+ fees with mountains of paperwork.
I asked myself: what if an MSME could tokenise a verified invoice and receive funding from a global investor in under 60 seconds — with no bank, no middleman, and no paperwork?
That's FactorFi.
What it does
FactorFi is a decentralised invoice factoring protocol that bridges Web2 financial truth with Web3 liquidity:
- Sellers verify a real Stripe invoice and mint it as an ERC-721 NFT on Ethereum
- Investors browse a marketplace of verified invoices and fund them at a seller-controlled discount in USDC
- Buyers repay the face value into a trustless smart contract escrow
- Investors claim their yield after repayment — all on-chain, all verifiable
The protocol charges a transparent 1% fee (hardcoded in the smart contract), and the seller controls their own discount rate via a slider (2-15%).
How I built it
Frontend: React 19 + TypeScript + Tailwind CSS v4 + Ethers.js v6, deployed on Vercel.
Backend: A Node.js/Express proxy server (deployed on Railway) that handles all sensitive API calls server-side. The frontend never touches a single secret key.
Smart Contract: InvoiceEscrow.sol — built with Solidity ^0.8.20, OpenZeppelin (ERC721URIStorage, SafeERC20, ReentrancyGuard), deployed on Ethereum Sepolia Testnet.
Integrations:
- Stripe API — Server-side invoice verification (checks existence, ownership, and
openstatus) - Pinata — IPFS pinning for immutable NFT metadata
- Resend — Automated email notifications to buyers when their invoice is funded
Challenges I ran into
The Oracle Problem: How do you verify that a real-world invoice exists without trusting the seller? I solved this for V1 by building a direct Stripe API bridge — the backend verifies the invoice is real and unpaid before allowing tokenisation.
Double-Financing Prevention: A malicious seller could try to mint the same invoice twice. I solved this by hashing the Web2 invoice ID on-chain in a
processedInvoicesmapping — the smart contract mathematically prevents duplicate minting.RPC Performance: Naively fetching invoices with unbounded loops took 15+ seconds. I implemented a
getNextTokenId()getter in the contract and usedPromise.all()on the frontend, dropping load times to under 1 second.Security without Complexity: I needed to keep Stripe/Pinata keys hidden from the client without overengineering the architecture. The Express proxy pattern gave me bank-grade key isolation with minimal overhead.
Accomplishments that I'm proud of
- End-to-end working protocol — Not a mockup. Every transaction (mint, fund, repay, claim) executes on a live Ethereum testnet smart contract.
- Trustless two-step escrow — Buyers repay into the contract, investors claim separately. No party has to trust the other.
- Zero secret key exposure — The entire Stripe/Pinata/Resend integration runs through a secured backend proxy. The React frontend never sees a single API key.
- Sub-second marketplace loading — Bounded RPC fetching with
Promise.all()brought page load from 15s down to under 1s. - Anti-fraud by default — Double-financing is impossible at the smart contract level, not just the UI level.
What I learned
- How to architect a full-stack Web3 application with proper separation of concerns
- The real-world challenges of RWA (Real World Asset) tokenisation — especially around fraud prevention and oracle design
- How to build a trustless two-step escrow mechanism (repay → claim) that eliminates counterparty risk
- The importance of bounded on-chain data fetching for frontend performance
What's next for FactorFi
- Chainlink Oracle Integration — Automate the repayment step by listening to bank webhooks
- GSTN API — Verify invoices against India's government tax portal for zero-fraud origination
- The Graph — Replace RPC loops with indexed GraphQL queries
- UUPS Proxy — Make the contract upgradeable for production deployment
Built With
- ethereum
- ethers.js
- express.js
- ipfs
- node.js
- openzeppelin
- pinata
- railway
- react
- resend
- solidity
- stripe
- tailwind-css
- typescript
- vercel
- vite
Log in or sign up for Devpost to join the conversation.