# Component

## Preface

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

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

component-1, component-2, component-3, etc. instead of actual names for the components.

## Explanations

All Smart Contracts for Components follow the same structure. Below is exemplified with the `Background Smart Contract` &#x20;

### 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 owner of lootbox, but someone else called
* the name does not exist in the map for components.
* doens not have the rights to call, but tried

{% code lineNumbers="true" %}
```lisp
(define-constant err-owner-only (err u100))
(define-constant err-invalid-name (err u301))
(define-constant err-no-rights (err u403))
```
{% 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 to let him 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) })

;; Populated map on deployment
(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)

;; 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-no-rights)
    (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-no-rights)     
    (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
;; Internal - Mint new NFT
(define-private (mint (new-owner principal))
  (begin 
    (asserts! (is-eq tx-sender (var-get contract-owner)) err-owner-only)
    (let 
      ((next-id (+ u1 (var-get last-id))))
      (var-set last-id next-id)
      (nft-mint? background next-id new-owner))))

(define-public (mint-url (address principal) (url (string-ascii 256)))
  (begin 
    (asserts! (is-eq tx-sender (var-get contract-owner)) err-owner-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! (is-eq tx-sender (var-get contract-owner)) err-owner-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 %}
