---
# System prepended metadata

title: 建立NFT
tags: [Sui Move 學習筆記]

---

## IPFS介紹
#### 我們這次要使用IPFS(Pinata)來存放我們的NFT圖片。
有關IPFS以及Pinata介紹，請看這篇文章 [IPFS介紹](https://hackmd.io/7vj9f0HiQXGfo_j1_u0KfA?view)


## 上傳圖片至Pinata
我們使用Pinata當作我們儲存圖片的IPFS系統。

[Pinata上傳圖片頁面](https://app.pinata.cloud/pinmanager)

![](https://hackmd.io/_uploads/rkvIzlxyp.png)

首先我們點選右上角的 "Add Files" 按鈕，然後點選 "File"，會有上傳視窗讓你選擇圖片。
![](https://hackmd.io/_uploads/ByjgQlxJT.png)

這邊可以隨意上傳隨便一張圖片，GIF檔也可以。

![](https://turquoise-smiling-halibut-906.mypinata.cloud/ipfs/QmUnLrNWquR3H4HZtLHLmhBy4zKebMdmqRTZaqJLrTraM4)

上傳好後，我們可以看到有出現我們剛剛上傳的檔案以及對應的CID，這個CID就是你圖片的類似代號的東西，我們待會在Mint NFT的時候會用到。
![](https://hackmd.io/_uploads/SJaLHlx1T.png)

## Publisher + Display

這次主要會使用到Publisher以及Display兩個Sui Framwork內的module。

#### Publisher
作為代表發布者權限的一種方式。
該物件本身並沒有任何特定的用法，有兩個主要驗證的功能：```package::from_module<T>```以及```package::from_package<T>```
檢查類型T是否屬於為其Publisher創建物件的package或module。
要設置Publisher，需要一次性見證（OTW） - 通過這種方式，我們確保Publisher僅初始化一次。

#### Object Display
擁有Publisher對象的創建者或構建者可以使用```sui::display```來定義其物件的顯示屬性。
Sui Object Display 是一個模板顯示標準，允許在鏈上顯示配置。它能夠把鏈下數據替換到模板中。

可以設置哪些字段沒有限制，所有對象屬性都可以通過語法訪問{property}並作為模板字符串的一部分插入。
    
目前定義的模板內容如下:
```javascript
{
    "name": "{name}", //顯示名稱
    "link": "https://sui-heroes.io/hero/{id}", //可以放入連結到自己的商品網址
    "image_url": "ipfs://{img_url}", //使用ipfs(推薦)或是一般Https圖片網址
    "description": "A true Hero of the Sui ecosystem!", //敘述
    "project_url": "https://sui-heroes.io", //放入連結到自己的網站
    "creator": "Unknown Sui Fan" //創建人名稱
}
```

## NFT智能合約
```rust
module nft_demo::my_hero {
    use sui::tx_context::{Self, TxContext};
    use std::string::{Self, String};
    use sui::transfer;
    use sui::object::{Self, UID};

    use sui::package;
    use sui::display;

    struct Hero has key, store {
        id: UID,
        name: String,
        img_url: String,
        description: String,
        creator: String
    }

    /// One-Time-Witness for the module.
    struct MY_HERO has drop {}
    
    fun init(otw: MY_HERO, ctx: &mut TxContext) {
        let keys = vector[
            string::utf8(b"name"),
            string::utf8(b"link"),
            string::utf8(b"image_url"),
            string::utf8(b"description"),
            string::utf8(b"project_url"),
            string::utf8(b"creator"),
        ];

        let values = vector[
            // For `name` we can use the `Hero.name` property
            string::utf8(b"{name}"),
            // For `link` we can build a URL using an `id` property
            string::utf8(b"https://sui-heroes.io/hero/{id}"),
            // For `image_url` we use an ipfs :// + `img_url` or https:// + `img_url`.
            string::utf8(b"{img_url}"),
            // Description is static for all `Hero` objects.
            string::utf8(b"{description}"),
            // Project URL is usually static
            string::utf8(b"https://sui-heroes.io"),
            // Creator field can be any
            string::utf8(b"{creator}")
        ];

        // Claim the `Publisher` for the package!
        let publisher = package::claim(otw, ctx);

        // Get a new `Display` object for the `Hero` type.
        let display = display::new_with_fields<Hero>(
            &publisher, keys, values, ctx
        );

        // Commit first version of `Display` to apply changes.
        display::update_version(&mut display);

        transfer::public_transfer(publisher, tx_context::sender(ctx));
        transfer::public_transfer(display, tx_context::sender(ctx));
    }

    /// Anyone can mint their `Hero`!
    public entry fun mint(
        name: String,
        img_url: String,
        description: String,
        creator: String,
        ctx: &mut TxContext
    ) {
        let id = object::new(ctx);

        let hero = Hero { 
            id, 
            name, 
            img_url,
            description,
            creator
        };

        transfer::public_transfer(hero, tx_context::sender(ctx));
    }

    /// Permanently delete `nft`
    public entry fun burn(nft: Hero) {
        let Hero {
            id,
            name: _ ,
            img_url: _ ,
            description: _ ,
            creator:_
        } = nft;
        object::delete(id);
    }
}
```

### 部署智能合約

把智能合約部署上鏈後，我們可以使用 [Sui Explorer](https://suiexplorer.com/?network=testnet) 來使用我們剛剛開發的mint功能，來mint一個NFT給自己

### Mint NFT

先來查看要傳入哪些參數
![](https://hackmd.io/_uploads/B1qr1Hg16.png)

第一個參數傳入NFT名稱
第二個參數傳入ipfs://{CID}
![](https://hackmd.io/_uploads/Sy7A1BlJa.png)
第三個參數傳入NFT敘述
第四個參數傳入建造者名稱

![](https://hackmd.io/_uploads/ryuhyBg16.png)

![](https://hackmd.io/_uploads/B1W7eSgkT.png)

在我們的錢包內，點選Assets，也可看到我們剛剛mint出來的NFT
![](https://hackmd.io/_uploads/B1eOgHxJ6.png)

### Burn NFT
傳入需要銷毀的NFT Object ID
![](https://hackmd.io/_uploads/HyC0lBxka.png)

會發現Sui Explorer以及錢包都找不到該NFT了

![](https://hackmd.io/_uploads/HJOMWrgkp.png)

![](https://hackmd.io/_uploads/H1NQ-rx1p.png)