Source Code

;; genome-sharing - Clarity 4
;; Secure sharing of genomic data between parties

(define-constant ERR-SHARE-NOT-FOUND (err u100))
(define-constant ERR-NOT-AUTHORIZED (err u101))
(define-constant ERR-SHARE-EXPIRED (err u102))
(define-constant ERR-ALREADY-REVOKED (err u103))

(define-map shares uint
  {
    owner: principal,
    recipient: principal,
    data-ref: uint,
    shared-at: uint,
    expires-at: uint,
    is-active: bool,
    access-level: (string-ascii 20),
    usage-purpose: (string-utf8 200),
    consent-given: bool
  }
)

(define-map share-access-logs uint
  {
    share-id: uint,
    accessor: principal,
    accessed-at: uint,
    action: (string-ascii 50),
    data-retrieved: (buff 32)
  }
)

(define-map sharing-agreements uint
  {
    share-id: uint,
    terms: (string-utf8 500),
    data-usage-restrictions: (list 10 (string-ascii 50)),
    agreed-at: uint,
    agreement-hash: (buff 64)
  }
)

(define-map recipient-groups uint
  {
    group-name: (string-utf8 100),
    owner: principal,
    members: (list 20 principal),
    default-access-level: (string-ascii 20),
    created-at: uint,
    is-active: bool
  }
)

(define-map sharing-notifications uint
  {
    share-id: uint,
    recipient: principal,
    notification-type: (string-ascii 50),
    message: (string-utf8 300),
    sent-at: uint,
    read: bool
  }
)

(define-data-var share-counter uint u0)
(define-data-var access-log-counter uint u0)
(define-data-var agreement-counter uint u0)
(define-data-var group-counter uint u0)
(define-data-var notification-counter uint u0)

(define-public (create-share
    (recipient principal)
    (data-ref uint)
    (expiration uint)
    (access-level (string-ascii 20))
    (usage-purpose (string-utf8 200))
    (consent-given bool))
  (let ((share-id (+ (var-get share-counter) u1)))
    (map-set shares share-id
      {
        owner: tx-sender,
        recipient: recipient,
        data-ref: data-ref,
        shared-at: stacks-block-time,
        expires-at: expiration,
        is-active: true,
        access-level: access-level,
        usage-purpose: usage-purpose,
        consent-given: consent-given
      })
    (var-set share-counter share-id)
    (ok share-id)))

(define-public (revoke-share (share-id uint))
  (let ((share (unwrap! (map-get? shares share-id) ERR-SHARE-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get owner share)) ERR-NOT-AUTHORIZED)
    (asserts! (get is-active share) ERR-ALREADY-REVOKED)
    (ok (map-set shares share-id
      (merge share { is-active: false })))))

(define-public (log-share-access
    (share-id uint)
    (action (string-ascii 50))
    (data-retrieved (buff 32)))
  (let ((log-id (+ (var-get access-log-counter) u1))
        (share (unwrap! (map-get? shares share-id) ERR-SHARE-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get recipient share)) ERR-NOT-AUTHORIZED)
    (asserts! (get is-active share) ERR-ALREADY-REVOKED)
    (map-set share-access-logs log-id
      {
        share-id: share-id,
        accessor: tx-sender,
        accessed-at: stacks-block-time,
        action: action,
        data-retrieved: data-retrieved
      })
    (var-set access-log-counter log-id)
    (ok log-id)))

(define-public (create-sharing-agreement
    (share-id uint)
    (terms (string-utf8 500))
    (data-usage-restrictions (list 10 (string-ascii 50)))
    (agreement-hash (buff 64)))
  (let ((agreement-id (+ (var-get agreement-counter) u1)))
    (asserts! (is-some (map-get? shares share-id)) ERR-SHARE-NOT-FOUND)
    (map-set sharing-agreements agreement-id
      {
        share-id: share-id,
        terms: terms,
        data-usage-restrictions: data-usage-restrictions,
        agreed-at: stacks-block-time,
        agreement-hash: agreement-hash
      })
    (var-set agreement-counter agreement-id)
    (ok agreement-id)))

(define-public (create-recipient-group
    (group-name (string-utf8 100))
    (members (list 20 principal))
    (default-access-level (string-ascii 20)))
  (let ((group-id (+ (var-get group-counter) u1)))
    (map-set recipient-groups group-id
      {
        group-name: group-name,
        owner: tx-sender,
        members: members,
        default-access-level: default-access-level,
        created-at: stacks-block-time,
        is-active: true
      })
    (var-set group-counter group-id)
    (ok group-id)))

(define-read-only (get-share (share-id uint))
  (ok (map-get? shares share-id)))

(define-read-only (get-access-log (log-id uint))
  (ok (map-get? share-access-logs log-id)))

(define-read-only (get-agreement (agreement-id uint))
  (ok (map-get? sharing-agreements agreement-id)))

(define-read-only (get-recipient-group (group-id uint))
  (ok (map-get? recipient-groups group-id)))

(define-read-only (is-share-active (share-id uint))
  (let ((share (map-get? shares share-id)))
    (ok (if (is-some share)
            (let ((s (unwrap-panic share)))
              (and
                (get is-active s)
                (> (get expires-at s) stacks-block-time)))
            false))))

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

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

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

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

Functions (14)

FunctionAccessArgs
create-sharepublicrecipient: principal, data-ref: uint, expiration: uint, access-level: (string-ascii 20
revoke-sharepublicshare-id: uint
log-share-accesspublicshare-id: uint, action: (string-ascii 50
create-sharing-agreementpublicshare-id: uint, terms: (string-utf8 500
create-recipient-grouppublicgroup-name: (string-utf8 100
get-shareread-onlyshare-id: uint
get-access-logread-onlylog-id: uint
get-agreementread-onlyagreement-id: uint
get-recipient-groupread-onlygroup-id: uint
is-share-activeread-onlyshare-id: uint
validate-recipientread-onlyrecipient: principal
format-share-idread-onlyshare-id: uint
parse-share-idread-onlyid-str: (string-ascii 20
get-bitcoin-blockread-only