
Freelance Trail
Verifiable freelance escrow: milestones, payments, and GitHub-proven contributions
Demo
About
FreelanceTrail is a blockchain-powered freelance platform that replaces trust with verification. Clients scope projects into milestones and fund each one in USDC through a smart contract escrow on Arc Testnet — funds release only after a milestone is approved. Developers submit proof of work that's checked against their real, merged GitHub pull requests, not a written claim. Every on-chain event is indexed through a Graph Protocol subgraph for fast, reliable syncing. AI agents built on NVIDIA's models analyze contributions, generate a portable Developer Payment Passport summarizing verified earnings and reputation, and match clients with developers based on real coding history instead of a resume.
How it's made
The stack: NestJS + Prisma 7 (Postgres) for the backend, Next.js 16 (App Router, Turbopack) + wagmi/viem + TanStack Query + Tailwind v4 for the frontend, and a Solidity escrow contract (Foundry) deployed on Arc Testnet handling USDC milestone payments end to end. Arc was the natural fit for the escrow layer since it's built for stablecoin settlement — USDC moves natively rather than as a bolted-on ERC-20, which matters when you're locking and releasing funds per milestone instead of per project. For on-chain sync, we started by polling Arc's RPC directly with viem — and hit its rate limits hard mid-hackathon once the escrow had real history to scan. We replaced that with a hand-authored Graph Protocol subgraph indexing all six contract events, with the backend polling its GraphQL endpoint and persisting a sync cursor for instant, rate-limit-free restarts. graph init's interactive wizard didn't work in our sandboxed shell, so we hand-wrote the schema/manifest/mappings directly and verified correctness by getting graph codegen && graph build to actually compile, rather than trusting the docs blind. Three AI agents (Mastra + NVIDIA NIM models) power contribution analysis, reputation generation, and freelancer matching. Getting NVIDIA's API reliable was its own saga — we hit EOL'd models, unprovisioned models, and one reasoning model that hung for 12 minutes before we settled on nemotron-3.5-lightning. We also chased down an intermittent ENOTFOUND that only Node's dns.lookup() (not dns.resolve()) triggered, fixed with a custom undici.Agent doing manual DNS resolution. The most "hacky-but-real" design choice: milestone proof isn't free text. A developer must pick from their own verified, merged GitHub pull requests, and the chain listener matches the submitted proof URL against that list before marking it verified — turning "trust me, it's done" into something actually checkable.