Hello ~ 大家好,首先感谢大家对本系列前两篇文章 👇👇👇 的喜爱,不知读者们都学废(不是,是学会)了吗?
ERC20:从入门到飞起,妈妈再也不用担心我不会写Token合约了
ERC721:全生命周期精析,妈妈再也不用担心我不会玩NFT合约啦
ERC1155: 批发小能手,妈妈再也不用担心网络拥堵造成的gas费飙升啦|猿创征文
今天主要想跟大家聊的是 ERC4907,于昨日(6月29日)新鲜过审。本文将基于官方给出的参考实现代码对ERC4907中的 UpdateUser 事件,和 setUser、userOf、userExpires三个接口展开详细介绍。由于篇幅有限,文章内容只能尽量做到通俗易懂,但其中不可避免地可能涉及一些新手不友好的概念,您可以查阅相关博客做进一步了解,本系列博客也会不断扩充、提升及优化,尽量做到不留死角,人人都能上手Solidity标准开发。
———————————————————————— 分割线 ————————————————————————
0. ERC 是什么鬼?ERC 全称 Ethereum Request For Comment (以太坊意见征求稿), 是以太坊上应用级的开发标准和协议(application-level standards and conventions),为以太坊开发人员提供了实施标准,开发人员可以使用这些标准来构建智能合约。
ERC 的雏形是开发人员提交的EIP(Ethereum Improvement Proposals),即新的ERC标准提案,一旦其得到以太坊委员会的批准并最终确定,新的ERC便由此诞生。
1. 初识ERC4907ERC4907 是 ERC721 的扩展,新增了赋予 NFT 使用权的角色权限,能在为 Owner 保留所有权的同时拆分其持有 NFT 的使用权,可用于 Decentraland、STEPN 等项目中 NFT 资产的租赁场景。
2. 一个重要的数据结构及映射数据结构 UserInfo 中包含两个关键变量:user 和 expires。user 用于存放具备 NFT 使用权的用户地址,expires 则保存使用权的到期时间。
数据结构 UserInfo 将作为映射 _users 的 value ,NFT 的 id 是该映射中的 key。
struct UserInfo {
address user; // address of user role
uint64 expires; // unix timestamp, user expires
}
mapping (uint256 => UserInfo) internal _users;
3. 一个唯一的事件
事件 UpdateUser 共接收三个参数:NFT id 、被赋予使用权的用户地址 和 使用权的到期时间,该事件将在 NFT 用户使用权发生变更时被触发。
// Logged when the user of a NFT is changed or expires is changed
/// @notice Emitted when the `user` of an NFT or the `expires` of the `user` is changed
/// The zero address for user indicates that there is no user address
event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);
4. 使用权赋予接口
接口 setUser 接收三个参数:NFT id 、被赋予使用权的用户地址 和 使用权的到期时间,用于赋予(更新)传入地址对特定NFT在指定时间前的使用权限。
该接口首先要求调用者是传入 NFT 的 owner 或具备 *** 作该 NFT 的权限,然后将传入的用户地址和到期时间存入数据结构 UserInfo ,并将该数据结构作为 _users 映射中键 NFT id 的值进行存储,最后触发事件 UpdateUser 。
/// @notice set the user and expires of a NFT
/// @dev The zero address indicates there is no user
/// Throws if `tokenId` is not valid NFT
/// @param user The new user of the NFT
/// @param expires UNIX timestamp, The new user could use the NFT before expires
function setUser(uint256 tokenId, address user, uint64 expires) public virtual{
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC4907: transfer caller is not owner nor approved");
UserInfo storage info = _users[tokenId];
info.user = user;
info.expires = expires;
emit UpdateUser(tokenId, user, expires);
}
5. 使用权查询接口
接口 userOf 用于查询指定 NFT 的使用者地址。该接口接收 NFT id 作为参数,首先通过映射 _users 找到数据结构中使用权的到期时间,并将其与当前区块时间进行对比,若大于当前区块时间,则返回数据结构中的使用者地址,否则返回 0 地址。
/// @notice Get the user address of an NFT
/// @dev The zero address indicates that there is no user or the user is expired
/// @param tokenId The NFT to get the user address for
/// @return The user address for this NFT
function userOf(uint256 tokenId) public view virtual returns(address){
if( uint256(_users[tokenId].expires) >= block.timestamp){
return _users[tokenId].user;
}
else{
return address(0);
}
}
6. 使用期限查询接口
接口 userExpires 用于查询指定 NFT 使用权的到期时间。该接口接收 NFT id 作为参数,并将其作为键,在映射 _users 中找到数据结构,并返回数据结构中的到期时间。
/// @notice Get the user expires of an NFT
/// @dev The zero value indicates that there is no user
/// @param tokenId The NFT to get the user expires for
/// @return The user expires for this NFT
function userExpires(uint256 tokenId) public view virtual returns(uint256){
return _users[tokenId].expires;
}
7. NFT 所有权转移前的特殊 *** 作
官方给出的参考实现代码中,还给出了一个 _beforeTokenTransfer 内部接口,用于在进行 NFT 所有权转移前清空该 NFT 的使用权。
该内部接口接收 NFT 转出地址、转入地址和 id 三个参数,首先调用继承来的同名函数,然后进行两个条件判断:一是转出地址不等于转入地址,二是转入地址不为 0 地址。在满足条件的情况下删除 _users 中键为传入 NFT id 的映射,并触发使用权更新事件 UpdateUser,将使用权声明为 0 地址并将过期时间置 0 。
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override{
super._beforeTokenTransfer(from, to, tokenId);
if (from != to && _users[tokenId].user != address(0)) {
delete _users[tokenId];
emit UpdateUser(tokenId, address(0), 0);
}
}
至此,ERC4907 的接口都已介绍完毕,你学会了嘛~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)