Web3
How to Build a Smart-Contract Escrow (and Ship It Safely)
A smart-contract escrow is a program that holds funds and releases them only when pre-agreed conditions are met — no bank, no middleman, every step provable on-chain. Done right it turns "trust me" into "verify it." Done wrong it loses customer money in a single transaction. So before we write a line of Solidity, we argue about the design.
This is how our team actually works through an escrow build — the questions we ask, the options we put on the whiteboard, and where we land. We've shipped this ourselves (AbsoluteSafe), so this is the real process, not the demo version.
01 First fight: what is the contract really holding?
The opening discussion is never about code — it's about the deal. Escrow is a state machine, and most failures are design failures, not bugs. We map every state and every transition: agree → fund → deliver → release, plus the unhappy paths that actually cause losses — partial delivery, no-show, dispute, abandonment.
The biggest early decision is release granularity. The simple version releases everything at the end. We almost always reject that.
02 The invariant that matters more than any feature
Once the contract is the custodian, its correctness is the product. We define one rule the contract can never violate: the funds held always cover everything owed. Every function is then judged against that invariant — if a path could let withdrawals exceed the balance, it doesn't ship.
This reframes the whole build. Features are negotiable; the solvency invariant is not. We write it as an explicit assertion and test against it relentlessly, because "looks fine" is how escrows get drained.
03 Disputes without inventing a referee problem
Every team hits the same wall here: who decides a contested release? We put three options up and pressure-test each.
- Pure code / oracle: elegant when "done" is objectively measurable on-chain, useless for subjective work.
- Single arbiter: simple, but it reintroduces the trusted middleman escrow was meant to remove.
- 2-of-3 multisig (buyer, seller, neutral): no single party can move funds alone, the neutral only breaks ties.
For most real deals we land on the 2-of-3 with a time-boxed process — propose, respond, arbiter decides — and a timeout so funds can never be trapped by a party who simply goes silent. The principle we keep repeating in the room: no path should ever permanently lock money.
04 Treat the audit as a gate, not a trophy
Before mainnet we run our own adversarial pass first — re-entrancy, rounding, griefing, gas-griefing, fee-on-transfer tokens — then a fork test against real token behaviour, then an independent audit. We budget more time for hardening than for the happy-path contract, because that ratio is where safe escrows and exploited ones diverge.
Key takeaways
- Design the deal as a state machine — including the unhappy paths — before any code.
- Hold one non-negotiable solvency invariant and judge every function against it.
- Use a 2-of-3 dispute path with timeouts so funds are never trapped.
- Gate launch on adversarial testing plus an independent audit.
FAQ
How long does escrow take to build?
A milestone MVP with disputes is a few weeks of design and build; hardening and the audit usually take longer than the contract itself — and that's the right ratio.
Which chains and tokens first?
One EVM chain and the stablecoins your users hold (USDC/USDT). Multi-chain is a later optimisation, never a launch requirement.
Do we really need an audit?
For anything holding real funds, yes — an internal adversarial review plus an independent audit is the floor.
We designed and shipped AbsoluteSafe — on-chain escrow, audited and live.
Build escrow with us