今天會簡單的將 project 需要使用的 ERC1155 合約製作出來!
原本我在 Day3 的設計是長這樣:
但是為了方便整個 project 的運行,我會先將 token 分成四個身分:
不同的身分會有不同的 token 作為票根(或是入場證明)。
這裡就先實作出相對應 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);
}
}
在 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 按鈕,第一個是與工作人員相關的;另一個則是與觀眾相關的。
與工作人員相關:
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 以外,也限制他們最多只能購買四張票。
實際 deply 在測試鏈後到 Opensea 上面看就可以看到,我已經 mint 5 張 Athlete 的工作證到我的地址中了!
今天完整的合約內容可見這裡,但是目前只是暫時的,未來會依照需求不同而改動這些 function!今天算是把 project 中的智能合約基本架構處理完,之後會開始進入前端的部分!
若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!
歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4