iT邦幫忙

2022 iThome 鐵人賽

DAY 9
1
Web 3

Road Map To DApp Developer系列 第 9

【DAY9】 - implement of OUR smart contract

  • 分享至 

  • xImage
  •  

Preface

今天會簡單的將 project 需要使用的 ERC1155 合約製作出來!

Design

原本我在 Day3 的設計是長這樣:


但是為了方便整個 project 的運行,我會先將 token 分成四個身分:

  1. 工作人員 (id = 0)
  2. 運動員 (id = 1)
  3. 運動員相關人員 (id = 2)
  4. 觀眾 (id = 3)

不同的身分會有不同的 token 作為票根(或是入場證明)。

ERC1155 Basis

這裡就先實作出相對應 token 的 ERC1155 合約。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Olympics is ERC1155, Ownable {
    constructor() ERC1155( "https://ipfs.io/ipfs/QmZ733swnB4hGcfHyFiXvg9irF6fqPScRxCsryQKU1byLo/{id}.json" )
    {}

    function mint(address account, uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        _mint(account, id, amount, data);
    }

    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        _mintBatch(to, ids, amounts, data);
    }
}

URI

在 ERC721 中需要透過_setTokenUri() 這個函式來設定每一枚 token 的 metadata。因此我很好奇,在 ERC1155 中只有一個 function 叫做 uri,難道他真的能透過一個 uri 來設置不同的 metadata 嗎?

我看過了 openzeppelin 的合約中後,發現其只有

// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;

constructor(string memory uri_) {
    _setURI(uri_);
}

function uri(uint256) public view virtual override returns (string memory) {
    return _uri;
}
function _setURI(string memory newuri) internal virtual {
    _uri = newuri;
}

這幾段函式,似乎沒有找到修改 uri 的 statement。因此我找了在 Opensea 上的範例程式,使用了裡面的修改方式。

string constant private BASE_URI = "https://ipfs.io/ipfs/QmPiEpJpb84oRrmSnBxhmR9CC7kgr39yvXy7fHaUaZi7Hn/";
string constant private JSON = ".json";
function uri (uint256 _tokenId) override public pure returns (string memory) {
    return 
    string(
        abi.encodePacked(
        BASE_URI,
        Strings.toString(_tokenId),
        JSON)
    );
}

這段程式同樣可以使用下面的方式:

function uri (uint256 _tokenId) override public pure returns (string memory) {
    return
    Strings.strConcat(
        baseURI,
        Strings.uint2str(_tokenId),
        JSON
    );

至於為什麼不直接使用 Openzeppelin 合約中的函式?我想是因為我目前還搞不懂為什麼直接使用一個 {id}.json(目前測試是可以成功的,我推測是透過 tokenId 對應到相對應的數字,例: tokenId = 0 => ipfs://CID/0.json) 便可以使不同 id 的 token 指向不同的 metadata(測試之後發現可以在 Opensea 上讀取到 json 的資料),若我有一天搞懂了才會開始使用他QQ

這也提醒了我一件事情,無論是 ERC20、ERC721 或是 ERC1155,他終究只是一個「協議」,因此只要你不要改動 ERC Interface function 的基本架構,基本上你想要如何改動其中的程式碼都是可以的,像我上面改動的方式就是利用 override 來改動 uri 中的 implement。

Openzeppelin 提供的合約的確是經過許多人驗證後確認是安全的,但是並不代表其是無法 alter 的,當你有不同需求的時候便可以使用你自己的方式來改動合約。但是這樣改動的方式就需要考慮到許多安全性的問題,例如你改動 safeMint(amount) (一次 mint 多個 token)的函式可能導致「重入攻擊」等問題。

Mint

接下來要處理 mint 的問題,這邊會做出兩種 mint 按鈕,第一個是與工作人員相關的;另一個則是與觀眾相關的。

與工作人員相關:

function mintForStaff(address account, uint256 id, uint256 amount, bytes memory data)
    public
{   
    require(id < 3, "This is only for Staff!");
    require(amount <= 0, "Amount should be bigger than 0.");
    _mint(account, id, amount, data);
}

function mintBatchForStaff(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
    public
{
    require(ids.length == amounts.length, "Two array length should match.");
    
    for (uint i = 0; i < ids.length; i++) {
        require(ids[i] < 3, "This is only for Staff!");
        require(amounts[i] > 0, "Amount should be bigger than 0.")
    }
    _mintBatch(to, ids, amounts, data);
}

基本上就是限制其無法購買 Audience 的票,其他部分沒有太大的改變。

觀眾:

function mintForAudience(address account, uint256 id, uint256 amount, bytes memory data)
    public
{
    require(id == 3, "This is only for Audience!");
    require(amount <= 0, "Amount should be bigger than 0");
    require(amount <= 4, "You can only buy 4 ticket once.");
    _mint(account, id, amount, data);
}

觀眾的部分除了限制只能購買 id==3 的 token 以外,也限制他們最多只能購買四張票。

Check on Opensea

實際 deply 在測試鏈後到 Opensea 上面看就可以看到,我已經 mint 5 張 Athlete 的工作證到我的地址中了!

Closing

今天完整的合約內容可見這裡,但是目前只是暫時的,未來會依照需求不同而改動這些 function!今天算是把 project 中的智能合約基本架構處理完,之後會開始進入前端的部分!

References


若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!

歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4


上一篇
【DAY8】 - ERC1155
下一篇
【DAY10】 - Construct the basis of website UI
系列文
Road Map To DApp Developer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言