Source Code

;; multisig-adapter-v2.clar
;; Lightweight signer approvals for action IDs.

(define-constant ERR-UNAUTHORIZED (err u12000))
(define-constant ERR-NOT-SIGNER (err u12001))
(define-constant ERR-ALREADY-APPROVED (err u12002))
(define-constant ERR-INVALID-THRESHOLD (err u12003))
(define-constant ERR-BELOW-THRESHOLD (err u12004))

(define-data-var signer-count uint u0)
(define-data-var threshold uint u1)

(define-map signers principal bool)
(define-map approvals {action-id: uint, signer: principal} bool)
(define-map approval-count uint uint)

(define-read-only (is-signer (signer principal))
  (default-to false (map-get? signers signer))
)

(define-read-only (get-threshold)
  (var-get threshold)
)

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

(define-read-only (get-approval-count (action-id uint))
  (default-to u0 (map-get? approval-count action-id))
)

(define-read-only (is-action-approved (action-id uint))
  (>= (get-approval-count action-id) (var-get threshold))
)

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

(define-private (check-principal (p principal))
  (ok (asserts! (is-eq p p) ERR-UNAUTHORIZED))
)

(define-private (check-bool (b bool))
  (ok (asserts! (or (is-eq b true) (is-eq b false)) ERR-UNAUTHORIZED))
)

(define-private (check-uint (n uint))
  (ok (asserts! (>= n u0) ERR-UNAUTHORIZED))
)

(define-public (set-signer (signer principal) (enabled bool))
  (begin
    (try! (is-dao-or-extension))
    (try! (check-principal signer))
    (try! (check-bool enabled))
    (let
      (
        (already (is-signer signer))
        (current (var-get signer-count))
        (next-count
          (if (and enabled (not already))
            (+ current u1)
            (if (and (not enabled) already)
              (- current u1)
              current
            )
          )
        )
      )
      (asserts! (or (is-eq next-count u0) (>= next-count (var-get threshold))) ERR-BELOW-THRESHOLD)
      (var-set signer-count next-count)
      (map-set signers signer enabled)
      (print {event: "signer-updated", signer: signer, enabled: enabled, signer-count: next-count})
      (ok true)
    )
  )
)

(define-public (set-threshold (new-threshold uint))
  (begin
    (try! (is-dao-or-extension))
    (try! (check-uint new-threshold))
    (asserts! (and (> new-threshold u0) (<= new-threshold (var-get signer-count))) ERR-INVALID-THRESHOLD)
    (var-set threshold new-threshold)
    (print {event: "threshold-updated", threshold: new-threshold})
    (ok true)
  )
)

(define-public (approve-action (action-id uint))
  (begin
    (try! (check-uint action-id))
    (asserts! (is-signer tx-sender) ERR-NOT-SIGNER)
    (asserts! (is-none (map-get? approvals {action-id: action-id, signer: tx-sender})) ERR-ALREADY-APPROVED)
    (map-set approvals {action-id: action-id, signer: tx-sender} true)
    (map-set approval-count action-id (+ (get-approval-count action-id) u1))
    (print {event: "action-approved", action-id: action-id, signer: tx-sender, approvals: (get-approval-count action-id)})
    (ok (is-action-approved action-id))
  )
)

(define-public (callback (sender principal) (memo (buff 34)))
  (begin
    sender
    memo
    (ok true)
  )
)

Functions (13)

FunctionAccessArgs
is-signerread-onlysigner: principal
get-thresholdread-only
get-signer-countread-only
get-approval-countread-onlyaction-id: uint
is-action-approvedread-onlyaction-id: uint
is-dao-or-extensionprivate
check-principalprivatep: principal
check-boolprivateb: bool
check-uintprivaten: uint
set-signerpublicsigner: principal, enabled: bool
set-thresholdpublicnew-threshold: uint
approve-actionpublicaction-id: uint
callbackpublicsender: principal, memo: (buff 34