Skip to content

bug: dispute-resolution's Dispute record never reflects escrow's admin-resolved settlement #60

Description

@JamesVictor-O

Problem

campaign-escrow::resolve_dispute is documented as a deliberate, working interim path that settles a committed payout without going through dispute-resolution at all (lib.rs:833-838):

"Admin-resolved settlement for a single creator's committed-but-not-yet-paid application, as a simplified interim path alongside the arbiter-resolved dispute-resolution contract... a separate admin-only shortcut that works today without it."

That's a reasonable design — but it means when this path is used for a payout that does have an open dispute in dispute-resolution (i.e. raise_dispute was called first, which is the normal/expected flow per that contract's own doc comments), dispute-resolution's record of it is left permanently stale. Nothing ever calls dispute-resolution::clear_open_dispute (storage.rs:113-119, doc comment says "Called once resolve_dispute is implemented" — grepping the whole crate confirms it is never called anywhere), and campaign-escrow::resolve_dispute has no awareness of dispute-resolution at all.

Concrete failure scenario

  1. Creator calls dispute-resolution::raise_dispute — this freezes the payout in escrow via freeze_for_dispute and writes a Dispute { status: Raised, outcome: Pending, resolved_at: None }.
  2. Admin settles it directly via campaign-escrow::resolve_dispute(admin, campaign_id, creator, PayCreator) — funds move, application.status = Paid, application.frozen = false.
  3. dispute-resolution::get_dispute(dispute_id) still returns status: Raised, outcome: Pending, resolved_at: None forever. There's no code path that will ever update it — dispute-resolution::resolve_dispute (the arbiter flow) is a separate todo!() stub, and even once implemented, it has no reason to be called for a dispute the admin already settled through the other contract.

Any indexer or frontend that treats dispute-resolution::get_dispute as the source of truth for "is this dispute still open" will show a stale, indefinitely-"Raised" dispute for money that has already been paid out — a real data-integrity gap for anyone building on top of this contract's event/read surface, even though the underlying funds themselves are safely resolved.

This is distinct from #42 (wiring the arbiter-resolved flow) — it's about the admin bypass path that already works today leaving the other contract's state permanently wrong, independent of whether the arbiter flow ever gets built.

Expected behaviour

When campaign-escrow::resolve_dispute settles a payout, any corresponding open dispute in dispute-resolution should be closed out — either via a cross-contract call from escrow back into dispute-resolution, or by exposing a way for indexers to reliably detect this case (e.g. clearly documenting that dispute-resolution::get_dispute is not authoritative once the admin bypass has been used, and giving them a cheap way to check — e.g. cross-referencing campaign-escrow::get_application(...).frozen == false against a still-Raised dispute).

Files

  • contracts/campaign-escrow/src/lib.rsresolve_dispute
  • contracts/dispute-resolution/src/lib.rs / storage.rs — expose a callable "close dispute" path if going the cross-contract route

Acceptance criteria

  • Decide and document how campaign-escrow's admin-resolve bypass should reconcile with an open dispute-resolution record (cross-contract close-out, or a documented "not authoritative" caveat + a supported way to detect the mismatch)
  • If implementing a close-out call: a test raises a dispute via dispute-resolution, resolves it via campaign-escrow::resolve_dispute, and asserts the dispute-resolution record reflects Resolved
  • If documenting instead: the caveat is added to dispute-resolution::get_dispute's doc comment, plus a read-only way for callers to detect the stale case

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third CampaignbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions