EIP-3664合约研究笔记05–扩展属性分析
1 属性介绍
DRepublic Labs团队认为NFT721协议中的属性值都是固定不变的,不适用于复杂多变的游戏应用,提出了3664协议,希望给NFT721协议额外增加扩展属性, 目前 EIP-3664 已经实现了六种核心属性操作:可升级,可修改,可添加,可移除,可拆分,可组合。
一般的游戏属性分类:
通用属性:用于描述头像出生日期等不可变属性。
变量属性:用于描述其值会发生变化的属性,例如分身的战斗力。
可转移属性:用于描述可以转移到其他 NFT 的属性。
可升级属性:用于描述 NFT 级别并可以触发升级。
可进化属性:用于描述 NFT 可以进化,进化可以失败,如果失败的情况下,NFT 不能再使用,直到正确修复。
Erc-3664扩展了Erc-1155,并将游戏的非功能属性分为四类:
1.一般变量属性:一般指NFT攻击强度、生命值等基本属性。其功能包括增加或减少属性值。
2.可转让财产:指非功能材料在损坏或其他情况下可以转让给其他非功能材料的可转让财产。
3.可升级属性:指根据公式可以升级的NFT。玩家支付费用,这反映在等级的增加,通常伴随着其他属性值的增加。
4.可演化属性:指非功能功能函数随时间自动演化的属性(链块高度),模拟现实世界中的时间属性,使非功能函数具有时变特性。
基于以上四种属性类,我们设计了四种通用属性契约,开发人员可以根据游戏逻辑设计不同的支持合同。
2 合约类关系图
3 一般通用合约–ERC3664Generic
ERC3664Generic合约相比ERC3664合约,具备权限控制(MINTER_ROLE、ATTACH_ROLE)。
在构造函数中设置了权限: 部署合约的用户注册为权限(MINTER、ATTACH),以后该用户就可以发起调用Mint、Attach函数了。
constructor() ERC3664() {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, _msgSender());
_setupRole(ATTACH_ROLE, _msgSender());
}
// mint()
require( hasRole(MINTER_ROLE, _msgSender()), “ERC3664Generic: must have minter role to mint”);
// attach()
require( hasRole(ATTACH_ROLE, _msgSender()), “ERC3664Generic: must have attach role to attach” );
4 可转移合约–ERC3664Transferable
这个合约比较难以理解,目的是把代币A添加的属性1转移给另一个代币B,听起来还是不明所云,举个例子看看:
假设Legoot项目tokenA具备一套装备属性,其中一个优秀属性“力量+10”。tokenB非常眼红,自己没有这个属性啊,土豪不差钱,马上买过来。 tokenA答应了,收了钱把这个属性转移给tokenB。在这个过程中就像转移属性就像基因一样转移。
转移属性需要满意一些前提条件:
tokenA的拥有者是msgsender
tokenA的拥有者授权属性attrId转移给tokenB
tokenB作为接收方不能有属性attrId。
transferFrom转移的具体过程:
_balances[attrId][to] = amount; // 设置接收方的属性余额,意味着就有了该属性attrId
delete _balances[attrId][from]; // 删除发送方的属性记录,意味着就发送方从此没有了该属性
delete _allowances[attrId][from]; // 删除发送方的授权记录
approve的过程
保证接收tokenId没有该项属性,才能设置授权成功
关于内置的nft:
constructor(address nft) ERC3664Generic() {
_nft = nft;
_setupRole(TRANSFER_ROLE, _msgSender());
}
modifier onlyHolder(uint256 tokenId) {
require(
ITokenHolder(_nft).holderOf(tokenId) == _msgSender(),
“ERC3664Transferable: caller is not the nft holder”
);
_;
}
在构造函数中需要填写一个NFT合约地址,用于后面检查发送方tokenId的所有者,需要满足 ITokenHolder接口。
这样就说明转移属性的代币合约必须实现 ITokenHolder接口,那么以前发行的普通类721合约就不能使用了,必须用实现了该接口的新721合约才行。
如何实现 ITokenHolder接口? 没有找到相关实现代码,估计要增加map类变量进行保存和查询了。
【转移属性与合并的区别?】
通过转移操作可以得到别人的属性,通过合并操作可以得到其他NFT,也同时带来了新的属性值。 那么这二者到底有哪些异同呢?
相同点: 主体NFT都具备了新的属性
差异性: 转移过程仅仅是属性的流转,不涉及到token的所有权转移。
合并是发生了token所有权的转移, 顺带着把子代币的主属性作为主代币的次要属性,性质是搂草打兔子。
5 可更新合约–ERC3664Updatable
可更新合约的设计目的—增加、减少属性的余额, 移除属性。
增加属性余额:
increase()
检查属性存在
检查tokenId拥有属性
余额+=amount
减小属性余额:
decrease()
检查属性存在
检查tokenId拥有属性
余额-=amount
移除属性: 是attach添加属性的反操作, 把 次要属性从主体NFT中剥离出去。注意只能移除次要属性,主要属性是无法移除的。
remove()
检查属性存在
属性余额>0, 表示tokenId拥有属性
删除余额
次要属性数组中删除属性id
6 可进化合约– ERC3664Evolvable
功能: 随着时间可以按照概率提升等级, 也可以设计成物品随着时间老化。
(1)类继承关系图:
ERC3664Evolvable —> ERC3664Generic —> ERC3664
(2) 工作过程:
mintWith 铸造主体NFT,属性元数据仓库中添加 新的属性元数据
attach 给代币添加属性,设置属性的等级、诞生区块、下一个升级区块。
evolutive 升级属性
repair 升级失败后修复属性
铸造NFT调用顺序
ERC3664Evolvable mintWith
—> ERC3664Generic mint
—> ERC3664 _mint
铸造NFT时要指定 升级概率和区块间隔数组。
uint8[] memory probabilities,
uint256[] memory evolutiveIntervals
(3) 升级计算过程
先计算随机数
seed = keccak256(用户地址+区块号+时间戳+区块难度系数)%100
判断随机数是否小于等级概率值, 小于就表示幸运的升级,Level++,更新下一个升级区块号。
大于就是很不幸的升级失败,状态设置为false, 表示NFFT不能再使用啦。
(4) 修复过程
状态恢复为true, 下一个区块号重置。
【示例】 属性的升级概率值[50, 20, 10], 升级间隔值[1000,2000,4000,8000],
意味着,Level 1 升级概率分别是50%,20%, 10%, 可升级3次,Level= 1、2、3、4 。
Level1升级必须经过1000个区块时间, 第二次升级必须再经过2000个区块时间。
【注意】概率数组和间隔数组长度不相等, 升级次数以概率数组长度决定。间隔数组长度多一个元素,不然的话最后一次升级后就无法设置正确的间隔时间了。
————————————————
版权声明:本文为CSDN博主「快活林高老大」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012084827/article/details/127119159