Source Code

;; title: vaccine-batch-monitor
;; version:
;; summary:
;; description:
;; Vaccine Tracking Smart Contract

;; Contract Owner Management
(define-data-var immunization-system-controller principal tx-sender)

;; Error Codes
(define-constant AUTHORIZATION-ERROR (err u100))
(define-constant INVALID-VACCINE-SHIPMENT (err u101))
(define-constant DUPLICATE-SHIPMENT-ERROR (err u102))
(define-constant SHIPMENT-NOT-FOUND-ERROR (err u103))
(define-constant VACCINE-SUPPLY-DEPLETED (err u104))
(define-constant INVALID-RECIPIENT-ID (err u105))
(define-constant DUPLICATE-IMMUNIZATION (err u106))
(define-constant COLD-CHAIN-BREACH (err u107))
(define-constant EXPIRED-VACCINE-ERROR (err u108))
(define-constant INVALID-CLINIC-LOCATION (err u109))
(define-constant IMMUNIZATION-LIMIT-REACHED (err u110))
(define-constant MINIMUM-INTERVAL-VIOLATION (err u111))
(define-constant ADMIN-PRIVILEGES-REQUIRED (err u112))
(define-constant DATA-VALIDATION-ERROR (err u113))
(define-constant EXPIRY-DATE-ERROR (err u114))
(define-constant STORAGE-CAPACITY-ERROR (err u115))
(define-constant CLINICIAN-ALREADY-REGISTERED (err u116))

;; Constants
(define-constant COLD-CHAIN-MINIMUM-TEMP (- 70))
(define-constant COLD-CHAIN-MAXIMUM-TEMP 8)
(define-constant DOSE-INTERVAL-REQUIREMENT u21) ;; 21 days minimum between doses
(define-constant MAXIMUM-IMMUNIZATION-SERIES u4)
(define-constant MINIMUM-ENTRY-LENGTH u1)
(define-constant CURRENT-CHAIN-HEIGHT stacks-block-height)

;; Data Maps
(define-map vaccine-shipment-registry
  { shipment-id: (string-ascii 32) }
  {
    manufacturer-details: (string-ascii 50),
    vaccine-brand-name: (string-ascii 50),
    production-timestamp: uint,
    expiration-timestamp: uint,
    available-unit-count: uint,
    storage-temp-celsius: int,
    shipment-status: (string-ascii 20),
    temp-violation-incidents: uint,
    storage-facility-id: (string-ascii 100),
    shipment-notes: (string-ascii 500),
  }
)

(define-map immunization-registry
  { recipient-id: (string-ascii 32) }
  {
    immunization-sequence: (list
      10
      {
        shipment-reference: (string-ascii 32),
        administration-timestamp: uint,
        vaccine-formulation: (string-ascii 50),
        sequence-number: uint,
        administering-clinician: principal,
        clinic-location: (string-ascii 100),
        next-dose-due-date: (optional uint),
      }
    ),
    completed-immunizations: uint,
    adverse-event-reports: (list 5 (string-ascii 200)),
    medical-exemption: (optional (string-ascii 200)),
  }
)

(define-map authorized-clinicians
  principal
  {
    clinical-role: (string-ascii 20),
    clinic-name: (string-ascii 100),
    credentials-valid-until: uint,
  }
)

(define-map cold-chain-facilities
  (string-ascii 100)
  {
    facility-location: (string-ascii 200),
    max-storage-units: uint,
    current-unit-count: uint,
    temperature-monitoring: (list 100 {
      monitoring-timestamp: uint,
      recorded-temp-celsius: int,
    }),
  }
)

;; Private Functions
(define-private (is-system-controller)
  (is-eq tx-sender (var-get immunization-system-controller))
)

;; String validation functions
(define-private (validate-identifier (input (string-ascii 32)))
  (> (len input) MINIMUM-ENTRY-LENGTH)
)

(define-private (validate-name-field (input (string-ascii 50)))
  (> (len input) MINIMUM-ENTRY-LENGTH)
)

(define-private (validate-location-field (input (string-ascii 100)))
  (> (len input) MINIMUM-ENTRY-LENGTH)
)

(define-private (validate-description-field (input (string-ascii 200)))
  (> (len input) MINIMUM-ENTRY-LENGTH)
)

(define-private (validate-future-date (input-date uint))
  (> input-date CURRENT-CHAIN-HEIGHT)
)

(define-private (validate-storage-limit (proposed-limit uint))
  (> proposed-limit u0)
)

;; Read-only Functions
(define-read-only (get-system-controller)
  (ok (var-get immunization-system-controller))
)

(define-read-only (verify-clinician-status (clinician-address principal))
  (match (map-get? authorized-clinicians clinician-address)
    clinician-data (>= (get credentials-valid-until clinician-data) CURRENT-CHAIN-HEIGHT)
    false
  )
)

