You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
contract(round): document and test all custom error codes (#172)
* Document and test all round contract error codes with CI drift check.
Add per-code integration tests, ERRORS.md/types.rs sync script, and contract workflow so SDK integrators can rely on stable documented codes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address review: trigger every round contract error path.
Wire AlreadyCleared/AlreadySettled/RoundVoided/BidExceedsEscrow into live return paths, add integration tests for all 27 codes, and document the deploy-only AlreadyInitialized constructor boundary.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy file name to clipboardExpand all lines: contracts/round/ERRORS.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,10 +15,10 @@ the SDK and bindings expose. **Both are part of the public API** and must
15
15
stay in sync with `contracts/round/src/types.rs`.
16
16
17
17
> Guardrail: no error codes are invented here. Every row corresponds to one
18
-
> variant of `enum Error` in [`src/types.rs`](src/types.rs). Variants marked
19
-
> **reserved** are present in the enum but not currently returned by any code
20
-
> path; they are documented because they are exported and integrators may
21
-
> see them in future protocol versions.
18
+
> variant of `enum Error` in [`src/types.rs`](src/types.rs). Every variant has
19
+
> an integration test in [`src/error_paths.rs`](src/error_paths.rs) that
20
+
> triggers the live return path (or, for deploy-only `AlreadyInitialized`,
21
+
> documents the constructor host boundary).
22
22
23
23
## Categories
24
24
@@ -49,9 +49,9 @@ stay in sync with `contracts/round/src/types.rs`.
49
49
| 15 |`RevealWindowClosed`|`reveal`|`env.ledger().timestamp() > round.reveal_deadline`. | The reveal window has closed for this round. | Do not retry the reveal. Any bid whose commit nobody successfully revealed stays marked `valid = false` and contributes no bid. After the deadline, anyone can call `clear`: if a valid reveal won, follow with `settle`; if no valid reveal existed, the round transitions to `Voided` and escrow is refunded via `void`/`refund_all` rather than `settle`. |
50
50
| 16 |`RevealStillOpen`|`clear`|`env.ledger().timestamp() <= round.reveal_deadline`. | The reveal window is still open; the round cannot be cleared yet. | Retry `clear` after `now > reveal_deadline`. |
51
51
| 17 |`NotCleared`|`settle`|`round.status != Status::Cleared`. | The round has not been cleared yet. | Call `clear` after `reveal_deadline`. If `clear` returned `Some(winner)` the round is now `Cleared` and `settle` is the right next step. If `clear` returned `None` the round has already transitioned to `Voided` with escrow refunded; do not call `settle` again — it will keep returning `NotCleared`. |
52
-
| 18 |`AlreadyCleared`|(reserved) | Not currently returned by any code path. |Reserved — the round is already in the Cleared state. |Reserved. If surfaced by a future version: do not retry `clear`. |
53
-
| 19 |`AlreadySettled`|(reserved) | Not currently returned by any code path. |Reserved — the round has already been settled. |Reserved. If surfaced by a future version: settlement funds have already moved; do not retry`settle`. |
54
-
| 20 |`RoundVoided`|(reserved) | Not currently returned by any code path. |Reserved — the round has been voided. |Reserved. If surfaced by a future version: all escrow has already been refunded; the round is terminal. |
52
+
| 18 |`AlreadyCleared`|`clear`, `open_reveal`|`round.status == Status::Cleared`. |The round has already been cleared. |Do not retry `clear`. Call `settle` if a winner exists. |
53
+
| 19 |`AlreadySettled`|`settle`, `commit`, `reveal`, `open_reveal`, `void`, `clear`|`round.status == Status::Settled`. |The round has already been settled. |Settlement funds have already moved; do not retry. |
54
+
| 20 |`RoundVoided`|`void`, `commit`, `reveal`, `open_reveal`, `clear`, `settle`|`round.status == Status::Voided`. |The round has been voided. |All escrow has already been refunded; the round is terminal. |
55
55
| 21 |`NotVoidable`|`void`| Round is past the `Open` status, or `now <= reveal_deadline + VOID_GRACE` (3600 s). | The round cannot be voided from its current state, or the grace window has not elapsed yet. | Either complete the normal lifecycle, or wait until `reveal_deadline + 1 hour` and try `void` again. |
56
56
| 22 |`WrongStatus`|`commit`|`round.status != Status::Open`. | A bid can only be submitted to a round in the Open status. | Start a new round; a Revealing/Cleared/Settled/Voided round no longer accepts commits. |
57
57
@@ -64,7 +64,7 @@ stay in sync with `contracts/round/src/types.rs`.
64
64
| 32 |`AlreadyRevealed`|`reveal`|`state.revealed_value.is_some()`. | A reveal has already been recorded for this bidder on this round. | No action — the recorded reveal stands. Repeated reveals are rejected on purpose to prevent front-running by a third party. |
65
65
| 33 |`PayloadTooLarge`|`create_round`, `commit`| One of: `auditor_pubkey.len() > 1024`, `ciphertext.len() > 4096`, `auditor_blob.len() > 2048`. | One of the submitted payloads is larger than the contract's size limit. | Shrink the offending payload: ciphertext ≤ 4096 B, auditor public key ≤ 1024 B, auditor blob ≤ 2048 B. |
66
66
| 34 |`InvalidAmount`|`create_round`, `commit`|`reveal_round == 0` (in `create_round`) or `escrow <= 0` (in `commit`). | The amount or value supplied is not positive. | Pass a positive integer; for `create_round`, use `reveal_round != 0` and a future `commit_deadline`. |
67
-
| 35 |`BidExceedsEscrow`|(reserved)|Not currently returned by any code path. |Reserved — the revealed bid would exceed the escrowed amount. |Reserved. The current contract already marks a bid invalid if `revealed_value > escrow` (see `BidState::valid`), so escrow refunds at settle. |
67
+
| 35 |`BidExceedsEscrow`|`reveal`|`value > state.escrow` after the commitment hash matches. |The revealed bid exceeds the escrowed amount. |Re-commit with escrow ≥ the sealed bid before the commit deadline, or reveal the exact committed value that fits under escrow. |
68
68
| 36 |`DeadlineInPast`|`create_round`|`commit_deadline <= now` (ledger time at submission). | The commit deadline is in the past. | Use a future timestamp; check ledger time at submission, since Drand round R must be strictly after `commit_deadline`. |
69
69
| 37 |`NoValidBids`|`settle`|`round.winner` is `None` on a round whose status is `Cleared`. | Round has no winner to settle against. | Investigate: under current behavior the contract transitions to `Voided` (with all escrow refunded) when no valid bid is revealed, so this code should not appear in normal flow. If it does, the round is in an inconsistent state and warrants a manual review. |
70
70
| 38 |`RoundFull`|`commit`|`round.bidders.len() >= MAX_BIDDERS` (500). | The round has reached its bidder cap. | Start a new round to accept further bidders. |
0 commit comments