Install
You need Rust 1.85 or newer and Node.js 22.13 or newer (below 27). Settype to module in package.json.
Why the escrow needs no signatures
complete and cancel are covenants: the operator and the emulator cosign them when every require passes. Anyone who can build a passing transaction can submit one. That is safe because the address pins each outcome’s outputs: complete must pay the seller’s script and cancel must pay the buyer’s. The submitter picks the moment, never the destination. The seller never signs, and the buyer signs once, when funding the address.
Compile the contract
Save Escrow asescrow.ark and compile it:
- Replace the three keys before you fund the escrow. The scripts use well-known test keys.
exitis the operator’sunilateralExitDelay, encoded in seconds withtimelockToSequence. A raw delay binds as blocks, and the operator rejects a block-based exit leaf. It also rejects an exit delay below its minimum.- The scripts read
unilateralExitDelayon each run, and the escrow address depends on it. If the operator changes its delay after you fund, the scripts derive another address and find no output. Pass the delay you funded with instead. partyAScriptandpartyBScriptare 32-byte witness programs (tweakedPublicKey). Spend outputs use the fullpkScript.timeoutAtis1700000000, already past, socancelworks as soon as an output arrives.
Complete
complete pays the seller when the oracle signs. Fund the printed address with 12000 sats, then run the same file again. The seller receives 10000 sats. The buyer receives the rest.
complete.ts
Cancel
cancel returns the output to the buyer. Fund the printed address, then run the same file again.
cancel.ts
Exit if the operator is unavailable
If the operator is unavailable, the parties can still claim the output onchain withunilateral. First unroll it: broadcast the virtual transactions that lead to it. After the output confirms and the exit delay passes, Bitcoin checks the leaf. Both parties sign, and the leaf does not check the outputs. This file pays a Bitcoin address with a 1000-sat fee.
Set UNROLLED_TXID, UNROLLED_VOUT, UNROLLED_VALUE, and BITCOIN_ADDRESS to the unrolled output and the destination.
unilateral.ts