# Z 前端開發班 - 實戰 NFT ERC721 網站完整功能與串接
Codesandbox: https://codesandbox.io/p/github/z-institute/web3-frontend-nft/draft/great-bush
## Tina
- 程式碼範例
- Goerli 測試網合約部署地址:[0x6fC9d31fcdBCCA0cb4a68840B87F0a80c8Ce12Da](https://goerli.etherscan.io/address/0x6fC9d31fcdBCCA0cb4a68840B87F0a80c8Ce12Da#code)
- NFT 智能合約:https://github.com/z-institute/web3-frontend-contracts/blob/main/NFT.sol
- Metadata Template https://gist.github.com/tina1998612/6b3f91350a3a681c4c1f8d1c132019f9
- `signWhitelistVoucher.js` 簽白名單:https://gist.github.com/tina1998612/530065be6cbf8d68d81cddd277e2564f
- `whitelist.txt` 白名單清單:https://gist.github.com/tina1998612/7c8923e7b10e1e31219ee97ddf5ebc2c
- `whitelist.json` 簽署完的簽章(只適用於目前部署在 Goerli 測試網的 NFT 合約):https://gist.github.com/tina1998612/0f2ad0a527a78852634d717911d4b132
- Opensea 測試網 NFT 連結:https://testnets.opensea.io/assets/goerli/0x6fc9d31fcdbcca0cb4a68840b87f0a80c8ce12da/1
- 步驟
- 創建 hardhat project:`npx hardhat init`
- `hardhat.config.js` 設定添加下列到 `networks` 底下
```
goerli: {
url: process.env.GOERLI_RPC_URL,
accounts: {
mnemonic: process.env.MNEMONIC,
},
chainId: 5,
},
```
- 執行簽署並獲得 `whitelist.json`:`npx hardhat run scripts/signWhitelistVoucher.js --network goerli`
## Agenda
1. ERC721 合約介紹
2. 其他變體的 NFT 合約介紹 - 721A / 721R / PBT / 一些近期的新標準
3. 常見交易平台 storefront 合約介紹
4. 多階段 Mint (不同價量) 原理講解
5. 合約功能測試
* 合約在 Goerli 部署時給 symbol name 跟 uri
7. Meta Data 與圖片準備
* 上傳到 ipfs Pinata / nftupload
* https://www.pinata.cloud

* NFT Storage https://nft.storage/

* 中心化伺服器
8. 串接 NFT Mint 前端功能
* 使用 ETH
* Reject Handle
```javascript=
try {
let tx = await mint();
setIsMinting(true);
setCurrentTxHash(tx.hash);
await tx.wait();
setIsMinting(false);
onOpen();
} catch (e) {
toast({
title: "Error",
description: JSON.stringify(e),
status: "error",
duration: 9000,
isClosable: true,
});
console.log("Error!", e);
}
```
* 使用自定義 Token
* 一次 Mint 多個的價量資料設定
9. 其他功能(可自行延伸練習)
* 如何設計 NFT Redeem 功能
* Burn Token 功能
* 如何調閱 NFT 資料與 Opensea API 作為會員組憑證
* 設定 Collection Fee 與 Opensea 頁面
* 
* 簡介動態型(內嵌網頁) NFT 運作原理
* 範例 https://gateway.fxhash2.xyz/ipfs/QmTX4bgRjn9RUvNyLfvWBi8vxtVD7EkRavktoYVtTuDVcZ/?fxhash=ooSfhwCapGMvV7eyFJYL9UnPrgNuSHXww5ahEw7MG8vyWaNzZJK
* 其他鏈開發 NFT 應用時會需要留意的事項
https://openprocessing.org/sketch/1723320
```javascript=
class Random {
constructor(seed) {
this.seed = seed;
}
random() {
return this.random_dec();
}
random_dec() {
return fxrand();
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
this.seed ^= this.seed << 13;
this.seed ^= this.seed >> 17;
this.seed ^= this.seed << 5;
return ((this.seed < 0 ? ~this.seed + 1 : this.seed) % 1000) / 1000;
}
random_num(a, b) {
if (b === undefined) {
b = a;
a = 0;
}
return a + (b - a) * this.random_dec();
}
random_int(a, b) {
if (b === undefined) {
b = a;
a = 0;
}
return Math.floor(this.random_num(a, b + 1));
}
random_bool(p) {
return this.random_dec() < p;
}
random_choice(list) {
return list[Math.floor(this.random_num(0, list.length * 0.99))];
}
random_choice_weight(obj) {
let sum = Object.values(obj).reduce((a, b) => a + b, 0);
let steps = Object.values(obj).reduce(
(arr, num) => {
arr.push((arr.slice(-1) || 0) * 1 + num);
return arr;
},
[0]
);
let ran = this.random_num(0, sum);
let result = 0;
for (let i = steps.length - 1; i >= 1; i--) {
result = i - 1;
if (ran > steps[i - 1] && ran < steps[i]) {
break;
}
}
return Object.keys(obj)[result];
}
}
let R = new Random()
let random = (obj, obj2) => {
//random()
if (obj == undefined) {
return R.random_dec()
}
//random([1,2,3])
if (Array.isArray(obj)) {
return R.random_choice(obj)
}
//random(50)
if (typeof obj == 'number' && typeof obj2 == 'number') {
return R.random_num(obj, obj2)
}
//random(50)
if (typeof obj == 'number' && obj2 == undefined) {
return R.random_num(0, obj)
}
if (typeof obj == 'object') {
return R.random_choice_weight(obj)
}
}
```
## 參考