The Problem
Freelancers and small businesses are sitting on billions of dollars of locked capital — invoices that are legitimate, enforceable, and already earned, but won't pay out for 30, 60, or 90 days. Traditional invoice factoring charges 2–5% fees, requires revealing sensitive business data to third parties, and still takes days to process. The money is yours. You just can't use it yet.
What vopo Does
vopo turns that waiting period into a yield-generating opportunity — automatically.
Mint — Connect your wallet, enter your invoice details, and mint an invoice NFT on Mantle Sepolia. Your invoice data never touches the chain in plain text: we use keccak256 commitments so only you can prove what you hold.
Deposit — Drop the NFT into the YieldVault. Choose a strategy: Conservative (3.5% APY) or Aggressive (7% APY). Your invoice is now earning while you wait.
Watch the Agent Work — A TypeScript AI agent runs 24/7 and streams its reasoning to the frontend in real time. It reads invoice risk scores from Pyth Network, evaluates days-until-due, payment probability, and current yield rates, then decides whether to change your strategy.
On-chain Execution — When the agent is confident enough (≥70%), it writes its decision through
AgentRouteron-chain. The decision, reasoning, and confidence score are all recorded and visible in the dashboard.Withdraw — When your invoice is paid or you want out, withdraw the NFT and claim accrued yield.
What Makes It Different
Most "AI + DeFi" demos call an API and show a chatbot. vopo's agent executes on-chain. Every strategy change it makes is a real transaction, signed by an authorized wallet, recorded permanently on Mantle Sepolia, and visible on the explorer. The "Living Agent" feed on the dashboard streams the agent's reasoning in real time — you can watch it think, decide, and act.
The privacy layer is also real. Invoice details are stored only in the user's browser as a salt. On-chain, only the keccak256 commitment exists. An authorized counterparty can verify an invoice is genuine without ever learning the amount or client name.
How We Built It
Smart Contracts (Solidity + Hardhat, Mantle Sepolia)
InvoiceNFT— ERC-721 with privacy commitments and oracle-driven risk scoresYieldVault— deposit/withdraw/strategy management with simulated Aave-style yield accrualAgentRouter— records agent decisions with confidence scores and executes them against the vaultPrivacyRegistry— Merkle-based selective disclosurePythOracle+AaveV3YieldSource— integrated oracle and yield source
Agent (TypeScript/Node.js)
- Runs a continuous loop: fetch deposits → analyze each invoice → generate LLM explanation → optionally execute → broadcast via WebSocket
- Uses Qwen for natural language reasoning summaries
- Pyth Network for real-time invoice risk pricing
- Each RPC call fans out across multiple Mantle Sepolia endpoints to avoid rate limiting
Frontend (Next.js 15 + React 19 + wagmi/viem)
- Dashboard with live TVL, yield, active invoices, and agent activity feed
- Mint page with privacy-preserving commitment generation
- Portfolio, issuer, and settings views
- QuickBooks OAuth integration for importing real invoice data
- Explorer link on every transaction
Infrastructure
- Docker containers for both app and agent, deployed to Ubuntu via GitHub Actions CI/CD
NEXT_PUBLIC_*vars baked at build time with placeholder strings replaced by entrypoint at runtime
Challenges We Faced
The NEXT_PUBLIC_* baking problem. Next.js embeds these vars into the JS bundle at build time,
not runtime — in both the client chunks and the server route bundles. We had to extend the
container entrypoint to sed-replace placeholder strings in both directories, and add guards in
API routes to detect unreplaced placeholders before constructing URLs.
EIP-1559 gas on production HTTPS. Locally, MetaMask is lenient with legacy type-0 transactions.
On an HTTPS origin it enforces EIP-1559 fee validation strictly, causing transactions with a
gasPrice override (from simulateContract) to get stuck in the mempool indefinitely. The fix was
to remove simulateContract entirely and let the wallet use native EIP-1559 fee estimation via
writeContractAsync.
Receipt polling across multiple RPCs. viem's fallback() transport only switches providers on
network errors — a null receipt from a 200 response doesn't trigger a retry. We poll each RPC URL
independently in the force-settle path to handle nodes that haven't yet indexed a transaction
another node already confirmed.
QuickBooks OAuth in a Docker container. The NEXT_PUBLIC_APP_URL placeholder surviving in
server-side route bundles caused new URL('__VOPO_APP_URL__/...') to crash. Combined with Docker's
--env-file parser including trailing whitespace as part of values (breaking clientId), this took
several debug cycles to fully resolve.
What We Learned
Real deployment is where the interesting bugs live. The gap between "works on localhost" and "works on production HTTPS in a Docker container behind a reverse proxy" exposed every assumption we'd made about environment variables, gas estimation, and transaction indexing. Mantle Sepolia's low fees and fast finality made on-chain iteration fast enough that we could actually fix these in real time without burning through test funds.
What's Next
- Integrate Lendle protocol for more yield
- Add Noir ZK circuits for amount range proofs (prove an invoice is > $X without revealing the amount)
- Secondary market for invoice NFTs
Log in or sign up for Devpost to join the conversation.