# 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 ![](https://i.imgur.com/JPIdUzd.png) * NFT Storage https://nft.storage/ ![](https://i.imgur.com/CVaDvQX.jpg) * 中心化伺服器 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 頁面 * ![](https://i.imgur.com/aiV0iLA.png) * 簡介動態型(內嵌網頁) 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) } } ``` ## 參考