This document details the dispute resolution lifecycle in Trustchain Escrow. It covers how disputes are initiated, how evidence is anchored on-chain and IPFS, arbiter evaluation workflows, percentage-based fund settlements, and reputation impacts.
- Overview
- Dispute Prerequisites & Eligibility
- Initiating a Dispute
- Evidence Submission and Hashing
- Arbiter Workflow & Evaluation
- Ruling & Fund Distribution
- Reputation Impact
- Sequence Diagram
- Cross-References
When a disagreement arises over milestone deliverables, either the Client or the Contractor can flag the escrow as Disputed. Placing an escrow in the Disputed state freezes all unreleased funds and transfers settlement authority exclusively to the designated Arbiter (or contract admin if no arbiter was specified).
A dispute can be raised if and only if:
- The escrow status is currently
Active. - The caller is either the
clientor thefreelancerassociated with the escrow. - Unreleased funds remain locked in the escrow contract balance.
Once raised, standard milestone approvals (approve_milestone) are blocked until the arbiter issues a ruling.
A participant initiates a dispute by invoking raise_dispute on the Soroban escrow contract (contracts/escrow_contract/src/lib.rs):
pub fn raise_dispute(
env: Env,
caller: Address,
escrow_id: u64,
evidence_hash: BytesN<32>,
) -> Result<(), EscrowError>- Validates
callersignature matchesclientorfreelancer. - Updates
EscrowState.statusfromActivetoDisputed. - Stores
evidence_hashon-chain. - Emits a
DisputeRaisedcontract event.
Disputes can also be raised via the backend API:
POST /api/v1/escrows/42/dispute
Authorization: Bearer <USER_JWT>
Content-Type: application/json
{
"reason": "Deliverable fails performance criteria outlined in brief",
"evidenceFiles": [
{
"name": "benchmark_results.json",
"ipfsHash": "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG"
}
]
}To ensure evidence cannot be tampered with after a dispute is initiated:
- Evidence files (chat logs, test reports, deliverables) are pinned to IPFS.
- The SHA-256 digest of the combined evidence manifest is generated:
$$\text{EvidenceHash} = \text{SHA-256}(\text{IPFS_CID}_1 \parallel \text{IPFS_CID}_2 \parallel \dots)$$ - The 32-byte hash is permanently anchored in the Soroban contract state and indexed by Elasticsearch for arbiter review.
The arbiter is specified during create_escrow. The arbiter serves as an independent, neutral judge:
- Authorized Actions: The arbiter (or contract admin fallback) is the only address authorized to invoke
resolve_dispute. - Review Period: Arbiters review the statement of work, milestone deliverables, and submitted evidence hashes.
When a dispute is raised, the backend dispatches signed webhooks (escrow.disputed) to subscribed arbiters and sends notifications to the web dashboard.
The arbiter resolves the dispute by issuing a percentage-based split ruling between the client and contractor:
pub fn resolve_dispute(
env: Env,
arbiter: Address,
escrow_id: u64,
client_share_bps: u32, // Basis points (0 to 10,000)
contractor_share_bps: u32, // Basis points (0 to 10,000)
) -> Result<(), EscrowError>Basis points constraint:
client_share_bps + contractor_share_bps == 10_000(representing 100%).
Or via REST API:
POST /api/v1/escrows/42/resolve
Authorization: Bearer <ARBITER_JWT>
Content-Type: application/json
{
"clientShareBps": 3000,
"contractorShareBps": 7000,
"rulingRationale": "Contractor delivered 70% of functional requirements before conflict."
}For an unreleased balance of 1,000 XLM (
| Ruling Scenario | clientShareBps |
contractorShareBps |
Client Refund | Contractor Payout |
|---|---|---|---|---|
| Full Contractor Win | 0 (0%) | 10,000 (100%) | 0 XLM | 1,000 XLM |
| Full Client Refund | 10,000 (100%) | 0 (0%) | 1,000 XLM | 0 XLM |
| Partial Split (70/30) | 3,000 (30%) | 7,000 (70%) | 300 XLM | 700 XLM |
Once resolve_dispute executes:
- Funds are transferred instantly per the specified basis point breakdown.
- The escrow state transitions to
Completed. - A
ReputationEventis recorded on-chain:- If
contractor_share_bps >= 5000, contractor gets a positive outcome event. - If
client_share_bps > 5000, client gets a positive dispute resolution event. - Reputation indexes update automatically via background indexer services.
- If
Participant (Client/Contractor) Soroban Escrow Contract Arbiter Backend Indexer
│ │ │ │
│─── raise_dispute(evidence_hash) ──────────►│ │ │
│ │── Update Status: Disputed│ │
│ │── Emit DisputeRaised ────┼───────────────────────►│
│ │ │ ├─ Notify Arbiter
│ │ │◄── Review Evidence ────┤
│ │◄─ resolve_dispute(bps) ──│ │
│ │ │ │
│◄──────── Transfer Client Share ────────────│ │ │
│───────── Transfer Contractor Share ───────►│ │ │
│ │── Emit DisputeResolved ──┼───────────────────────►│
│ │ │ ├─ Update Reputation DB
- Arbiter Role Guide — Detailed guide on arbiter selection and permissions.
- Escrow Creation and Release Flow — Standard non-disputed escrow flow.
- Reputation Scoring Documentation — Mathematical formula for reputation score adjustments.
- Slashing Mechanism — Malicious dispute penalties and stake slashing rules.