Source Code

;; dispute-resolution - Clarity 4
;; Decentralized dispute resolution for platform conflicts

(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-DISPUTE-NOT-FOUND (err u101))
(define-constant ERR-ALREADY-RESOLVED (err u102))
(define-constant ERR-INVALID-VOTE (err u103))
(define-constant ERR-VOTING-CLOSED (err u104))

(define-map disputes uint
  {
    plaintiff: principal,
    defendant: principal,
    dispute-type: (string-ascii 50),
    description: (string-utf8 500),
    evidence-hash: (buff 64),
    filed-at: uint,
    status: (string-ascii 20),
    resolution: (optional (string-utf8 500)),
    resolved-at: (optional uint)
  }
)

(define-map arbitrators principal
  {
    name: (string-utf8 100),
    specialization: (string-ascii 50),
    cases-resolved: uint,
    reputation-score: uint,
    is-active: bool
  }
)

(define-map dispute-votes { dispute-id: uint, arbitrator: principal }
  {
    vote: (string-ascii 20),
    reasoning: (string-utf8 500),
    voted-at: uint
  }
)

(define-map vote-tallies uint
  {
    votes-for-plaintiff: uint,
    votes-for-defendant: uint,
    total-votes: uint,
    voting-deadline: uint
  }
)

(define-map evidence-submissions uint
  {
    dispute-id: uint,
    submitter: principal,
    evidence-hash: (buff 64),
    evidence-type: (string-ascii 50),
    submitted-at: uint
  }
)

(define-data-var dispute-counter uint u0)
(define-data-var evidence-counter uint u0)
(define-data-var voting-period uint u604800) ;; 7 days

(define-public (file-dispute
    (defendant principal)
    (dispute-type (string-ascii 50))
    (description (string-utf8 500))
    (evidence-hash (buff 64)))
  (let ((dispute-id (+ (var-get dispute-counter) u1)))
    (map-set disputes dispute-id
      {
        plaintiff: tx-sender,
        defendant: defendant,
        dispute-type: dispute-type,
        description: description,
        evidence-hash: evidence-hash,
        filed-at: stacks-block-time,
        status: "open",
        resolution: none,
        resolved-at: none
      })
    (map-set vote-tallies dispute-id
      {
        votes-for-plaintiff: u0,
        votes-for-defendant: u0,
        total-votes: u0,
        voting-deadline: (+ stacks-block-time (var-get voting-period))
      })
    (var-set dispute-counter dispute-id)
    (ok dispute-id)))

(define-public (register-arbitrator
    (name (string-utf8 100))
    (specialization (string-ascii 50)))
  (ok (map-set arbitrators tx-sender
    {
      name: name,
      specialization: specialization,
      cases-resolved: u0,
      reputation-score: u50,
      is-active: true
    })))

(define-public (cast-vote
    (dispute-id uint)
    (vote (string-ascii 20))
    (reasoning (string-utf8 500)))
  (let ((dispute (unwrap! (map-get? disputes dispute-id) ERR-DISPUTE-NOT-FOUND))
        (arbitrator (unwrap! (map-get? arbitrators tx-sender) ERR-NOT-AUTHORIZED))
        (tally (unwrap! (map-get? vote-tallies dispute-id) ERR-DISPUTE-NOT-FOUND)))
    (asserts! (get is-active arbitrator) ERR-NOT-AUTHORIZED)
    (asserts! (is-eq (get status dispute) "open") ERR-ALREADY-RESOLVED)
    (asserts! (< stacks-block-time (get voting-deadline tally)) ERR-VOTING-CLOSED)
    (map-set dispute-votes { dispute-id: dispute-id, arbitrator: tx-sender }
      {
        vote: vote,
        reasoning: reasoning,
        voted-at: stacks-block-time
      })
    (try! (update-vote-tally dispute-id vote))
    (ok true)))

