本文是上上篇文章《如何在一级市场发行NFT(1):区块链合约开发》的姊妹篇,本来想直接为大家跑一遍合约代码演示发行过程,但是和很多朋友交流后,大家对于NFT这个实体有很多困惑,NFT是一张图片吗?在表现层确实是的,但它的内核是什么?所以本文是试图回答这个问题的,当你花了10万元买了个NFT,你买到的究竟是什么?另外经过这篇文章我们会推演出一个我认为非常大的漏洞可能会让你的NFT变为废纸,本文可能会影响你对于目前NFT价值的认同,但长期来看NFT依然向好。
NFT的全称是Non-Fungible Token非同质化代币,在网上可以搜到很多对于这个概念的解释,但是目前找到的资料都比较抽象模糊,相信你看完本文,会更清晰到底怎么就“非同质化”了。
建议各位先翻一下之前那篇区块链合约开发的文章,本文中会用到大量上篇文章的内容。
首先将上次使用的Doodles代码进行部署,因为等下要在opensea查看所mint的NFT,所以这次使用Injected Web3测试网络环境部署,同时需要将你的小狐狸钱包也切换为Rinkeby网络。
这次部署你会发现右上角的小狐狸会提示你要付gas费,因为我们使用了测试网进行部署,测试网也是需要上链的,所有在区块链的写入操作均需要缴纳gas费。
部署完成后,我们需要使用setBaseURI来设置每个NFT对应的URI地址,以后我会单独讲什么是URI,这里你可以先简单理解为它是存储NFT图片数据的一个网络链接地址,我们使用Doodles的URI进行测试。
然后使用reserve来mint2个NFT,同样这里也需要缴纳gas费。
mint成功后,我们来到opensea测试网络,可以看到你居然拥有了2个价值50万的Doodles!哈哈别激动,这只是测试网。
我们回到编译器,调用totalSupply接口,可以查看到目前总共产生了2个NFT,这2个就是刚才我们mint的。
tokenURI这个接口可以查询某个NFT对应的表现层数据地址,我们输入编号1可以看到出现了一串字符,字符最后有一个对应的数字编号1。
我们将这串字符复制粘贴到浏览器,可以看到出现了一个json文件,这里面就存储了所有和这个编号为1的NFT的表现层数据,包括image地址,以及attributes属性,平时我们聊到的某个NFT很稀有,这个稀有就是从该属性中读取到的。
我们将image的地址复制粘贴到浏览器中,就可以发现打开的图片和我们刚才在opensea看到的是一样的。
所以到这里你应该明白了,我们在opensea看到的NFT,注意是“看到的”,都是存储在这个URI中的。
ownerOf是一个可以检索某个NFT是谁持有的接口,我们输入1就可以查看到编号为1的NFT持有者地址。
所以查询某个NFT是由谁持有的,输入的是什么?是一个数字编号,是从1到N的一个数字,这个数字是写入区块链中的,不可被篡改。
到这里答案清晰了,当你在买NFT时,你买到的是一个编号。
其实这里会引申出一个问题,我们刚才说到NFT的表现层即图片、属性等都是存在URI中的,但是还记得吗,我们的URI是部署后使用setBaseURI设置的,那是否意味着这个URI地址是可以改的呢?我们来试一下。
在setBaseURI中输入另外一个URI并提交。
然后我们再调用tokenURI检查一下编号1的NFT,这时会发现它的URI确实被改了。
我们再刷新一下opensea中刚才mint的其中一个NFT的地址,会赫然发现被刷新的那个NFT居然变成了无聊猿!
其实这里是细思极恐的,我们都认为NFT是运行在区块链上不可被篡改的,但是实际上包括Doodles在内的大量NFT都只是将编号存在了区块链上,而对应的表现层均是使用外部接口推进去的,那就意味着,你手里持有的NFT,其实是可以随时被改成另外一副你完全不认识的模样,可能昨天你还持有稀有度0.01%价值100万的NFT,只要项目方愿意,今天他就可以给你改成一坨狗屎。
我不清楚opensea是否有制定相关的规则杜绝这种情况,至少在我实际运行代码时确实发现了这个问题。
总结一下,在当前opensea里,你购买的NFT,是一个数字编号,你没有买图片,也没有买任何你能看到的东西,你真正买到的,只是一个编号。
至于这个漏洞该如何处理?目前来看只能靠项目方的自觉与理智,如果有丧心病狂的项目方,完全不要口碑与收益,他就可以将所有的NFT变得一文不值。除非是未来URI也需要存储到区块链中而不是通过接口推进去。
如有不对的地方非常欢迎指正讨论,我并不是唱衰NFT,我反而非常看好NFT的前景,只是作为一个如此早期且发展迅速的领域,一定会有一些不完美的地方值得我们去改进。