Source Code

;; title: aibtc-dao-users
;; version: 1.0.0
;; summary: An extension that tracks the current users and their reputation in the DAO.

;; traits
;;

(impl-trait 'SPW8QZNWKZGVHX012HCBJVJVPS94PXFG578P53TM.aibtc-dao-traits.extension)
(impl-trait 'SPW8QZNWKZGVHX012HCBJVJVPS94PXFG578P53TM.aibtc-dao-traits.dao-users)

;; constants
;;

;; contract details
(define-constant DEPLOYED_BURN_BLOCK burn-block-height)
(define-constant DEPLOYED_STACKS_BLOCK stacks-block-height)
(define-constant SELF (as-contract tx-sender))

;; error messages
(define-constant ERR_NOT_DAO_OR_EXTENSION (err u1500))
(define-constant ERR_USER_NOT_FOUND (err u1501))

;; data vars
;;

(define-data-var userCount uint u0) ;; total number of users

;; data maps
;;

;; central tracking for DAO users
(define-map UserIndexes
  principal
  uint
)
(define-map UserData
  uint ;; user index
  {
    address: principal,
    createdAt: uint,
    reputation: int, ;; increases/decreases from proposal bonds
  }
)

;; public functions
;;

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

(define-public (get-or-create-user-index (address principal))
  (match (map-get? UserIndexes address)
    ;; user already exists, return the index
    value
    (ok value)
    ;; user does not exist, create a new one
    (let ((userIndex (+ u1 (var-get userCount))))
      (try! (is-dao-or-extension))
      (print {
        notification: "fake-dao-users/get-or-create-user-index",
        payload: {
          userIndex: userIndex,
          address: address,
          createdAt: burn-block-height,
          contractCaller: contract-caller,
          txSender: tx-sender,
        },
      })
      (map-insert UserIndexes address userIndex)
      (map-insert UserData userIndex {
        address: address,
        createdAt: burn-block-height,
        reputation: 0,
      })
      (var-set userCount userIndex)
      (ok userIndex)
    )
  )
)

(define-public (increase-user-reputation
    (address principal)
    (amount uint)
  )
  (let (
      (userIndex (unwrap! (get-user-index address) ERR_USER_NOT_FOUND))
      (userData (unwrap! (get-user-data-by-index userIndex) ERR_USER_NOT_FOUND))
      (increaseAmount (to-int amount))
    )
    (try! (is-dao-or-extension))
    (print {
      notification: "fake-dao-users/increase-user-reputation",
      payload: {
        userIndex: userIndex,
        address: address,
        contractCaller: contract-caller,
        txSender: tx-sender,
      },
    })
    (map-set UserData userIndex
      (merge userData { reputation: (+ (get reputation userData) increaseAmount) })
    )
    (ok true)
  )
)

(define-public (decrease-user-reputation
    (address principal)
    (amount uint)
  )
  (let (
      (userIndex (unwrap! (get-user-index address) ERR_USER_NOT_FOUND))
      (userData (unwrap! (get-user-data-by-index userIndex) ERR_USER_NOT_FOUND))
      (decreaseAmount (to-int amount))
    )
    (try! (is-dao-or-extension))
    (print {
      notification: "fake-dao-users/decrease-user-reputation",
      payload: {
        userIndex: userIndex,
        address: address,
        contractCaller: contract-caller,
        txSender: tx-sender,
      },
    })
    (map-set UserData userIndex
      (merge userData { reputation: (- (get reputation userData) decreaseAmount) })
    )
    (ok true)
  )
)

;; read only functions
;;

;; returns the unique user count
(define-read-only (get-user-count)
  (var-get userCount)
)

;; returns (some data) if the user exists or none if unknown
(define-read-only (get-user-index (address principal))
  (map-get? UserIndexes address)
)

;; returns (some data) if the user exists or none if unknown
(define-read-only (get-user-data-by-index (userIndex uint))
  (map-get? UserData userIndex)
)

;; returns (some data) if the user exists or none if unknown
(define-read-only (get-user-data-by-address (address principal))
  (get-user-data-by-index (unwrap! (get-user-index address) none))
)

;; private functions
;;

;; returns ok if the caller is the DAO or an extension or err if not
(define-private (is-dao-or-extension)
  (ok (asserts!
    (or
      (is-eq tx-sender .fake-base-dao)
      (contract-call? .fake-base-dao is-extension contract-caller)
    )
    ERR_NOT_DAO_OR_EXTENSION
  ))
)

Functions (7)

FunctionAccessArgs
callbackpublicsender: principal, memo: (buff 34
get-or-create-user-indexpublicaddress: principal
get-user-countread-only
get-user-indexread-onlyaddress: principal
get-user-data-by-indexread-onlyuserIndex: uint
get-user-data-by-addressread-onlyaddress: principal
is-dao-or-extensionprivate