Source Code

;; extensions-registry.clar
;; Modular extension loader and registry
;; Tracks all installed extensions with metadata

;; Error codes
(define-constant ERR-UNAUTHORIZED (err u3000))
(define-constant ERR-EXTENSION-NOT-FOUND (err u3001))
(define-constant ERR-EXTENSION-ALREADY-EXISTS (err u3002))
(define-constant ERR-INVALID-CATEGORY (err u3003))

;; Extension categories
(define-constant CATEGORY-GOVERNANCE u1)
(define-constant CATEGORY-UTILITY u5)

;; Data vars
(define-data-var extension-count uint u0)
(define-data-var extension-nonce uint u0)

;; Data maps
(define-map extension-info
  principal
  {
    id: uint,
    name: (string-ascii 64),
    description: (string-utf8 256),
    category: uint,
    version: (string-ascii 16),
    enabled: bool,
    added-at: uint,
    added-by: principal
  }
)

(define-map extensions-by-id uint principal)
(define-map extensions-by-category uint (list 50 principal))

;; Read-only functions

(define-read-only (get-extension-count)
  (var-get extension-count)
)

(define-read-only (get-extension-info (extension principal))
  (map-get? extension-info extension)
)

(define-read-only (get-extension-by-id (id uint))
  (map-get? extensions-by-id id)
)

(define-read-only (get-extensions-by-category (category uint))
  (default-to (list) (map-get? extensions-by-category category))
)

(define-read-only (is-extension-enabled (extension principal))
  (match (map-get? extension-info extension)
    info (get enabled info)
    false
  )
)

(define-read-only (get-extension-category (extension principal))
  (match (map-get? extension-info extension)
    info (some (get category info))
    none
  )
)

;; Input checks (satisfy check_checker)
(define-private (check-principal (p principal))
  (ok (asserts! (is-eq p p) ERR-UNAUTHORIZED))
)

(define-private (check-ascii-64 (s (string-ascii 64)))
  (ok (asserts! (<= (len s) u64) ERR-UNAUTHORIZED))
)

(define-private (check-ascii-16 (s (string-ascii 16)))
  (ok (asserts! (<= (len s) u16) ERR-UNAUTHORIZED))
)

(define-private (check-utf8-256 (s (string-utf8 256)))
  (ok (asserts! (<= (len s) u256) ERR-UNAUTHORIZED))
)

;; Authorization
(define-private (is-dao-or-extension)
  (contract-call? .dao-core-v2-c4 is-dao-or-extension)
)

;; Public functions

;; Register a new extension
(define-public (register-extension 
  (extension principal) 
  (name (string-ascii 64))
  (description (string-utf8 256))
  (category uint)
  (version (string-ascii 16))
)
  (let
    (
      (new-id (+ (var-get extension-nonce) u1))
      (current-category-list (get-extensions-by-category category))
    )
    (try! (is-dao-or-extension))
    (try! (check-principal extension))
    (try! (check-ascii-64 name))
    (try! (check-utf8-256 description))
    (try! (check-ascii-16 version))
    (asserts! (is-none (map-get? extension-info extension)) ERR-EXTENSION-ALREADY-EXISTS)
    (asserts! (and (>= category CATEGORY-GOVERNANCE) (<= category CATEGORY-UTILITY)) ERR-INVALID-CATEGORY)
    
    ;; Store extension info
    (map-set extension-info extension {
      id: new-id,
      name: name,
      description: description,
      category: category,
      version: version,
      enabled: true,
      added-at: stacks-block-height,
      added-by: tx-sender
    })
    
    ;; Index by ID
    (map-set extensions-by-id new-id extension)
    
    ;; Index by category
    (map-set extensions-by-category category 
      (unwrap-panic (as-max-len? (append current-category-list extension) u50))
    )
    
    ;; Update counters
    (var-set extension-nonce new-id)
    (var-set extension-count (+ (var-get extension-count) u1))
    
    ;; Enable in dao-core
    (try! (as-contract? ()
      (try! (contract-call? .dao-core-v2-c4 set-extension extension true))
      true
    ))
    
    (print {
      event: "extension-registered",
      extension: extension,
      id: new-id,
      name: name,
      category: category
    })
    (ok new-id)
  )
)

;; Enable an extension
(define-public (enable-extension (extension principal))
  (begin
    (try! (is-dao-or-extension))
    (try! (check-principal extension))
    (match (map-get? extension-info extension)
      info (begin
        (map-set extension-info extension (merge info {enabled: true}))
        (try! (as-contract? ()
          (try! (contract-call? .dao-core-v2-c4 set-extension extension true))
          true
        ))
        (print {event: "extension-enabled", extension: extension})
        (ok true)
      )
      ERR-EXTENSION-NOT-FOUND
    )
  )
)

;; Disable an extension
(define-public (disable-extension (extension principal))
  (begin
    (try! (is-dao-or-extension))
    (try! (check-principal extension))
    (match (map-get? extension-info extension)
      info (begin
        (map-set extension-info extension (merge info {enabled: false}))
        (try! (as-contract? ()
          (try! (contract-call? .dao-core-v2-c4 set-extension extension false))
          true
        ))
        (print {event: "extension-disabled", extension: extension})
        (ok true)
      )
      ERR-EXTENSION-NOT-FOUND
    )
  )
)

;; Update extension version
(define-public (update-extension-version (extension principal) (new-version (string-ascii 16)))
  (begin
    (try! (is-dao-or-extension))
    (try! (check-principal extension))
    (try! (check-ascii-16 new-version))
    (match (map-get? extension-info extension)
      info (begin
        (map-set extension-info extension (merge info {version: new-version}))
        (print {event: "extension-updated", extension: extension, version: new-version})
        (ok true)
      )
      ERR-EXTENSION-NOT-FOUND
    )
  )
)

;; Extension callback (required by extension-trait)
(define-public (callback (sender principal) (memo (buff 34)))
  (begin
    sender
    memo
    (ok true)
  )
)

Functions (16)

FunctionAccessArgs
get-extension-countread-only
get-extension-inforead-onlyextension: principal
get-extension-by-idread-onlyid: uint
get-extensions-by-categoryread-onlycategory: uint
is-extension-enabledread-onlyextension: principal
get-extension-categoryread-onlyextension: principal
check-principalprivatep: principal
check-ascii-64privates: (string-ascii 64
check-ascii-16privates: (string-ascii 16
check-utf8-256privates: (string-utf8 256
is-dao-or-extensionprivate
register-extensionpublicextension: principal, name: (string-ascii 64
enable-extensionpublicextension: principal
disable-extensionpublicextension: principal
update-extension-versionpublicextension: principal, new-version: (string-ascii 16
callbackpublicsender: principal, memo: (buff 34