昨天我們成功的將鐵人賽NFT總數設定成2枚,並且規定每個錢包只能擁有一個。不過單單檢查該錢包是否擁有此NFT代幣的作法好像會有一些漏洞? 讓我們今天來強化一下邏輯
錢包地址
來鑄造NFT如果用戶可以選擇鑄造到哪一個錢包,這樣便會造成單一錢包可以不停的更換輸入的錢包地址
,來達到鑄造多個NFT的效果。用戶不應該可以選擇鑄造NFT到哪個錢包,而是只能鑄造在的自己的錢包
所以我們這邊直接把safeMint()
函式括號中的address to
移除
不過這樣馬上就遇到問題了,我們現在缺少了一個目標錢包地址來進行檢查balanceOf()
以及鑄造_safeMint()
,因為我們把原本的目標錢包to
移除了,怎麼辦呢? 其實我們可以透過與合約互動時內建的變數msg.sender
來取得與此合約互動的錢包地址。所以修改完之後應該會長這樣:
我們目前限制一人只能鑄造一枚NFT的方法是檢查該錢包是否擁有此NFT系列,不過這樣做很明顯會遇到一個問題,用戶可以鑄造完後將NFT轉至其他錢包再繼續進行鑄造,這樣變成功繞過了一人只能鑄造一枚的規則。怎麼防範呢? 我們應該建立一個清單來紀錄誰有鑄造過,而每次執行鑄造時就會檢查該清單,用這樣的方法來防止此種情況發生。
我們這邊先建立一個Mapping,而Key跟Value的屬性分別設定為address
以及bool
,分別用來記錄用戶的地址以及是否鑄造過,每次呼叫時填入地址便會直接回傳布林值。
我們先將原本的檢查方式balanceOf()
刪除
將鑄造函式的條件加入Mapping,查看互動的地址是否鑄造過(預設為false
)
若回傳的值為false
則代表可以鑄造
而鑄造後我們將該錢包Mapping內的資料改成true
這樣下次檢查時就會被擋掉了,完成應該會長這樣
做到這邊如果你想要允許用戶可以不只鑄造一次而是2次或以上
可以在Mapping中把值設定成unit256
的屬性, 並在require
條件式檢查是否符合MAX_PER_WALLET
變數
而每次鑄造成功時在對Mapping中的值進行+1
由於我們只允許用戶鑄造一次, 使用boolean
值會更有效率
而以下也就可以把MAX_PER_WALLET
移除了(本篇文章的截圖均未移除)
一樣先編譯Compile合約,並且佈署上測試鏈Goerli
並且執行safeMint()
的函式進行鑄造
可以看到已經不需輸入錢包地址了!
(然後留意一下我們現在使用帳戶2來鑄造NFT)
現在我們到測試網OpenSea檢查一下
成功! 接著我們點擊右上角的Transfer轉移NFT到其他錢包
並填入錢包1的地址,點擊Transfer
完成,可以點擊左邊的View Item查看現在的擁有者是誰確認
現在讓我們回到Remix上看看還能不能用帳戶2再鑄造一次
不行鑄造了! 即使我們轉移了NFT至其他帳戶也一樣!
大成功
今天我們修正了每人只能鑄造一枚NFT的邏輯,透過Mapping的方式直接紀錄每個地址是否鑄造過並以布林值回傳,若為false
則可以鑄造,true
則不行。明天讓我們來設定NFT的MetaData吧!包括了圖片/屬性/顯示名稱等,不過圖片要請大家自行準備好喔! 我們明天見
<上一篇> [Day 26] 建造鐵人賽專屬NFT!(三)設定NFT總數, 並限制一人只能鑄造一個
<下一篇> [Day 28] 建造鐵人賽專屬NFT!(五)設定圖片/名稱Metadata並上傳至IPFS!