;; Public Functions
(define-public (transfer-system-control (new-controller principal))
  (begin
    (asserts! (is-system-controller) ADMIN-PRIVILEGES-REQUIRED)
    (asserts! (is-some (map-get? authorized-clinicians new-controller))
      AUTHORIZATION-ERROR
    )
    (ok (var-set immunization-system-controller new-controller))
  )
)

(define-public (register-clinician
    (clinician-address principal)
    (role (string-ascii 20))
    (facility-name (string-ascii 100))
    (credential-expiry uint)
  )
  (begin
    (asserts! (is-system-controller) AUTHORIZATION-ERROR)
    (asserts! (is-none (map-get? authorized-clinicians clinician-address))
      CLINICIAN-ALREADY-REGISTERED
    )
    (asserts! (validate-identifier role) DATA-VALIDATION-ERROR)
    (asserts! (validate-location-field facility-name) DATA-VALIDATION-ERROR)
    (asserts! (validate-future-date credential-expiry) EXPIRY-DATE-ERROR)
    (ok (map-set authorized-clinicians clinician-address {
      clinical-role: role,
      clinic-name: facility-name,
      credentials-valid-until: credential-expiry,
    }))
  )
)

(define-public (register-storage-facility
    (facility-id (string-ascii 100))
    (location-address (string-ascii 200))
    (storage-capacity uint)
  )
  (begin
    (asserts! (is-system-controller) AUTHORIZATION-ERROR)
    (asserts! (validate-location-field facility-id) DATA-VALIDATION-ERROR)
    (asserts! (validate-description-field location-address) DATA-VALIDATION-ERROR)
    (asserts! (validate-storage-limit storage-capacity) STORAGE-CAPACITY-ERROR)
    (ok (map-set cold-chain-facilities facility-id {
      facility-location: location-address,
      max-storage-units: storage-capacity,
      current-unit-count: u0,
      temperature-monitoring: (list),
    }))
  )
)

(define-public (register-vaccine-shipment
    (shipment-id (string-ascii 32))
    (manufacturer (string-ascii 50))
    (brand-name (string-ascii 50))
    (production-date uint)
    (expiry-date uint)
    (dose-quantity uint)
    (storage-temp int)
    (facility-id (string-ascii 100))
  )
  (begin
    (asserts! (verify-clinician-status tx-sender) AUTHORIZATION-ERROR)
    (asserts! (validate-identifier shipment-id) DATA-VALIDATION-ERROR)
    (asserts! (validate-name-field manufacturer) DATA-VALIDATION-ERROR)
    (asserts! (validate-name-field brand-name) DATA-VALIDATION-ERROR)
    (asserts! (validate-location-field facility-id) DATA-VALIDATION-ERROR)
    (asserts!
      (is-none (map-get? vaccine-shipment-registry { shipment-id: shipment-id }))
      DUPLICATE-SHIPMENT-ERROR
    )
    (asserts! (validate-storage-limit dose-quantity) INVALID-VACCINE-SHIPMENT)
    (asserts! (validate-future-date expiry-date) EXPIRY-DATE-ERROR)
    (asserts! (> expiry-date production-date) INVALID-VACCINE-SHIPMENT)
    (asserts!
      (and
        (>= storage-temp COLD-CHAIN-MINIMUM-TEMP)
        (<= storage-temp COLD-CHAIN-MAXIMUM-TEMP)
      )
      COLD-CHAIN-BREACH
    )

    (ok (map-set vaccine-shipment-registry { shipment-id: shipment-id } {
      manufacturer-details: manufacturer,
      vaccine-brand-name: brand-name,
      production-timestamp: production-date,
      expiration-timestamp: expiry-date,
      available-unit-count: dose-quantity,
      storage-temp-celsius: storage-temp,
      shipment-status: "active",
      temp-violation-incidents: u0,
      storage-facility-id: facility-id,
      shipment-notes: "",
    }))
  )
)

(define-public (update-shipment-status
    (shipment-id (string-ascii 32))
    (new-status (string-ascii 20))
  )
  (begin
    (asserts! (verify-clinician-status tx-sender) AUTHORIZATION-ERROR)
    (asserts! (validate-identifier shipment-id) DATA-VALIDATION-ERROR)
    (asserts! (validate-identifier new-status) DATA-VALIDATION-ERROR)
    (match (map-get? vaccine-shipment-registry { shipment-id: shipment-id })
      shipment-data (ok (map-set vaccine-shipment-registry { shipment-id: shipment-id }
        (merge shipment-data { shipment-status: new-status })
      ))
      SHIPMENT-NOT-FOUND-ERROR
    )
  )
)

