Source Code

;; kv-store.clar
;; Key-Value store with namespaces and permissions

;; Constants
(define-constant ERR-NAMESPACE-NOT-FOUND (err u100))
(define-constant ERR-NOT-NAMESPACE-OWNER (err u101))
(define-constant ERR-NO-READ-PERMISSION (err u102))
(define-constant ERR-NO-WRITE-PERMISSION (err u103))
(define-constant ERR-ENTRY-NOT-FOUND (err u104))
(define-constant ERR-EMPTY-KEY (err u105))
(define-constant ERR-NAMESPACE-EXISTS (err u106))

;; Maps
(define-map namespaces (buff 32)
  {
    name: (string-ascii 64),
    owner: principal,
    public-read: bool,
    public-write: bool
  }
)

(define-map entries { namespace-id: (buff 32), key: (string-ascii 64) }
  {
    value: (string-ascii 256),
    owner: principal,
    timestamp: uint
  }
)

(define-map namespace-readers { namespace-id: (buff 32), user: principal } bool)
(define-map namespace-writers { namespace-id: (buff 32), user: principal } bool)

;; Public Functions
(define-public (create-namespace (name (string-ascii 64)) (public-read bool) (public-write bool))
  (let ((namespace-id (sha256 (concat (unwrap-panic (to-consensus-buff? tx-sender)) (unwrap-panic (to-consensus-buff? name))))))
    (begin
      (asserts! (is-none (map-get? namespaces namespace-id)) ERR-NAMESPACE-EXISTS)
      (map-set namespaces namespace-id {
        name: name,
        owner: tx-sender,
        public-read: public-read,
        public-write: public-write
      })
      (ok namespace-id)
    )
  )
)

(define-public (put (namespace-id (buff 32)) (key (string-ascii 64)) (value (string-ascii 256)))
  (let ((ns (unwrap! (map-get? namespaces namespace-id) ERR-NAMESPACE-NOT-FOUND)))
    (begin
      (asserts! (> (len key) u0) ERR-EMPTY-KEY)
      (asserts! (> (len value) u0) (err u107))
      (asserts! (has-write-permission namespace-id ns tx-sender) ERR-NO-WRITE-PERMISSION)
      
      (map-set entries { namespace-id: namespace-id, key: key } {
        value: value,
        owner: tx-sender,
        timestamp: stacks-block-time
      })
      (ok true)
    )
  )
)

(define-public (delete-entry (namespace-id (buff 32)) (key (string-ascii 64)))
  (let (
    (ns (unwrap! (map-get? namespaces namespace-id) ERR-NAMESPACE-NOT-FOUND))
  )
    (begin
      (asserts! (> (len key) u0) ERR-EMPTY-KEY)
      (asserts! (is-eq (get owner ns) tx-sender) ERR-NOT-NAMESPACE-OWNER)
      (map-delete entries { namespace-id: namespace-id, key: key })
      (ok true)
    )
  )
)

(define-public (grant-read-permission (namespace-id (buff 32)) (user principal))
  (let ((ns (unwrap! (map-get? namespaces namespace-id) ERR-NAMESPACE-NOT-FOUND)))
    (begin
      (asserts! (is-eq (get owner ns) tx-sender) ERR-NOT-NAMESPACE-OWNER)
      (asserts! (not (is-eq user tx-sender)) (err u108))
      (ok (map-set namespace-readers { namespace-id: namespace-id, user: user } true))
    )
  )
)

(define-public (grant-write-permission (namespace-id (buff 32)) (user principal))
  (let ((ns (unwrap! (map-get? namespaces namespace-id) ERR-NAMESPACE-NOT-FOUND)))
    (begin
      (asserts! (is-eq (get owner ns) tx-sender) ERR-NOT-NAMESPACE-OWNER)
      (asserts! (not (is-eq user tx-sender)) (err u109))
      (ok (map-set namespace-writers { namespace-id: namespace-id, user: user } true))
    )
  )
)

;; Read-only
(define-read-only (get-value (namespace-id (buff 32)) (key (string-ascii 64)))
  (let ((ns (unwrap! (map-get? namespaces namespace-id) ERR-NAMESPACE-NOT-FOUND)))
    (begin
      (asserts! (has-read-permission namespace-id ns tx-sender) ERR-NO-READ-PERMISSION)
      (ok (get value (unwrap! (map-get? entries { namespace-id: namespace-id, key: key }) ERR-ENTRY-NOT-FOUND)))
    )
  )
)

;; Private helpers
(define-private (has-read-permission (ns-id (buff 32)) (ns {name: (string-ascii 64), owner: principal, public-read: bool, public-write: bool}) (user principal))
  (or 
    (is-eq (get owner ns) user)
    (get public-read ns)
    (default-to false (map-get? namespace-readers { namespace-id: ns-id, user: user }))
  )
)

(define-private (has-write-permission (ns-id (buff 32)) (ns {name: (string-ascii 64), owner: principal, public-read: bool, public-write: bool}) (user principal))
  (or 
    (is-eq (get owner ns) user)
    (get public-write ns)
    (default-to false (map-get? namespace-writers { namespace-id: ns-id, user: user }))
  )
)

Functions (8)

FunctionAccessArgs
create-namespacepublicname: (string-ascii 64
putpublicnamespace-id: (buff 32
delete-entrypublicnamespace-id: (buff 32
grant-read-permissionpublicnamespace-id: (buff 32
grant-write-permissionpublicnamespace-id: (buff 32
get-valueread-onlynamespace-id: (buff 32
has-read-permissionprivatens-id: (buff 32
has-write-permissionprivatens-id: (buff 32