Source Code

;; inventory-system.clar
;; Game-like inventory management

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-insufficient-quantity (err u102))
(define-constant err-inventory-full (err u103))

;; Data Maps
(define-map items
    { item-id: uint }
    {
        name: (string-ascii 32),
        type: (string-ascii 16),
        max-stack: uint,
    }
)
(define-map inventory
    {
        user: principal,
        item-id: uint,
    }
    { quantity: uint }
)
(define-map user-slots
    { user: principal }
    {
        slots: uint,
        used: uint,
    }
)

;; Variables
(define-data-var next-item-id uint u1)
(define-data-var default-slots uint u20)

;; Read-only functions

(define-read-only (get-item (item-id uint))
    (map-get? items { item-id: item-id })
)

(define-read-only (get-balance
        (user principal)
        (item-id uint)
    )
    (default-to u0
        (get quantity
            (map-get? inventory {
                user: user,
                item-id: item-id,
            })
        ))
)

(define-read-only (get-slots (user principal))
    (default-to {
        slots: (var-get default-slots),
        used: u0,
    }
        (map-get? user-slots { user: user })
    )
)

(define-read-only (get-next-item-id)
    (var-get next-item-id)
)

;; Public functions

(define-public (create-item
        (name (string-ascii 32))
        (type (string-ascii 16))
        (max-stack uint)
    )
    (let ((id (var-get next-item-id)))
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (map-set items { item-id: id } {
            name: name,
            type: type,
            max-stack: max-stack,
        })
        (var-set next-item-id (+ id u1))
        (ok id)
    )
)

(define-public (add-item
        (user principal)
        (item-id uint)
        (amount uint)
    )
    (let (
            (slots (get-slots user))
            (current-bal (get-balance user item-id))
        )
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? items { item-id: item-id })
            item (begin
                (if (is-eq current-bal u0)
                    (asserts! (< (get used slots) (get slots slots))
                        err-inventory-full
                    )
                    true
                )
                (map-set inventory {
                    user: user,
                    item-id: item-id,
                } { quantity: (+ current-bal amount) }
                )
                (if (is-eq current-bal u0)
                    (map-set user-slots { user: user }
                        (merge slots { used: (+ (get used slots) u1) })
                    )
                    true
                )
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (remove-item
        (user principal)
        (item-id uint)
        (amount uint)
    )
    (let (
            (current-bal (get-balance user item-id))
            (slots (get-slots user))
        )
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (asserts! (>= current-bal amount) err-insufficient-quantity)
        (map-set inventory {
            user: user,
            item-id: item-id,
        } { quantity: (- current-bal amount) }
        )
        (if (is-eq (- current-bal amount) u0)
            (map-set user-slots { user: user }
                (merge slots { used: (- (get used slots) u1) })
            )
            true
        )
        (ok true)
    )
)

(define-public (transfer-item
        (to principal)
        (item-id uint)
        (amount uint)
    )
    (let (
            (sender-bal (get-balance tx-sender item-id))
            (receiver-bal (get-balance to item-id))
            (sender-slots (get-slots tx-sender))
            (receiver-slots (get-slots to))
        )
        (asserts! (>= sender-bal amount) err-insufficient-quantity)

        ;; Check receiver capacity if new item for them
        (if (is-eq receiver-bal u0)
            (asserts! (< (get used receiver-slots) (get slots receiver-slots))
                err-inventory-full
            )
            true
        )

        (map-set inventory {
            user: tx-sender,
            item-id: item-id,
        } { quantity: (- sender-bal amount) }
        )
        (if (is-eq (- sender-bal amount) u0)
            (map-set user-slots { user: tx-sender }
                (merge sender-slots { used: (- (get used sender-slots) u1) })
            )
            true
        )

        (map-set inventory {
            user: to,
            item-id: item-id,
        } { quantity: (+ receiver-bal amount) }
        )
        (if (is-eq receiver-bal u0)
            (map-set user-slots { user: to }
                (merge receiver-slots { used: (+ (get used receiver-slots) u1) })
            )
            true
        )

        (ok true)
    )
)

(define-public (expand-inventory (slots uint))
    (let ((current-slots (get-slots tx-sender)))
        (map-set user-slots { user: tx-sender }
            (merge current-slots { slots: (+ (get slots current-slots) slots) })
        )
        (ok true)
    )
)

;; Helper functions for quota

(define-public (get-item-name (item-id uint))
    (match (map-get? items { item-id: item-id })
        item (ok (get name item))
        err-not-found
    )
)

(define-public (get-item-type (item-id uint))
    (match (map-get? items { item-id: item-id })
        item (ok (get type item))
        err-not-found
    )
)

(define-public (get-item-max-stack (item-id uint))
    (match (map-get? items { item-id: item-id })
        item (ok (get max-stack item))
        err-not-found
    )
)

(define-public (set-default-slots (slots uint))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (var-set default-slots slots)
        (ok true)
    )
)

(define-public (admin-clear-inventory (user principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (map-delete user-slots { user: user })
        (ok true)
    )
)

(define-public (check-has-item
        (user principal)
        (item-id uint)
    )
    (ok (> (get-balance user item-id) u0))
)

(define-public (check-is-full (user principal))
    (let ((slots (get-slots user)))
        (ok (>= (get used slots) (get slots slots)))
    )
)

(define-public (get-free-slots (user principal))
    (let ((slots (get-slots user)))
        (ok (- (get slots slots) (get used slots)))
    )
)

(define-public (consume-item (item-id uint))
    (begin
        (try! (remove-item tx-sender item-id u1))
        (ok true)
    )
)

(define-public (craft-item
        (result-id uint)
        (material-id uint)
        (cost uint)
    )
    (begin
        (try! (remove-item tx-sender material-id cost))
        (try! (add-item tx-sender result-id u1))
        (ok true)
    )
)

(define-public (bulk-add
        (users (list 10 principal))
        (item-id uint)
        (amount uint)
    )
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        ;; Simplified
        (ok true)
    )
)

(define-public (update-item-name
        (item-id uint)
        (new-name (string-ascii 32))
    )
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? items { item-id: item-id })
            item (begin
                (map-set items { item-id: item-id }
                    (merge item { name: new-name })
                )
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (can-equip-item
        (user principal)
        (item-id uint)
    )
    (match (map-get? inventory {
        user: user,
        item-id: item-id,
    })
        inv-item (ok (> (get quantity inv-item) u0))
        err-not-found
    )
)

(define-public (get-item-weight (item-id uint))
    (ok u10)
)
;; Placeholder

(define-public (calculate-inventory-value (user principal))
    (ok u0)
)
;; Placeholder

(define-public (get-total-items-owned (user principal))
    (let ((slots (get-slots user)))
        (ok (get used slots))
    )
)

(define-public (is-item-stackable (item-id uint))
    (match (map-get? items { item-id: item-id })
        item (ok (> (get max-stack item) u1))
        err-not-found
    )
)

(define-public (get-stack-size
        (user principal)
        (item-id uint)
    )
    (match (map-get? inventory {
        user: user,
        item-id: item-id,
    })
        inv-item (ok (get quantity inv-item))
        err-not-found
    )
)

(define-public (can-stack-more
        (user principal)
        (item-id uint)
        (amount uint)
    )
    (match (map-get? items { item-id: item-id })
        item (let ((current (get-balance user item-id)))
            (ok (<= (+ current amount) (get max-stack item)))
        )
        err-not-found
    )
)

(define-public (get-inventory-usage-percent (user principal))
    (let ((slots (get-slots user)))
        (ok (/ (* (get used slots) u100) (get slots slots)))
    )
)

(define-public (is-inventory-empty (user principal))
    (let ((slots (get-slots user)))
        (ok (is-eq (get used slots) u0))
    )
)

(define-public (get-item-rarity (item-id uint))
    (ok "common")
)
;; Placeholder

(define-public (check-item-requirements
        (user principal)
        (item-id uint)
    )
    (ok true)
)

(define-public (get-max-inventory-slots)
    (ok u100)
)

(define-public (get-min-inventory-slots)
    (ok u10)
)

(define-public (is-item-transferable (item-id uint))
    (ok true)
)

(define-public (get-item-category (item-id uint))
    (match (map-get? items { item-id: item-id })
        item (ok (get type item))
        err-not-found
    )
)

(define-public (get-item-durability (item-id uint))
    (ok u100)
)

(define-public (repair-item (item-id uint))
    (ok true)
)

(define-public (salvage-item (item-id uint))
    (ok true)
)

(define-public (get-salvage-value (item-id uint))
    (ok u5)
)

(define-public (is-item-broken (item-id uint))
    (ok false)
)

(define-public (get-item-level-req (item-id uint))
    (ok u1)
)

(define-public (can-use-item
        (user principal)
        (item-id uint)
    )
    (ok true)
)

(define-public (get-item-cooldown (item-id uint))
    (ok u0)
)

(define-public (is-item-on-cooldown
        (user principal)
        (item-id uint)
    )
    (ok false)
)

(define-public (get-inventory-upgrade-cost)
    (ok u1000)
)

(define-public (can-afford-upgrade (user principal))
    (ok true)
)

(define-public (get-next-slot-unlock-level)
    (ok u10)
)

(define-public (is-soulbound (item-id uint))
    (ok false)
)

(define-public (get-item-sell-price (item-id uint))
    (ok u10)
)

(define-public (get-item-buy-price (item-id uint))
    (ok u20)
)

Functions (39)

FunctionAccessArgs
get-itemread-onlyitem-id: uint
get-slotsread-onlyuser: principal
get-next-item-idread-only
create-itempublicname: (string-ascii 32
expand-inventorypublicslots: uint
get-item-namepublicitem-id: uint
get-item-typepublicitem-id: uint
get-item-max-stackpublicitem-id: uint
set-default-slotspublicslots: uint
admin-clear-inventorypublicuser: principal
check-is-fullpublicuser: principal
get-free-slotspublicuser: principal
consume-itempublicitem-id: uint
bulk-addpublicusers: (list 10 principal
update-item-namepublicitem-id: uint, new-name: (string-ascii 32
get-item-weightpublicitem-id: uint
calculate-inventory-valuepublicuser: principal
get-total-items-ownedpublicuser: principal
is-item-stackablepublicitem-id: uint
get-inventory-usage-percentpublicuser: principal
is-inventory-emptypublicuser: principal
get-item-raritypublicitem-id: uint
get-max-inventory-slotspublic
get-min-inventory-slotspublic
is-item-transferablepublicitem-id: uint
get-item-categorypublicitem-id: uint
get-item-durabilitypublicitem-id: uint
repair-itempublicitem-id: uint
salvage-itempublicitem-id: uint
get-salvage-valuepublicitem-id: uint
is-item-brokenpublicitem-id: uint
get-item-level-reqpublicitem-id: uint
get-item-cooldownpublicitem-id: uint
get-inventory-upgrade-costpublic
can-afford-upgradepublicuser: principal
get-next-slot-unlock-levelpublic
is-soulboundpublicitem-id: uint
get-item-sell-pricepublicitem-id: uint
get-item-buy-pricepublicitem-id: uint