Wire dual control — the maker can never be the checker
In August 2020 Citibank meant to send $7.8M of interest on a Revlon loan and instead wired the full $893M principal. Three humans approved it — but all three were looking at the same misleading screen, and a court initially let the creditors KEEP it. Dual control only works when the checker is structurally distinct and the amount has a hard ceiling. Here a wire cannot reach `sent` except through `checked` (the drafted -> sent edge does not exist), the maker's own approval is refused, and the per-wire amount slot rejects anything over the desk's $10M limit at the write — the $893M fat-finger dies in memory, not in a code review.
A Soma program from the escrow_finance part of the verified corpus: 98 lines, cells WireDesk, WireTests. It passes soma check with soma 3.2.4.
How it is built
The cell WireDesk declares 4 signals in its face: draft_wire(id: String, maker: String, amount: Int) -> Map, check_wire(id: String, checker: String) -> Map, send_wire(id: String) -> Map and cancel_wire(id: String) -> Map; keeps 2 memory slots: amount (Map<String, Int>, persistent and consistent) under the invariant amount >= 0 && amount <= 10000000 and makers (Map<String, String>, persistent and consistent). Its state machine wire starts in blank and allows 5 transitions: blank -> drafted, drafted -> checked, drafted -> cancelled, checked -> sent and checked -> cancelled. cancelled and sent are terminal. Handlers: draft_wire (line 42), check_wire (line 50), send_wire (line 60) and cancel_wire (line 66).
The file also holds 1 test cell (WireTests) with 14 assertions, run by soma test.
The source
wire_dual_control.cell
// ============================================================================
// WIRE DUAL CONTROL — the maker can never be the checker
// ============================================================================
//
// In August 2020 Citibank meant to send $7.8M of interest on a Revlon loan
// and instead wired the full $893M principal. Three humans approved it —
// but all three were looking at the same misleading screen, and a court
// initially let the creditors KEEP it. Dual control only works when the
// checker is structurally distinct and the amount has a hard ceiling.
// Here a wire cannot reach `sent` except through `checked` (the drafted ->
// sent edge does not exist), the maker's own approval is refused, and the
// per-wire amount slot rejects anything over the desk's $10M limit at the
// write — the $893M fat-finger dies in memory, not in a code review.
// ============================================================================
cell WireDesk {
face {
signal draft_wire(id: String, maker: String, amount: Int) -> Map
signal check_wire(id: String, checker: String) -> Map
signal send_wire(id: String) -> Map
signal cancel_wire(id: String) -> Map
}
memory {
// hard desk limit: a single wire over $10M is an impossible write
amount: Map<String, Int> [persistent, consistent]
invariant amount >= 0 && amount <= 10000000
makers: Map<String, String> [persistent, consistent]
}
// sent and cancelled are terminal. The only road to sent runs
// through checked — there is no drafted -> sent shortcut.
state wire {
initial: blank
blank -> drafted
drafted -> checked
drafted -> cancelled
checked -> sent
checked -> cancelled
}
on draft_wire(id: String, maker: String, amount_usd: Int) {
if amount_usd <= 0 { return map("ok", false, "reason", "bad amount") }
transition(id, "drafted")
amount.set(id, amount_usd) // raises above the $10M desk limit
makers.set(id, maker)
return map("ok", true, "state", get_status(id), "maker", maker)
}
on check_wire(id: String, checker: String) {
let maker = makers.get(id) ?? ""
if checker == maker {
// DUAL CONTROL: the person who typed it cannot bless it
return map("ok", false, "reason", "{checker} drafted this wire — second person required")
}
transition(id, "checked")
return map("ok", true, "state", get_status(id), "checker", checker)
}
on send_wire(id: String) {
transition(id, "sent") // raises unless independently checked
let amt = amount.get(id) ?? 0
return map("ok", true, "sent_usd", amt)
}
on cancel_wire(id: String) {
transition(id, "cancelled")
return map("ok", true, "state", get_status(id))
}
}
cell test WireTests {
rules {
// THE CITIBANK NUMBER: $893M cannot even be drafted — the slot
// refuses the write, the wire never exists
assert_fails draft_wire("w0", "raj", 893000000)
// a sane wire: $7.8M interest payment
assert draft_wire("w1", "raj", 7800000).ok == true
// UNCHECKED SEND: the drafted -> sent edge does not exist
assert_fails transition("w1", "sent")
assert_fails send_wire("w1")
// SELF-APPROVAL: the maker is refused as checker
assert check_wire("w1", "raj").ok == false
assert_fails transition("w1", "sent")
// a distinct checker unlocks the send — once
assert check_wire("w1", "priya").ok == true
assert send_wire("w1").sent_usd == 7800000
// sent is terminal: no re-send, no post-hoc cancel
assert_fails transition("w1", "sent")
assert_fails transition("w1", "cancelled")
// cancellation path is just as final
assert draft_wire("w2", "raj", 500000).ok == true
assert cancel_wire("w2").ok == true
assert_fails transition("w2", "checked")
assert_fails amount.set("w2", -1)
}
}What the toolchain says
$ soma check wire_dual_control.cell
warning: parameter 3 of `draft_wire`: the face calls it `amount`, the handler `amount_usd` — an HTTP JSON body is matched by NAME (the handler's), and `soma describe` publishes the face's: use one name
--> wire_dual_control.cell:18:9
|
18 | signal draft_wire(id: String, maker: String, amount: Int) ->…
| ^
✓ 1 warning(s), no errors.$ soma test wire_dual_control.cell
test WireTests ...
✓ assert_fails draft_wire("w0", "raj", 893000000) — raised memory invariant violated on 'amount': amount >= 0 && amount <= 10000000 — rejected write of 893000000 (key "w0"); the slot is unchanged
✓ assert draft_wire("w1", "raj", 7800000).ok == true
✓ assert_fails transition("w1", "sent") — raised invalid transition: drafted → sent. Current state: 'drafted'. Valid targets: [checked, cancelled]
✓ assert_fails send_wire("w1") — raised invalid transition: drafted → sent. Current state: 'drafted'. Valid targets: [checked, cancelled]
✓ assert check_wire("w1", "raj").ok == false
✓ assert_fails transition("w1", "sent") — raised invalid transition: drafted → sent. Current state: 'drafted'. Valid targets: [checked, cancelled]
✓ assert check_wire("w1", "priya").ok == true
✓ assert send_wire("w1").sent_usd == 7800000
✓ assert_fails transition("w1", "sent") — raised invalid transition: sent → sent. Current state: 'sent'. Valid targets: []
✓ assert_fails transition("w1", "cancelled") — raised invalid transition: sent → cancelled. Current state: 'sent'. Valid targets: []
✓ assert draft_wire("w2", "raj", 500000).ok == true
✓ assert cancel_wire("w2").ok == true
✓ assert_fails transition("w2", "checked") — raised invalid transition: cancelled → checked. Current state: 'cancelled'. Valid targets: []
✓ assert_fails amount.set("w2", -1) — raised memory invariant violated on 'amount': amount >= 0 && amount <= 10000000 — rejected write of -1 (key "w2"); the slot is unchanged
14 tests: 14 passed, 0 failed$ soma verify wire_dual_control.cell
Verifying wire_dual_control.cell...
State machine 'wire': 5 states, initial 'blank'
States: [blank, cancelled, checked, drafted, sent]
✓ 5 states, 5 transitions
✓ all states reachable from 'blank'
✓ terminal states: [cancelled, sent]
✓ no deadlocks
✓ liveness: every state can eventually reach a terminal state
✓ think-isolated: CTL safety properties hold regardless of LLM output (4 handlers, 4 literal transitions, 0 dynamic)
✓ termination: all 4 handlers structurally terminate
✓ refinement: handler `draft_wire` ⟶ {drafted}
✓ refinement: handler `check_wire` ⟶ {checked}
✓ refinement: handler `send_wire` ⟶ {sent}
✓ refinement: handler `cancel_wire` ⟶ {cancelled}
· transition sources: `draft_wire`, `check_wire`, `send_wire`, `cancel_wire` call transition(id, target) without declaring the source — the runtime refuses a move the graph forbids, but the proof does not see where the handler starts; `transition(id, from, to)` names the edge (checked by `soma check`, refused at run time from any other state)
WireDesk/invariants:
✓ invariant amount >= 0 — writer 'draft_wire' proven by induction (writes amount_usd)
⚠ invariant amount >= 0 && amount <= 10000000 — runtime-checked (computed values): draft_wire → amount [amount <= 10000000] because `amount_usd` is only known to lie in [1, ∞) — narrow it: `require amount_usd <= 10000000 else …`
12 passed, 1 warnings, 0 failures
Temporal properties for 'wire':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK