Skip to content

feat: On-chain milestone arbitration — staked jurors resolve disputed rejections #1082

Description

@Anuoluwapo25

Summary

Build on-chain milestone arbitration — a Soroban module where a rejected scholar can escalate to a panel of LRN-staking jurors who vote on the dispute, with the escrow release bound to the outcome and stakes slashed for jurors who vote against the result. Appeals today are resolved by a single platform admin off-chain (server/src/controllers/milestone-appeal.controller.ts, resolveAppeal behind admin middleware), and milestone_escrow::release_tranche is admin-gated.

Background

LearnVault's pitch is "no gatekeepers" — but the single decision that determines whether a scholar gets paid is made by one admin, off-chain, with no appeal beyond that same admin. That is the most centralised point in the entire protocol and it sits directly on top of the money.

The platform already has the pieces this needs: LRN with a working balance model, governance voting patterns in the governance_token contract, and an escrow contract with tranche release. What is missing is a credibly neutral way to resolve a disagreement between a scholar and a reviewer.

Scope

Smart contract, backend, and frontend. The contract is the substance of this issue; the API and UI exist to make it usable. Reuse the existing escrow and token contracts rather than forking them.

What to build

1. Arbitration contract (contracts/milestone_arbitration/)

  • open_dispute(proposal_id, milestone_id, evidence_hash) — callable by the scholar within a bounded window after rejection, requiring a stake that is forfeited on a frivolous claim.
  • join_panel(juror) — jurors stake LRN to be eligible; selection is pseudo-random and weighted by stake, seeded from ledger data so it cannot be trivially ground by the caller.
  • commit_vote / reveal_vote — commit-reveal so early votes cannot anchor later ones. A juror who commits and never reveals is slashed.
  • resolve(dispute_id) — tallies revealed votes, slashes the minority and the non-revealers, distributes their stake to the majority and the winning party, and emits an event carrying the outcome.
  • Deadlines at every phase with a defined fallback if a phase never reaches quorum — a dispute that can hang forever is a dispute that holds the escrow hostage.
  • Full test.rs coverage in the style of the existing contracts, and an entry in the workspace Cargo.toml.

2. Escrow integration

  • milestone_escrow accepts an arbitration outcome as an authorisation path for release_tranche, alongside the existing admin path.
  • The arbitration contract address is set at initialisation and changeable only through the existing upgrade/timelock mechanism — not by a bare admin call.

3. Backend

  • Index the dispute lifecycle events into Postgres via the existing indexer (server/src/services/event-indexer.service.ts, server/src/lib/event-config.ts) so the UI reads a database rather than replaying the chain.
  • Migration for disputes, dispute_jurors, and dispute_votes; endpoints to list open disputes, fetch one, and list a juror's assignments.
  • Notify the scholar, the reviewer, and selected jurors at each phase change through the existing notification services — a commit-reveal scheme where jurors miss the reveal window because nobody told them will slash honest participants.
  • Evidence goes to IPFS through the existing pinata.service.ts; the chain stores the hash only.

4. Frontend

  • An escalate control on a rejected milestone, with the stake cost stated plainly before signing.
  • A juror console: available disputes, stake and join, review evidence, commit a vote, and a prominent reveal deadline with reminders.
  • A public dispute detail page showing phase, timers, vote tallies after reveal, and the final outcome with a link to the transaction.
  • Every wallet-signing step needs the usual pending/success/failure handling and a clear explanation of what is being signed and what is at risk.

5. Tests

  • Contract: full happy path; minority slashing; non-revealer slashing; quorum failure fallback; double-vote and double-join rejected; dispute opened outside the window rejected; only the scholar can open a dispute on their own milestone.
  • Juror selection is not predictable from caller-controlled input.
  • Escrow releases on a favourable outcome and does not on an unfavourable one.
  • Backend: indexer maps every dispute event to the right row; phase transitions notify the right parties.

Acceptance criteria

  • Arbitration contract with commit-reveal voting, staking, and slashing, fully tested
  • Escrow release can be authorised by an arbitration outcome
  • Arbitration address changeable only through the timelock path
  • Every phase is deadline-bounded with a defined quorum-failure fallback
  • Dispute events indexed into Postgres and exposed over the API
  • Scholars can escalate a rejection; jurors can stake, vote, and reveal from the UI
  • Reveal deadlines are surfaced with notifications, not just a timestamp
  • Evidence stored on IPFS with only the hash on-chain
  • cargo test --workspace and the frontend and server suites pass

Notes for contributors

  • This design has real economic edges. Say in the PR what stops a whale from staking enough to dominate panels, and what stops a scholar from opening disputes indefinitely. A defensible answer beats an elegant one.
  • Commit-reveal is easy to get subtly wrong. Salt the commitment per juror per dispute, and reject a reveal that does not match the commitment rather than silently ignoring it.
  • Do not put evidence text on-chain. Ledger storage is expensive and permanent, and dispute evidence is neither small nor something anyone should be unable to take down.
  • Discuss the parameter choices — stake sizes, panel size, phase lengths — in the issue before building. They are policy decisions, not implementation details.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third CampaignbackendAPI/database/infrastructureenhancementNew feature or requestfeatureNew feature implementationfrontendReact/TypeScript UI worksmart-contractSoroban/Rust contract work

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions