anvil devnet · Base-native by design

Freelance work,
paid the way
code pays:
by proof.

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.

2.5%
fee on released value, nothing else
72h
arbiter SLA, enforced by slashing
48h
window to agree on an arbiter
milestone 1 · threat modelFunded
value under escrow
0.240ETH
fee 2.5% · on release · Base-native settlement
Mara locks 0.24 ETHescrow contract holds it; nobody can move it
Dario submits on-chaindelivery proof lands with the milestone
0.234 ETH paid outapproved, instant release, 2.5% fee accounted
tx 0x7f3a…c21e · 12 confopenlance · anvil
0xf39F…2266funded milestone 1 · 0.240 ETH0x7099…79C8submitted threat model for reviewescrowreleased 0.234 ETH to freelancer · fee 0.0060x9965…0a4Dresolved dispute · split 50/50registryarbiter trust +1 · inside SLA0x3C44…93BCaccepted proposal · 3 milestones

Five moves. All on-chain.

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.

Watch it live on real jobs
STEP 01

Post the work, broken into milestones

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.

> POST /jobs · milestone sum validated
STEP 02

Award it — the bridge event

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.

> project + milestones born atomically
STEP 03

Fund the milestone — value locks

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.

> fund(bytes32 ref, address freelancer)
STEP 04

Ship, then submit on-chain

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.

> submit(uint256 milestoneId)
STEP 05

Approve — or open the arbiter path

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.

> approve · openDispute · commitReveal

Disputes end in hours, with people who stake their name.

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.

+1
trust per resolution inside the 72h SLA
−2
slashed when the clock runs out; anyone can call it
SBT
soulbound badge (ERC-5194), non-transferable by design
arbiter registry · erc-5194 72h SLA live
Ingrid Salm
security researcher · 40+ peer reviews
12
trust
resolved · split1h 48m inside SLA+1
resolved · release3h 02m inside SLA+1
resolved · refund61h 20m inside SLA+1
badge #7 · soulbound · transfer() reverts by design

Stop invoicing.
Start escrowing.

Post your first jobanvil devnet · no real funds, real contracts