Source Code

;; genome-provenance - Clarity 4
;; Track chain of custody for genomic data

(define-constant ERR-EVENT-NOT-FOUND (err u100))
(define-constant ERR-NOT-AUTHORIZED (err u101))
(define-constant ERR-INVALID-CHAIN (err u102))

(define-map provenance-events uint
  {
    data-id: uint,
    actor: principal,
    action: (string-ascii 50),
    timestamp: uint,
    location: (string-ascii 100),
    previous-event-id: (optional uint),
    metadata-hash: (buff 64),
    verified: bool
  }
)

(define-map custody-chains uint
  {
    data-id: uint,
    chain-start: uint,
    chain-length: uint,
    current-custodian: principal,
    last-transfer: uint,
    is-complete: bool
  }
)

(define-map transfer-records uint
  {
    data-id: uint,
    from-party: principal,
    to-party: principal,
    transfer-reason: (string-utf8 300),
    transfer-date: uint,
    approval-required: bool,
    approved-by: (optional principal)
  }
)

(define-map data-lineage uint
  {
    data-id: uint,
    parent-data-id: (optional uint),
    derivation-method: (string-ascii 100),
    created-at: uint,
    created-by: principal,
    lineage-depth: uint
  }
)

(define-map provenance-attestations uint
  {
    event-id: uint,
    attestor: principal,
    attestation-type: (string-ascii 50),
    attestation-data: (buff 128),
    attested-at: uint,
    is-valid: bool
  }
)

(define-map integrity-checks uint
  {
    data-id: uint,
    check-type: (string-ascii 50),
    expected-hash: (buff 64),
    actual-hash: (buff 64),
    matches: bool,
    checked-at: uint,
    checked-by: principal
  }
)

(define-data-var event-counter uint u0)
(define-data-var chain-counter uint u0)
(define-data-var transfer-counter uint u0)
(define-data-var lineage-counter uint u0)
(define-data-var attestation-counter uint u0)
(define-data-var check-counter uint u0)

(define-public (log-event
    (data-id uint)
    (action (string-ascii 50))
    (location (string-ascii 100))
    (previous-event-id (optional uint))
    (metadata-hash (buff 64)))
  (let ((event-id (+ (var-get event-counter) u1)))
    (map-set provenance-events event-id
      {
        data-id: data-id,
        actor: tx-sender,
        action: action,
        timestamp: stacks-block-time,
        location: location,
        previous-event-id: previous-event-id,
        metadata-hash: metadata-hash,
        verified: false
      })
    (var-set event-counter event-id)
    (ok event-id)))

(define-public (initialize-custody-chain
    (data-id uint))
  (let ((custody-chain-id (+ (var-get chain-counter) u1))
        (event-id (var-get event-counter)))
    (map-set custody-chains custody-chain-id
      {
        data-id: data-id,
        chain-start: event-id,
        chain-length: u1,
        current-custodian: tx-sender,
        last-transfer: stacks-block-time,
        is-complete: false
      })
    (var-set chain-counter custody-chain-id)
    (ok custody-chain-id)))

(define-public (transfer-custody
    (data-id uint)
    (to-party principal)
    (transfer-reason (string-utf8 300))
    (approval-required bool))
  (let ((transfer-id (+ (var-get transfer-counter) u1)))
    (map-set transfer-records transfer-id
      {
        data-id: data-id,
        from-party: tx-sender,
        to-party: to-party,
        transfer-reason: transfer-reason,
        transfer-date: stacks-block-time,
        approval-required: approval-required,
        approved-by: (if approval-required none (some tx-sender))
      })
    (var-set transfer-counter transfer-id)
    (ok transfer-id)))

(define-public (record-data-lineage
    (data-id uint)
    (parent-data-id (optional uint))
    (derivation-method (string-ascii 100))
    (lineage-depth uint))
  (let ((lineage-id (+ (var-get lineage-counter) u1)))
    (map-set data-lineage lineage-id
      {
        data-id: data-id,
        parent-data-id: parent-data-id,
        derivation-method: derivation-method,
        created-at: stacks-block-time,
        created-by: tx-sender,
        lineage-depth: lineage-depth
      })
    (var-set lineage-counter lineage-id)
    (ok lineage-id)))

(define-public (attest-provenance
    (event-id uint)
    (attestation-type (string-ascii 50))
    (attestation-data (buff 128)))
  (let ((attestation-id (+ (var-get attestation-counter) u1)))
    (asserts! (is-some (map-get? provenance-events event-id)) ERR-EVENT-NOT-FOUND)
    (map-set provenance-attestations attestation-id
      {
        event-id: event-id,
        attestor: tx-sender,
        attestation-type: attestation-type,
        attestation-data: attestation-data,
        attested-at: stacks-block-time,
        is-valid: true
      })
    (var-set attestation-counter attestation-id)
    (ok attestation-id)))

(define-public (verify-integrity
    (data-id uint)
    (check-type (string-ascii 50))
    (expected-hash (buff 64))
    (actual-hash (buff 64)))
  (let ((check-id (+ (var-get check-counter) u1))
        (matches (is-eq expected-hash actual-hash)))
    (map-set integrity-checks check-id
      {
        data-id: data-id,
        check-type: check-type,
        expected-hash: expected-hash,
        actual-hash: actual-hash,
        matches: matches,
        checked-at: stacks-block-time,
        checked-by: tx-sender
      })
    (var-set check-counter check-id)
    (ok check-id)))

(define-public (complete-custody-chain (custody-chain-id uint))
  (let ((chain (unwrap! (map-get? custody-chains custody-chain-id) ERR-INVALID-CHAIN)))
    (asserts! (is-eq tx-sender (get current-custodian chain)) ERR-NOT-AUTHORIZED)
    (ok (map-set custody-chains custody-chain-id
      (merge chain { is-complete: true })))))

(define-read-only (get-event (event-id uint))
  (ok (map-get? provenance-events event-id)))

(define-read-only (get-custody-chain (custody-chain-id uint))
  (ok (map-get? custody-chains custody-chain-id)))

(define-read-only (get-transfer-record (transfer-id uint))
  (ok (map-get? transfer-records transfer-id)))

(define-read-only (get-data-lineage (lineage-id uint))
  (ok (map-get? data-lineage lineage-id)))

(define-read-only (get-attestation (attestation-id uint))
  (ok (map-get? provenance-attestations attestation-id)))

(define-read-only (get-integrity-check (check-id uint))
  (ok (map-get? integrity-checks check-id)))

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

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

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

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

Functions (17)

FunctionAccessArgs
log-eventpublicdata-id: uint, action: (string-ascii 50
initialize-custody-chainpublicdata-id: uint
transfer-custodypublicdata-id: uint, to-party: principal, transfer-reason: (string-utf8 300
record-data-lineagepublicdata-id: uint, parent-data-id: (optional uint
attest-provenancepublicevent-id: uint, attestation-type: (string-ascii 50
verify-integritypublicdata-id: uint, check-type: (string-ascii 50
complete-custody-chainpubliccustody-chain-id: uint
get-eventread-onlyevent-id: uint
get-custody-chainread-onlycustody-chain-id: uint
get-transfer-recordread-onlytransfer-id: uint
get-data-lineageread-onlylineage-id: uint
get-attestationread-onlyattestation-id: uint
get-integrity-checkread-onlycheck-id: uint
validate-actorread-onlyactor: principal
format-event-idread-onlyevent-id: uint
parse-event-idread-onlyid-str: (string-ascii 20
get-bitcoin-blockread-only