(define-public (record-temperature-violation
    (shipment-id (string-ascii 32))
    (violation-temp int)
  )
  (begin
    (asserts! (verify-clinician-status tx-sender) AUTHORIZATION-ERROR)
    (asserts! (validate-identifier shipment-id) DATA-VALIDATION-ERROR)
    (match (map-get? vaccine-shipment-registry { shipment-id: shipment-id })
      shipment-data (ok (map-set vaccine-shipment-registry { shipment-id: shipment-id }
        (merge shipment-data {
          temp-violation-incidents: (+ (get temp-violation-incidents shipment-data) u1),
          shipment-status: (if (> (get temp-violation-incidents shipment-data) u2)
            "compromised"
            (get shipment-status shipment-data)
          ),
        })
      ))
      SHIPMENT-NOT-FOUND-ERROR
    )
  )
)

(define-public (record-immunization
    (recipient-id (string-ascii 32))
    (shipment-id (string-ascii 32))
    (clinic-location (string-ascii 100))
  )
  (begin
    (asserts! (verify-clinician-status tx-sender) AUTHORIZATION-ERROR)
    (asserts! (validate-identifier recipient-id) INVALID-RECIPIENT-ID)
    (asserts! (validate-identifier shipment-id) DATA-VALIDATION-ERROR)
    (asserts! (validate-location-field clinic-location) INVALID-CLINIC-LOCATION)

    (match (map-get? vaccine-shipment-registry { shipment-id: shipment-id })
      shipment-data (begin
        (asserts! (> (get available-unit-count shipment-data) u0)
          VACCINE-SUPPLY-DEPLETED
        )
        (asserts! (is-eq (get shipment-status shipment-data) "active")
          INVALID-VACCINE-SHIPMENT
        )
        (asserts!
          (<= CURRENT-CHAIN-HEIGHT (get expiration-timestamp shipment-data))
          EXPIRED-VACCINE-ERROR
        )

        (match (map-get? immunization-registry { recipient-id: recipient-id })
          recipient-record
          (begin
            (asserts!
              (< (get completed-immunizations recipient-record)
                MAXIMUM-IMMUNIZATION-SERIES
              )
              IMMUNIZATION-LIMIT-REACHED
            )
            (let ((current-dose (+ (get completed-immunizations recipient-record) u1)))
              (if (> current-dose u1)
                (asserts!
                  (>=
                    (- CURRENT-CHAIN-HEIGHT
                      (get administration-timestamp
                        (unwrap-panic (element-at (get immunization-sequence recipient-record)
                          (- current-dose u2)
                        ))
                      ))
                    DOSE-INTERVAL-REQUIREMENT
                  )
                  MINIMUM-INTERVAL-VIOLATION
                )
                true
              )

              (ok (map-set immunization-registry { recipient-id: recipient-id } {
                immunization-sequence: (unwrap-panic (as-max-len?
                  (append (get immunization-sequence recipient-record) {
                    shipment-reference: shipment-id,
                    administration-timestamp: CURRENT-CHAIN-HEIGHT,
                    vaccine-formulation: (get vaccine-brand-name shipment-data),
                    sequence-number: current-dose,
                    administering-clinician: tx-sender,
                    clinic-location: clinic-location,
                    next-dose-due-date: (some (+ CURRENT-CHAIN-HEIGHT DOSE-INTERVAL-REQUIREMENT)),
                  })
                  u10
                )),
                completed-immunizations: current-dose,
                adverse-event-reports: (get adverse-event-reports recipient-record),
                medical-exemption: (get medical-exemption recipient-record),
              }))
            )
          )
          ;; First immunization for recipient
          (ok (map-set immunization-registry { recipient-id: recipient-id } {
            immunization-sequence: (list
              {
                shipment-reference: shipment-id,
                administration-timestamp: CURRENT-CHAIN-HEIGHT,
                vaccine-formulation: (get vaccine-brand-name shipment-data),
                sequence-number: u1,
                administering-clinician: tx-sender,
                clinic-location: clinic-location,
                next-dose-due-date: (some (+ CURRENT-CHAIN-HEIGHT DOSE-INTERVAL-REQUIREMENT)),
              }
            ),
            completed-immunizations: u1,
            adverse-event-reports: (list),
            medical-exemption: none,
          }))
        )
      )
      SHIPMENT-NOT-FOUND-ERROR
    )
  )
)

Functions (16)

FunctionAccessArgs
is-system-controllerprivate
validate-identifierprivateinput: (string-ascii 32
validate-name-fieldprivateinput: (string-ascii 50
validate-location-fieldprivateinput: (string-ascii 100
validate-description-fieldprivateinput: (string-ascii 200
validate-future-dateprivateinput-date: uint
validate-storage-limitprivateproposed-limit: uint
get-system-controllerread-only
verify-clinician-statusread-onlyclinician-address: principal
transfer-system-controlpublicnew-controller: principal
register-clinicianpublicclinician-address: principal, role: (string-ascii 20
register-storage-facilitypublicfacility-id: (string-ascii 100
register-vaccine-shipmentpublicshipment-id: (string-ascii 32
update-shipment-statuspublicshipment-id: (string-ascii 32
record-temperature-violationpublicshipment-id: (string-ascii 32
record-immunizationpublicrecipient-id: (string-ascii 32