v2.9.0
v2.9.0 — Silence stops paying
Compatibility: COORDINATED — please update. No wire-format change (the events
are identical), but this release changes which arbiter votes the rules ACCEPT
during a disputed, expiring trade. Existing trades, balances, listings, and
communities are untouched, and a normal trade behaves exactly as before. The one
place it matters: a CONTESTED trade that reaches its deadline now resolves by an
arbiter's ruling instead of an automatic refund — and an old client would still
expect the old automatic refund. So everyone in a dispute should be on v2.9
before the deadline. The app now says so, in the trade, at exactly that moment.
The hole we closed
- A seller could win by doing nothing. Seller locks the sats, buyer sends the
fiat and votes to release — and then the seller simply goes quiet until the
trade expires. The old expiry rule always refunded whoever locked, so the
silent seller got the sats BACK while keeping the buyer's fiat. Both sides of
the money, zero effort, no message required. That's now closed.
How it's closed
- A standing "release" vote from the party who performed turns an expiry from an
abandonment into a CONTEST. Once a performer has voted release and the other
side stays silent past a short, trade-length-proportional deadline, the
deadline no longer auto-refunds the locker — the assigned arbiter (or a backup,
through the same gate) can rule on the merits. Showing up is the only way to
win; silence isn't. - The safety valve that keeps this honest: if the arbiter rules REFUND — i.e.
finds the performer didn't actually perform — the locker's refund completes
normally. So a buyer can't vote "release" without paying to freeze a seller's
sats forever; the worst they achieve is a trip to the arbiter, at the cost of
their own reputation. Two-of-three is never weakened, and no settled vote is
ever rewritten. - Abandonment still works the way it should: if nobody performed (the buyer
never voted release), the deadline still auto-refunds the locker. The fix only
bites when one side performed and the other ghosts.
In the trade, at the right moment
- Once a release vote is standing on a locked trade, the expiry banner stops
promising an automatic refund and reads: "At the deadline this goes to an
arbiter, not an automatic refund. Make sure everyone in this trade is on the
latest Chama, so the decision settles the same for all." Non-contested trades
keep the familiar refund-at-expiry banner, untouched.
Why a coordinated release (the honest version)
- Every change since v2.0 has been additive — new clients saw more, old clients
saw less, nobody disagreed. This one is different: it changes a rule about
which votes are valid, so a new client and an un-updated client could read the
same contested-expired trade differently until both update. That's why this
ships on its own, why the in-trade nudge exists, and why these notes lead with
"please update." The new deadline is derived purely from the trade's own event
chain (replay-deterministic, same discipline as arbiter substitution), so once
everyone's updated, every client lands on the identical answer with no
coordinator.
Numbers
- 2,277 tests green (+22 for this fix: the theft closed, the freeze that can't
happen, abandonment still refunds, the marketplace inversion, and the deadline
always landing before expiry); typecheck clean; verified by an independent
multi-angle adversarial review (theft / freeze / two-of-three integrity /
cross-version divergence) that found nothing.