Every milestone locks its value in a smart-contract escrow before the work starts. The freelancer submits on-chain. The client approves. The contract pays: no invoicing, no chasing, no “the check is in the mail.” Disagreements go to staked arbiters, not silence.
The marketplace lives off-chain where content belongs. Money never does; every state change below is a contract call you can verify, not a database row you have to trust.
A job carries its own milestone template: titles, scope, amounts. The API validates the sum against the budget range server-side; the template becomes the contract's blueprint when the work is awarded.
Accepting a proposal creates the project and its milestones in one transaction, locks the job, and auto-rejects the losing bids. Half-awarded jobs are structurally impossible.
The client's wallet calls fund() with the amount and a reference. From this second the money belongs to the contract: it can only move by approve, cancel, or arbitration. Both parties can see it, neither can touch it.
Delivery notes and files land off-chain; the state flip that matters is the freelancer's submit() transaction. The indexer mirrors it within seconds and the client's review window opens.
approve() releases the escrowed value instantly, minus the 2.5% fee. Can't agree? Either side locks the milestone into dispute and pays the fee; the contract draws up to 3 random, staked arbiters who vote commit-reveal to a 2-of-3 majority.
Both parties nominate an arbiter; a match starts the 72-hour SLA clock. Resolutions inside the SLA raise the arbiter's on-chain trust score, overdue ones slash it. The badge is soulbound (ERC-5194), so the score can't be bought, sold, or reset.