Skip to content

Transfer escrowed funds on dispute resolution in resolve_dispute #641

Description

@mikewheeleer

Transfer escrowed funds on dispute resolution in resolve_dispute

Description

resolve_dispute in contracts/escrow/src/lib.rs computes (client_payout, freelancer_payout) via dispute::resolution_payouts, mutates contract.refunded_amount and contract.released_amount, sets the final status, and emits an event — but it never moves any tokens. Every other money-flow path (release_milestone, refund_unreleased_milestones, cancel_contract) performs a token::Client::transfer from the contract's escrow balance; resolve_dispute is the only one that updates accounting while leaving the SAC token balance untouched. The result is that resolved disputes credit nobody on-chain: the freelancer's awarded payout and the client's refund both remain stranded in the contract address, and the accounting fields no longer match the real token balance.

This issue makes dispute resolution actually pay out: after computing the split, transfer client_payout to contract.client and freelancer_payout to contract.freelancer from the bound settlement token, atomically with the accounting update.

Requirements and context

  • Repository scope: Talenttrust/Talenttrust-Contracts only.
  • Read the bound settlement token via Self::read_settlement_token(&env) and resolve to a typed error (SettlementTokenNotConfigured) rather than a host expect panic if unset.
  • After resolution_payouts returns, transfer client_payout to contract.client and freelancer_payout to contract.freelancer, skipping zero-value transfers.
  • Keep the existing accounting invariant check (released + refunded == funded) and only mutate state after the transfers are staged so a transfer failure cannot leave inconsistent accounting.
  • Preserve the arbiter require_auth, the Disputed-state gate, the pause/emergency gate, and the dispute resolved event (extend the payload with the actual transferred amounts).
  • Apply this fix to the canonical resolve_dispute only; do not resurrect the duplicate definitions in dispute.rs.

Suggested execution

  • Fork the repo and create a branch
  • git checkout -b feature/contracts-dispute-payout-transfer
  • Implement changes
    • Write code in: contracts/escrow/src/lib.rs — add the two soroban_sdk::token transfers into resolve_dispute after the payout computation.
    • Write comprehensive tests in: contracts/escrow/src/test/dispute.rs — register a mock SAC, fund a disputed contract, and assert post-resolution token balance deltas for client and freelancer across FullRefund, PartialRefund, FullPayout, and Split.
    • Add documentation: update docs/escrow/ dispute notes to state that resolution settles on-chain.
    • Include NatSpec-style doc comments (///) on the changed entrypoint matching the existing style in lib.rs.
    • Validate security assumptions: no double-pay across repeated resolution, no overdraw beyond available balance, zero-transfer skipping, correct arbiter auth.
  • Test and commit

Test and commit

  • Run cargo fmt --all -- --check, cargo build, and cargo test.
  • Cover edge cases and failure paths: zero available balance, unconfigured settlement token, non-arbiter caller, and a non-Disputed contract.
  • Include the full cargo test output and a short security notes section in the PR description.

Example commit message

feat: transfer escrowed funds to client and freelancer on dispute resolution with tests

Guidelines

  • Minimum 95 percent test coverage for impacted modules.
  • Clear, reviewer-focused documentation.
  • Timeframe: 96 hours.

Community & contribution rewards

  • 💬 Join the TalentTrust community on Discord for questions, reviews, and faster merges: https://discord.gg/WqnGpcPx
  • ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.

Metadata

Metadata

Assignees

No one assigned

    Fields

    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions