# Item

## Preface

It is exemplified and used with the background contracts for easier understanding.

The more general version will be `item` instead of `background` and the name of the `items`&#x20;

item-common-1, item-common-2, item-rare-1, etc. instead of actual names for the items.

## Explanations

### Traits used

This trait enforces that the standard for NFTs is implemented in this smart contract through SIP009.

```
(use-trait nft-trait .nft-trait.nft-trait)
```

### Errors

Errors for different cases such as:

* should be called by admin, but someone else called
* should be called by owner, but someone else called
* the name is not part of the existent in map for items&#x20;

{% code lineNumbers="true" %}

```lisp
(define-constant err-admin-only (err u100))
(define-constant err-owner-only (err u101))
(define-constant err-invalid-name (err u301))
```

{% endcode %}

### Variable Data Stored - Maps and Vars

Every NFT has a token-url value attributed. This helps in calling the get-token-uri function.&#x20;

Map name-url - keeps all types of items the collection has. On deployment it will have DarkPurple,  Emerald, Goldie, Orange, Purple, Sunset with their token-URI.

Also keep contract-owner and contract-lootbox to let them perform mints, add and update new `item-names` to the collection and remove old ones.

{% code lineNumbers="true" %}

```lisp
(define-map token-url { token-id: uint } { url: (string-ascii 256) })
;; this is used if we want for a given attribute value to give a specific url
;; eg. purple background -> ipfs://dasd..
(define-map name-url { name: (string-ascii 30)} { url: (string-ascii 256) })

(map-set name-url  {name: "DarkPurple"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/DarkPurple.json"})
(map-set name-url  {name: "Emerald"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/Emerald.json"})
(map-set name-url  {name: "Goldie"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/Goldie.json"})
(map-set name-url  {name: "Orange"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/Orange.json"})
(map-set name-url  {name: "Purple"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/Purple.json"})
(map-set name-url  {name: "Sunset"} {url: "ipfs://QmSUD8LoZL4ChE1LRmhcACsP1FJCaHuWpW8FXEtedD1rPo/Sunset.json"})

;; Owner
(define-data-var contract-owner principal tx-sender)
(define-data-var contract-lootbox principal .lootbox-background)

;; Store the last issues token ID
(define-data-var last-id uint u0)
```

{% endcode %}

### SIP009: Standard Implementations for NFTs

{% code lineNumbers="true" %}

```lisp
;; SIP009: Transfer token to a specified principal
(define-public (transfer (token-id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) err-owner-only)
    (nft-transfer? background token-id sender recipient)))

(define-public (transfer-memo (token-id uint) (sender principal) (recipient principal) (memo (buff 34)))
  (begin 
    (try! (transfer token-id sender recipient))
    (print memo)
    (ok true)))

;; SIP009: Get the owner of the specified token ID
(define-read-only (get-owner (token-id uint))
  ;; Make sure to replace background
  (ok (nft-get-owner? background token-id)))

;; SIP009: Get the last token ID
(define-read-only (get-last-token-id)
  (ok (var-get last-id)))

(define-read-only (get-token-uri (token-id uint)) 
  (let ((token-urr (get url (map-get? token-url {token-id: token-id})))) 
  (ok token-urr)))

;; Burn a token
(define-public (burn-token (token-id uint))  
  (begin     
    (asserts! (is-eq (some tx-sender) (nft-get-owner? background token-id) ) err-owner-only)     
    (nft-burn? background token-id tx-sender)))
```

{% endcode %}

## Item Name-URI

Get-name-url - anyone can get the saved URI for the specified URI

Set-name-url - only admins can store the URI to the name

Remove-name-url - only admins can remove the key name from the map  &#x20;

{% code lineNumbers="true" %}

```lisp
(define-read-only (get-name-url (name (string-ascii 30)))
  (let ((token-urr (get url (map-get? name-url {name: name})))) 
    (ok token-urr)))

(define-public (set-name-url (name (string-ascii 30)) (url (string-ascii 30))) 
  (begin
    (asserts! 
      (or
        (is-eq tx-sender (var-get contract-owner)) 
        (is-eq tx-sender (var-get contract-lootbox))) 
      err-admin-only)
    (ok (map-set name-url {name: name} {url: url}))))

(define-public (remove-name-url (name (string-ascii 30))) 
  (begin
  (asserts! 
      (or
        (is-eq tx-sender (var-get contract-owner)) 
        (is-eq tx-sender (var-get contract-lootbox))) 
      err-admin-only)
    (ok (map-delete name-url {name: name}))))
```

{% endcode %}

## Item Mint

#### There are two ways to mint a new item, by using directly the URI of the NFT,  or by minting with the name and getting the URI from the values stored on-chain in the map. Safer and easier to use `mint-name` as it checks the type of item minted already exists in the map.

{% code lineNumbers="true" %}

```lisp
(define-public (mint-url (address principal) (url (string-ascii 256)))
  (begin     
    (asserts! 
      (or
        (is-eq tx-sender (var-get contract-owner)) 
        (is-eq tx-sender (var-get contract-lootbox))) 
      err-admin-only)
    (let 
      ((next-id (+ u1 (var-get last-id))))
      (map-set token-url {token-id: next-id} {url: url})
      (var-set last-id next-id)
      (nft-mint? background next-id address))))

(define-public (mint-name (address principal) (name (string-ascii 30)))
  (begin
    (asserts! 
      (or
        (is-eq tx-sender (var-get contract-owner)) 
        (is-eq tx-sender (var-get contract-lootbox))) 
      err-admin-only)
    (let 
    ;; define and assign: next-id and url
      ((next-id (+ u1 (var-get last-id)))
        (url (get url (map-get? name-url {name: name}))))
      (if (is-none url)
        err-invalid-name
        (begin 
          (map-set token-url {token-id: next-id} {url: (unwrap-panic url)})
          (var-set last-id next-id)
          (nft-mint? background next-id address)))))
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.degenlab.io/gamefistacks/lootbox-on-chain-m3/smart-contracts/item.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