(define-public (submit-evidence
    (dispute-id uint)
    (evidence-hash (buff 64))
    (evidence-type (string-ascii 50)))
  (let ((dispute (unwrap! (map-get? disputes dispute-id) ERR-DISPUTE-NOT-FOUND))
        (evidence-id (+ (var-get evidence-counter) u1)))
    (asserts! (or (is-eq tx-sender (get plaintiff dispute))
                  (is-eq tx-sender (get defendant dispute))) ERR-NOT-AUTHORIZED)
    (map-set evidence-submissions evidence-id
      {
        dispute-id: dispute-id,
        submitter: tx-sender,
        evidence-hash: evidence-hash,
        evidence-type: evidence-type,
        submitted-at: stacks-block-time
      })
    (var-set evidence-counter evidence-id)
    (ok evidence-id)))

(define-public (resolve-dispute
    (dispute-id uint)
    (resolution (string-utf8 500)))
  (let ((dispute (unwrap! (map-get? disputes dispute-id) ERR-DISPUTE-NOT-FOUND))
        (tally (unwrap! (map-get? vote-tallies dispute-id) ERR-DISPUTE-NOT-FOUND)))
    (asserts! (>= stacks-block-time (get voting-deadline tally)) ERR-VOTING-CLOSED)
    (asserts! (is-eq (get status dispute) "open") ERR-ALREADY-RESOLVED)
    (ok (map-set disputes dispute-id
      (merge dispute {
        status: "resolved",
        resolution: (some resolution),
        resolved-at: (some stacks-block-time)
      })))))

(define-private (update-vote-tally (dispute-id uint) (vote (string-ascii 20)))
  (let ((tally (unwrap! (map-get? vote-tallies dispute-id) ERR-DISPUTE-NOT-FOUND)))
    (map-set vote-tallies dispute-id
      (merge tally {
        votes-for-plaintiff: (if (is-eq vote "plaintiff")
                                (+ (get votes-for-plaintiff tally) u1)
                                (get votes-for-plaintiff tally)),
        votes-for-defendant: (if (is-eq vote "defendant")
                                (+ (get votes-for-defendant tally) u1)
                                (get votes-for-defendant tally)),
        total-votes: (+ (get total-votes tally) u1)
      }))
    (ok true)))

(define-read-only (get-dispute (dispute-id uint))
  (ok (map-get? disputes dispute-id)))

(define-read-only (get-arbitrator (arbitrator principal))
  (ok (map-get? arbitrators arbitrator)))

(define-read-only (get-vote (dispute-id uint) (arbitrator principal))
  (ok (map-get? dispute-votes { dispute-id: dispute-id, arbitrator: arbitrator })))

(define-read-only (get-vote-tally (dispute-id uint))
  (ok (map-get? vote-tallies dispute-id)))

(define-read-only (get-evidence (evidence-id uint))
  (ok (map-get? evidence-submissions evidence-id)))

(define-read-only (validate-principal (p principal))
  (principal-destruct? p))

(define-read-only (format-dispute-id (dispute-id uint))
  (ok (int-to-ascii dispute-id)))

(define-read-only (parse-dispute-id (id-str (string-ascii 20)))
  (string-to-uint? id-str))

(define-read-only (get-bitcoin-block)
  (ok burn-block-height))

Functions (15)

FunctionAccessArgs
file-disputepublicdefendant: principal, dispute-type: (string-ascii 50
register-arbitratorpublicname: (string-utf8 100
cast-votepublicdispute-id: uint, vote: (string-ascii 20
submit-evidencepublicdispute-id: uint, evidence-hash: (buff 64
resolve-disputepublicdispute-id: uint, resolution: (string-utf8 500
update-vote-tallyprivatedispute-id: uint, vote: (string-ascii 20
get-disputeread-onlydispute-id: uint
get-arbitratorread-onlyarbitrator: principal
get-voteread-onlydispute-id: uint, arbitrator: principal
get-vote-tallyread-onlydispute-id: uint
get-evidenceread-onlyevidence-id: uint
validate-principalread-onlyp: principal
format-dispute-idread-onlydispute-id: uint
parse-dispute-idread-onlyid-str: (string-ascii 20
get-bitcoin-blockread-only