Skip to content

Admin dispute resolution for Pending sessions (#32)#59

Merged
Bosun-Josh121 merged 2 commits intoLightForgeHub:mainfrom
EtimbukUdofia:feature/admin-dispute-resolution
Mar 29, 2026
Merged

Admin dispute resolution for Pending sessions (#32)#59
Bosun-Josh121 merged 2 commits intoLightForgeHub:mainfrom
EtimbukUdofia:feature/admin-dispute-resolution

Conversation

@EtimbukUdofia
Copy link
Copy Markdown
Contributor

@EtimbukUdofia EtimbukUdofia commented Mar 29, 2026

Admin Dispute Resolution
Closes #32

Summary
Adds an admin-only resolve_dispute endpoint to the payment-vault-contract that allows forcefully splitting escrowed funds for a Pending booking. This is the fallback mechanism for when the Oracle crashes or an unresolvable dispute occurs between user and expert.

Summary by CodeRabbit

  • New Features

    • Admins can resolve booking disputes by splitting escrowed deposits and can recover any remaining disputed amount; bookings gain a new "disputed/resolved" state.
  • Events

    • New notifications emitted when disputes are resolved and when disputed remainders are recovered.
  • Errors

    • Added specific error responses for invalid dispute or remainder-recovery actions.
  • Tests

    • Comprehensive tests for authorization, validation, state transitions, pauses, and edge cases.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5051bfd7-2ea0-446c-9b8c-889af3db3d7b

📥 Commits

Reviewing files that changed from the base of the PR and between 9d6b1d8 and eee338b.

📒 Files selected for processing (7)
  • contracts/payment-vault-contract/src/contract.rs
  • contracts/payment-vault-contract/src/error.rs
  • contracts/payment-vault-contract/src/events.rs
  • contracts/payment-vault-contract/src/lib.rs
  • contracts/payment-vault-contract/src/storage.rs
  • contracts/payment-vault-contract/src/test.rs
  • contracts/payment-vault-contract/src/types.rs
✅ Files skipped from review due to trivial changes (1)
  • contracts/payment-vault-contract/src/error.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • contracts/payment-vault-contract/src/types.rs

📝 Walkthrough

Walkthrough

Adds admin-only dispute resolution and remainder recovery flows to the payment vault: admins can split a booking's escrow between user and expert, mark the booking DisputedAndResolved, and later recover any undistributed remainder to the admin. New storage helper, events, errors, types, and tests were added.

Changes

Cohort / File(s) Summary
Dispute control-flow & persistence
contracts/payment-vault-contract/src/contract.rs
Added resolve_dispute(env, booking_id, user_refund, expert_pay) and recover_disputed_remainder(env, booking_id) with admin auth, pausability checks, validation, transfers, booking updates, and event emission.
Contract surface / wrappers
contracts/payment-vault-contract/src/lib.rs
Exposed new PaymentVaultContract methods resolve_dispute(...) and recover_disputed_remainder(...) as contract entrypoints (thin wrappers).
Events
contracts/payment-vault-contract/src/events.rs
Added dispute_resolved(...) and disputed_remainder_recovered(...) events; minor formatting change to session_topped_up emission.
Types / Storage model
contracts/payment-vault-contract/src/types.rs, contracts/payment-vault-contract/src/storage.rs
Added BookingStatus::DisputedAndResolved = 4; extended BookingRecord with dispute_user_refund: Option<i128>, dispute_expert_pay: Option<i128>, dispute_remainder_recovered: bool; added update_booking(env, booking) helper to persist a full booking.
Errors
contracts/payment-vault-contract/src/error.rs
Added VaultError::BookingNotDisputed = 13 and VaultError::RemainderAlreadyRecovered = 14.
Tests
contracts/payment-vault-contract/src/test.rs
Added comprehensive "Dispute Resolution Tests": admin success path, auth checks, split validation (overflow/too-large/negative), pause behavior, non-existent booking handling, partial splits leaving remainder, and one-time remainder recovery and authorization checks.

Sequence Diagram

sequenceDiagram
    actor Admin
    participant Contract
    participant Storage
    participant Token as TokenTransfer
    participant Events

    Admin->>Contract: resolve_dispute(booking_id, user_refund, expert_pay)

    rect rgba(100, 150, 200, 0.5)
    Note over Contract: Validation Phase
    Contract->>Contract: check paused & require_admin_auth
    Contract->>Storage: load_booking(booking_id)
    Contract->>Contract: assert booking exists && status == Pending
    Contract->>Contract: validate amounts (>=0, no overflow, ≤ total_deposit)
    end

    rect rgba(150, 200, 150, 0.5)
    Note over Contract: Fund Distribution Phase
    alt user_refund > 0
        Contract->>Token: transfer(user_refund) from contract to booking.user
    end
    alt expert_pay > 0
        Contract->>Token: transfer(expert_pay) from contract to booking.expert
    end
    end

    rect rgba(200, 150, 150, 0.5)
    Note over Contract: State Update & Emission
    Contract->>Storage: update_booking(status=DisputedAndResolved, dispute_* fields)
    Contract->>Events: dispute_resolved(booking_id, user_refund, expert_pay)
    Events->>Events: publish topic/payload
    end

    Contract-->>Admin: Ok(())
Loading
sequenceDiagram
    actor Admin
    participant Contract
    participant Storage
    participant Token as TokenTransfer
    participant Events

    Admin->>Contract: recover_disputed_remainder(booking_id)

    rect rgba(100, 150, 200, 0.5)
    Note over Contract: Validation Phase
    Contract->>Contract: check paused & require_admin_auth
    Contract->>Storage: load_booking(booking_id)
    Contract->>Contract: assert status == DisputedAndResolved
    Contract->>Contract: assert !dispute_remainder_recovered
    end

    rect rgba(150, 200, 150, 0.5)
    Note over Contract: Remainder Calculation & Transfer
    Contract->>Contract: remainder = total_deposit - dispute_user_refund - dispute_expert_pay
    alt remainder > 0
        Contract->>Token: transfer(remainder) to admin
    end
    end

    rect rgba(200, 150, 150, 0.5)
    Note over Contract: Finalize
    Contract->>Storage: set dispute_remainder_recovered = true and persist
    Contract->>Events: disputed_remainder_recovered(booking_id, remainder)
    end

    Contract-->>Admin: Ok(remainder)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I hopped into the vault today,
to split the hoard the proper way,
A token here, a token there,
Remainder found — admin's care!
Disputes resolved with carrot flair.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description addresses the core change but does not follow the repository's required template structure, missing sections like Type of Change, Evidence, and proper checkbox usage. Use the complete PR template including Type of Change (Enhancement), checkboxes for tests/cargo verification, and Evidence section with test results or logs.
Out of Scope Changes check ❓ Inconclusive The PR includes an additional recover_disputed_remainder function and related infrastructure (new error variants, storage helper, and tests) that exceed the minimal scope defined in issue #32 but are functionally aligned with the dispute resolution feature. Clarify whether the remainder recovery functionality should be part of this PR or deferred to a separate feature, and document the decision in the PR description.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature being added: admin-only dispute resolution functionality for pending sessions, with the issue number reference.
Linked Issues check ✅ Passed All required code changes from issue #32 are implemented: BookingStatus::DisputedAndResolved added, resolve_dispute and recover_disputed_remainder functions implemented in contract.rs with proper validation, exposed in lib.rs, events added, and comprehensive tests included.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
contracts/payment-vault-contract/src/test.rs (2)

1485-1486: Consider adding a test for negative split amounts.

The test suite thoroughly covers the main scenarios. Consider adding a test that passes negative values for user_refund or expert_pay to verify the InvalidAmount error is returned, ensuring the validation at contract.rs lines 440-442 is exercised.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/payment-vault-contract/src/test.rs` around lines 1485 - 1486, Add a
unit test in contracts/payment-vault-contract/src/test.rs (e.g.,
test_negative_split_amounts) that calls the dispute resolution entry point (the
resolve_dispute or equivalent function in contract.rs) with negative values for
user_refund and/or expert_pay and assert it returns the InvalidAmount error;
ensure the test exercises the validation branch around the InvalidAmount
condition referenced in contract.rs (lines ~440-442) and verifies both
single-negative and mixed-negative parameter cases to cover validation paths.

2-2: Minor: Duplicate import exists in test_expert_rejects_pending_session.

The BookingStatus import is now at module level (line 2), but there's a duplicate use crate::types::BookingStatus; inside test_expert_rejects_pending_session at line 540 and test_user_cancels_before_session_starts_success at line 1290. Consider removing those inner imports for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/payment-vault-contract/src/test.rs` at line 2, Remove the redundant
inner imports of BookingStatus inside the test functions; since BookingStatus is
already imported at module scope (use crate::types::BookingStatus;), delete the
duplicate use crate::types::BookingStatus; lines found inside the functions
test_expert_rejects_pending_session and
test_user_cancels_before_session_starts_success so the tests rely on the
module-level import only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/payment-vault-contract/src/test.rs`:
- Around line 1642-1671: The test shows resolve_dispute leaves a remainder
locked in the contract; fix by adding an admin recovery path or documenting the
behavior. Either implement an admin-only method (e.g.,
admin_recover_disputed_remainder or recover_orphaned_funds) that (1) requires
caller == admin, (2) checks the booking is in DisputedAndResolved (or another
terminal status) and not already recovered, (3) computes remainder =
booking.deposit - booking.user_refund - booking.expert_pay, (4) transfers
remainder to admin (or to a configurable recipient) and marks the booking as
recovered to prevent double-withdrawal; update resolve_dispute/Booking struct to
record user_refund/expert_pay/status if needed. Or alternatively, update
contract docs and tests to explicitly state that resolve_dispute can leave
remainders locked and add guidance for dispute amounts—change tests referencing
"Funds remain locked in contract" accordingly.

---

Nitpick comments:
In `@contracts/payment-vault-contract/src/test.rs`:
- Around line 1485-1486: Add a unit test in
contracts/payment-vault-contract/src/test.rs (e.g., test_negative_split_amounts)
that calls the dispute resolution entry point (the resolve_dispute or equivalent
function in contract.rs) with negative values for user_refund and/or expert_pay
and assert it returns the InvalidAmount error; ensure the test exercises the
validation branch around the InvalidAmount condition referenced in contract.rs
(lines ~440-442) and verifies both single-negative and mixed-negative parameter
cases to cover validation paths.
- Line 2: Remove the redundant inner imports of BookingStatus inside the test
functions; since BookingStatus is already imported at module scope (use
crate::types::BookingStatus;), delete the duplicate use
crate::types::BookingStatus; lines found inside the functions
test_expert_rejects_pending_session and
test_user_cancels_before_session_starts_success so the tests rely on the
module-level import only.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 257a2f2c-ba24-44b7-950a-94f9cc949b91

📥 Commits

Reviewing files that changed from the base of the PR and between 2482d34 and 9d6b1d8.

📒 Files selected for processing (5)
  • contracts/payment-vault-contract/src/contract.rs
  • contracts/payment-vault-contract/src/events.rs
  • contracts/payment-vault-contract/src/lib.rs
  • contracts/payment-vault-contract/src/test.rs
  • contracts/payment-vault-contract/src/types.rs

Implement admin fund recovery mechanism or document remainder handling in dispute resolution.
@Bosun-Josh121
Copy link
Copy Markdown
Collaborator

Nice work @EtimbukUdofia

@Bosun-Josh121 Bosun-Josh121 merged commit 2dad268 into LightForgeHub:main Mar 29, 2026
2 checks passed
@EtimbukUdofia
Copy link
Copy Markdown
Contributor Author

@Bosun-Josh121 Thank you. Still open for further collaboration.

@coderabbitai coderabbitai bot mentioned this pull request Mar 30, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Admin Dispute Resolution

2 participants