从合约考量项目价值-兔子

我比较喜欢的项目兔子,最近开盒了,玩法还是挺不错的,可惜中奖绝缘体的我并没有第一时间获得带有塔罗牌属性的兔子。今天抽时间从技术角度浅分析下项目玩法如何实现的。

玩法介绍

每只兔子除了拥有基础的部件属性外(body、ears等),还额外拥有一个“隐藏属性”(因为有些开了,有些没开,所以我们这里暂且称之为隐藏属性),根据兔子项目白皮书描述,隐藏属性有78只最稀有的NFT在开盒时就会开启,其余的也可以通过一些特殊途径开启(具体方式没有细说,估计后续会公布)。里面有一点比较吸引我:隐藏属性每天可变,而且是表现在图片上,这点我开始没想明白,今天就从合约代码看看能否找到一些线索。

合约代码-盲盒

项目方采用盲盒(ERC-1155)与NFT(ERC-721)分开的方式实现,可能是为了尽可能减少发售时用户的铸造费用,因为1155对于批量铸造的支持非常友好,批量铸造10个和铸造1个气费相同。

盲盒中代码没有特别要说的,这里看下开盒代码:

开盒方法
开盒方法

只有这一个单个开盒的方法,先销毁1155盲盒,再调用NFT的mintTransfer方法下发NFT。

合约代码-NFT

开盒开启隐藏属性

通过这段代码,可以看到3261 - 3184 = 77,由于是>= 所以刚好有78只NFT在开盒的时候就会解锁luckyCard属性

NFT合约-开盒
NFT合约-开盒

开启隐藏属性扩展口

主动开启隐藏属性入口
主动开启隐藏属性入口

通过代码或注释已经可以比较清楚的看到项目方多方面布局,不仅可以通过做各种各样的任务来自动解锁 unlock(),也可以自己获取授权来解锁 unlockBySelf() 。

有趣的是,居然还有能开启隐藏属性的地方:

post image

不过这里有点疑惑,为什么仅仅发了个event,并没有真的修改luckyCardStatus?于是有道了下这句注释:

post image

金额合理这个方法会在transfer时调用,也就是在转手时会触发这段逻辑,也就是在交易所上以高于特定价格的交易来触发,估计是借助中心化服务完成的金额校验。

再看白皮书,并没有这个关于特定价格说明,看项目方后续的动作吧,也算是一个开启隐藏属性的方式。

隐藏属性每日可变

我刚看到这个的时候就在思考怎么实现?如果是我的话,可能会采用拼接svg的方式,但拼接svg的方式需要把图片部件数据全部代码化并写到合约上,像素风还行,这种非像素类型的作品图片较大且难压缩,那在这个合约里面:

tokenURI()
tokenURI()

好吧,还是比较简单粗暴的,根据当天luckyCard来返回对应的图片。不过这种方案也是很大缺点,即整个系列的图要准备78套,为了实现这个功能也是挺费劲的了。

其中最核心的方法是luckyCardValue(),这个方法为什么能保持一天内返回值不变?撸代码:

luckyCardValue()
luckyCardValue()

这个方法我看了半天,可以看到已开启隐藏属性的NFT获取今天的luckyCard时,是随机的,取(1970.1.1 00:00:00 到现在的天数)、(盐evenSalt/ollSalt)、(tokenId)的hash值,其中天数在一天之内都不会变,tokenId一直都不会变,中间这个盐在每次交易时都会重新计算:

盐

这里设计比较有意思,为了保证修改盐不会改变当天的luckyCard,他这里分了“奇数盐”和“偶数盐”,当天是奇数天修改偶数天的盐,当天是偶数天修改奇数天的盐。

同时也在某种程度上保证了第二天的属性不可预测。

扩展

支持升级,但不清楚具体是以什么方式展开,留了一个悬念。

预留升级
预留升级

总结

关于随机数这块,应该是考虑到用户体验,他这里并没有选择VRF,但也没有太大问题,因为这种实现方式也已经规避了预测属性值带来的风险。

最后广告下,我会持续分析NFT合约代码,从合约出发考量项目价值,可以关注twitter