Source Code

;; ============================================================================
;; ACCESS.CLAR - Role-Based Access Control & Emergency Controls
;; ============================================================================
;; Manages system roles, emergency pause functionality, and parameter updates.
;; This contract is the central authority for access control across the system.
;; ============================================================================

;; ============================================================================
;; CONSTANTS
;; ============================================================================

;; Error codes
(define-constant ERR-NOT-AUTHORIZED (err u1000))
(define-constant ERR-ALREADY-INITIALIZED (err u1001))
(define-constant ERR-NOT-INITIALIZED (err u1002))
(define-constant ERR-SYSTEM-PAUSED (err u1003))
(define-constant ERR-INVALID-ROLE (err u1004))
(define-constant ERR-ROLE-ALREADY-GRANTED (err u1005))
(define-constant ERR-ROLE-NOT-GRANTED (err u1006))
(define-constant ERR-CANNOT-REVOKE-SELF (err u1007))
(define-constant ERR-ZERO-ADDRESS (err u1008))

;; Role identifiers (bitflags for efficient storage)
(define-constant ROLE-ADMIN u1)           ;; Can manage roles and parameters
(define-constant ROLE-ORACLE u2)          ;; Can post price updates
(define-constant ROLE-RELAYER u4)         ;; Can credit collateral from Chainhook
(define-constant ROLE-LIQUIDATOR u8)      ;; Can trigger liquidations (optional restriction)
(define-constant ROLE-FEE-COLLECTOR u16)  ;; Can withdraw collected fees
(define-constant ROLE-PAUSER u32)         ;; Can pause/unpause system

;; ============================================================================
;; DATA STORAGE
;; ============================================================================

;; Initialization flag
(define-data-var initialized bool false)

;; System pause state
(define-data-var system-paused bool false)

;; Pause timestamp for tracking
(define-data-var pause-block uint u0)

;; Contract deployer (initial admin)
(define-data-var deployer principal tx-sender)

;; Role assignments: principal -> role bitmap
(define-map roles principal uint)

;; Authorized contracts that can call privileged functions
(define-map authorized-contracts principal bool)

;; Emergency contacts for multi-sig scenarios (optional extension)
(define-map emergency-contacts principal bool)

;; ============================================================================
;; INITIALIZATION
;; ============================================================================

;; Initialize the access control system
;; Can only be called once by the deployer
(define-public (initialize (initial-admin principal))
  (begin
    (asserts! (is-eq tx-sender (var-get deployer)) ERR-NOT-AUTHORIZED)
    (asserts! (not (var-get initialized)) ERR-ALREADY-INITIALIZED)
    (asserts! (not (is-eq initial-admin tx-sender)) ERR-ZERO-ADDRESS)
    
    ;; Grant all roles to initial admin
    (map-set roles initial-admin 
      (+ ROLE-ADMIN ROLE-ORACLE ROLE-RELAYER ROLE-LIQUIDATOR ROLE-FEE-COLLECTOR ROLE-PAUSER))
    
    ;; Also grant admin to deployer
    (map-set roles (var-get deployer) ROLE-ADMIN)
    
    (var-set initialized true)
    (print {event: "access-initialized", admin: initial-admin, deployer: (var-get deployer)})
    (ok true)))

;; ============================================================================
;; ROLE MANAGEMENT
;; ============================================================================

;; Check if a principal has a specific role
(define-read-only (has-role (account principal) (role uint))
  (let ((user-roles (default-to u0 (map-get? roles account))))
    (> (bit-and user-roles role) u0)))

;; Check if caller has admin role
(define-read-only (is-admin (account principal))
  (has-role account ROLE-ADMIN))

;; Check if caller has oracle role
(define-read-only (is-oracle (account principal))
  (has-role account ROLE-ORACLE))

;; Check if caller has relayer role
(define-read-only (is-relayer (account principal))
  (has-role account ROLE-RELAYER))

;; Check if caller has pauser role
(define-read-only (is-pauser (account principal))
  (has-role account ROLE-PAUSER))

;; Get all roles for a principal
(define-read-only (get-roles (account principal))
  (default-to u0 (map-get? roles account)))

;; Grant a role to a principal (admin only)
(define-public (grant-role (account principal) (role uint))
  (let ((current-roles (default-to u0 (map-get? roles account))))
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (is-admin tx-sender) ERR-NOT-AUTHORIZED)
    (asserts! (is-valid-role role) ERR-INVALID-ROLE)
    
    ;; Check if role already granted
    (asserts! (is-eq (bit-and current-roles role) u0) ERR-ROLE-ALREADY-GRANTED)
    
    ;; Grant the role by OR-ing with existing roles
    (map-set roles account (bit-or current-roles role))
    
    (print {event: "role-granted", account: account, role: role, granter: tx-sender})
    (ok true)))

;; Revoke a role from a principal (admin only)
(define-public (revoke-role (account principal) (role uint))
  (let ((current-roles (default-to u0 (map-get? roles account))))
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (is-admin tx-sender) ERR-NOT-AUTHORIZED)
    (asserts! (is-valid-role role) ERR-INVALID-ROLE)
    
    ;; Prevent admin from revoking their own admin role
    (asserts! (not (and (is-eq account tx-sender) (is-eq role ROLE-ADMIN))) ERR-CANNOT-REVOKE-SELF)
    
    ;; Check if role exists
    (asserts! (> (bit-and current-roles role) u0) ERR-ROLE-NOT-GRANTED)
    
    ;; Revoke the role by AND-ing with complement
    (map-set roles account (bit-and current-roles (bit-not role)))
    
    (print {event: "role-revoked", account: account, role: role, revoker: tx-sender})
    (ok true)))

