Commit 66dfaf4
committed
fix(escrow): allow multi-sig escrows to enter the Disputed state
`dispute()` read only `EscrowEntry.arbiter`, returning `NoArbiter` when it was
`None`. Escrows created by `deposit_with_arbiters` deliberately leave `arbiter`
as `None` and carry their arbiters in `arbiters` + `arbiter_threshold`, so every
multi-sig escrow was rejected.
Because `dispute()` is the only transition into `Disputed`, and both
`vote_for_dispute` and `resolve_dispute_multi_sig` require that status, the
entire multi-arbiter dispute path was unreachable. A multi-sig escrow could only
ever be withdrawn or refunded after expiry; its arbiters could never act.
`dispute()` now accepts either shape. The emitted `EscrowDisputed` event still
carries a single representative arbiter: the assigned one for single-arbiter
escrows, otherwise the first listed arbiter — the same deterministic fallback
`dispute::resolve_expiry_recipient` already uses.
Why this was not caught:
- `test_deposit_with_arbiters_creates_escrow_and_is_disputable` never calls
`dispute()`; it only asserts the escrow is `Pending`.
- `test_multi_sig_invalid_signer_cannot_vote`,
`test_multi_sig_insufficient_votes_cannot_resolve` and the single-vote test
all build their escrow with `deposit(..., Some(arbiter))` — a single-arbiter
escrow, not a multi-sig one — then assert `is_err()`, which passed for the
wrong reason.
Adds `lifecycle_test.rs` covering the real transition: a multi-sig escrow
reaching `Disputed`, and an assigned arbiter voting once it is.
Also adds `reentrancy_test.rs`, which drives the money paths with a hostile
token that calls back into the contract. `deposit_with_commitment` and
`partial_payment` transfer before writing state, unlike the other eight money
paths; the tests pin down that the Soroban host refuses the re-entrant frame, so
the duplicate-commitment and overpayment guards cannot be bypassed. If that
platform guarantee ever changes, these fail rather than silently allowing
duplicate settlement.
Tests: 407 -> 411, all passing. clippy clean on the changed files. Repo-wide
`cargo fmt` is not clean (326 pre-existing diffs, which is why it is disabled in
CI), so only the two new files were formatted.1 parent 5978569 commit 66dfaf4
4 files changed
Lines changed: 389 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1098 | 1098 | | |
1099 | 1099 | | |
1100 | 1100 | | |
1101 | | - | |
1102 | | - | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
1103 | 1125 | | |
1104 | 1126 | | |
1105 | 1127 | | |
| |||
1113 | 1135 | | |
1114 | 1136 | | |
1115 | 1137 | | |
1116 | | - | |
| 1138 | + | |
1117 | 1139 | | |
1118 | 1140 | | |
1119 | 1141 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
| 40 | + | |
| 41 | + | |
38 | 42 | | |
39 | 43 | | |
40 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
0 commit comments