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.
Transfer escrowed funds on dispute resolution in resolve_dispute
Description
resolve_disputeincontracts/escrow/src/lib.rscomputes(client_payout, freelancer_payout)viadispute::resolution_payouts, mutatescontract.refunded_amountandcontract.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 atoken::Client::transferfrom the contract's escrow balance;resolve_disputeis 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_payouttocontract.clientandfreelancer_payouttocontract.freelancerfrom the bound settlement token, atomically with the accounting update.Requirements and context
Self::read_settlement_token(&env)and resolve to a typed error (SettlementTokenNotConfigured) rather than a hostexpectpanic if unset.resolution_payoutsreturns, transferclient_payouttocontract.clientandfreelancer_payouttocontract.freelancer, skipping zero-value transfers.released + refunded == funded) and only mutate state after the transfers are staged so a transfer failure cannot leave inconsistent accounting.require_auth, theDisputed-state gate, the pause/emergency gate, and thedispute resolvedevent (extend the payload with the actual transferred amounts).resolve_disputeonly; do not resurrect the duplicate definitions indispute.rs.Suggested execution
git checkout -b feature/contracts-dispute-payout-transfercontracts/escrow/src/lib.rs— add the twosoroban_sdk::tokentransfers intoresolve_disputeafter the payout computation.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.docs/escrow/dispute notes to state that resolution settles on-chain.///) on the changed entrypoint matching the existing style inlib.rs.Test and commit
cargo fmt --all -- --check,cargo build, andcargo test.cargo testoutput 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 testsGuidelines
Community & contribution rewards