;; Validate that role is a known role
(define-read-only (is-valid-role (role uint))
  (or (is-eq role ROLE-ADMIN)
      (is-eq role ROLE-ORACLE)
      (is-eq role ROLE-RELAYER)
      (is-eq role ROLE-LIQUIDATOR)
      (is-eq role ROLE-FEE-COLLECTOR)
      (is-eq role ROLE-PAUSER)))

;; ============================================================================
;; CONTRACT AUTHORIZATION
;; ============================================================================

;; Authorize a contract to call privileged functions
(define-public (authorize-contract (contract-principal principal))
  (begin
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (is-admin tx-sender) ERR-NOT-AUTHORIZED)
    
    (map-set authorized-contracts contract-principal true)
    
    (print {event: "contract-authorized", contract: contract-principal, authorizer: tx-sender})
    (ok true)))

;; Revoke contract authorization
(define-public (revoke-contract (contract-principal principal))
  (begin
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (is-admin tx-sender) ERR-NOT-AUTHORIZED)
    
    (map-delete authorized-contracts contract-principal)
    
    (print {event: "contract-revoked", contract: contract-principal, revoker: tx-sender})
    (ok true)))

;; Check if a contract is authorized
(define-read-only (is-authorized-contract (contract-principal principal))
  (default-to false (map-get? authorized-contracts contract-principal)))

;; ============================================================================
;; EMERGENCY CONTROLS
;; ============================================================================

;; Pause the entire system
(define-public (pause)
  (begin
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (or (is-pauser tx-sender) (is-admin tx-sender)) ERR-NOT-AUTHORIZED)
    (asserts! (not (var-get system-paused)) ERR-SYSTEM-PAUSED)
    
    (var-set system-paused true)
    (var-set pause-block block-height)
    
    (print {event: "system-paused", pauser: tx-sender, block: block-height})
    (ok true)))

;; Unpause the system (admin only for safety)
(define-public (unpause)
  (begin
    (asserts! (var-get initialized) ERR-NOT-INITIALIZED)
    (asserts! (is-admin tx-sender) ERR-NOT-AUTHORIZED)
    (asserts! (var-get system-paused) (err u1009)) ;; Not paused
    
    (var-set system-paused false)
    
    (print {event: "system-unpaused", unpauser: tx-sender, block: block-height, 
            paused-duration: (- block-height (var-get pause-block))})
    (ok true)))

;; Check if system is paused
(define-read-only (is-paused)
  (var-get system-paused))

;; Get pause info
(define-read-only (get-pause-info)
  {
    paused: (var-get system-paused),
    pause-block: (var-get pause-block),
    current-block: block-height
  })

;; ============================================================================
;; ACCESS CHECK HELPERS (for other contracts to call)
;; ============================================================================

;; Assert that system is not paused (for use in other contracts)
(define-read-only (check-not-paused)
  (not (var-get system-paused)))

;; Combined check: not paused AND has role
(define-read-only (can-execute (account principal) (required-role uint))
  (and (not (var-get system-paused))
       (has-role account required-role)))

;; Check if caller can perform oracle operations
(define-read-only (can-post-price (account principal))
  (and (not (var-get system-paused))
       (has-role account ROLE-ORACLE)))

;; Check if caller can credit collateral (relayer)
(define-read-only (can-credit-collateral (account principal))
  (and (not (var-get system-paused))
       (has-role account ROLE-RELAYER)))

;; ============================================================================
;; ADMIN INFO
;; ============================================================================

;; Get system info
(define-read-only (get-system-info)
  {
    initialized: (var-get initialized),
    paused: (var-get system-paused),
    deployer: (var-get deployer)
  })

;; Get role constants for reference
(define-read-only (get-role-constants)
  {
    admin: ROLE-ADMIN,
    oracle: ROLE-ORACLE,
    relayer: ROLE-RELAYER,
    liquidator: ROLE-LIQUIDATOR,
    fee-collector: ROLE-FEE-COLLECTOR,
    pauser: ROLE-PAUSER
  })

Functions (23)

FunctionAccessArgs
initializepublicinitial-admin: principal
has-roleread-onlyaccount: principal, role: uint
is-adminread-onlyaccount: principal
is-oracleread-onlyaccount: principal
is-relayerread-onlyaccount: principal
is-pauserread-onlyaccount: principal
get-rolesread-onlyaccount: principal
grant-rolepublicaccount: principal, role: uint
revoke-rolepublicaccount: principal, role: uint
is-valid-roleread-onlyrole: uint
authorize-contractpubliccontract-principal: principal
revoke-contractpubliccontract-principal: principal
is-authorized-contractread-onlycontract-principal: principal
pausepublic
unpausepublic
is-pausedread-only
get-pause-inforead-only
check-not-pausedread-only
can-executeread-onlyaccount: principal, required-role: uint
can-post-priceread-onlyaccount: principal
can-credit-collateralread-onlyaccount: principal
get-system-inforead-only
get-role-constantsread-only