• ERC4907:租赁中介,让你的NFT租赁像租房一样简单


    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. 初识ERC4907 

    ERC4907 是 ERC721 的扩展,新增了赋予 NFT 使用权的角色权限,能在为 Owner 保留所有权的同时拆分其持有 NFT 的使用权,可用于 Decentraland、STEPN 等项目中 NFT 资产的租赁场景。

    2. 一个重要的数据结构及映射

    数据结构 UserInfo 中包含两个关键变量:user 和 expires。user 用于存放具备 NFT 使用权的用户地址,expires 则保存使用权的到期时间。

    数据结构 UserInfo 将作为映射 _users 的 value ,NFT 的 id 是该映射中的 key。

    1. struct UserInfo {
    2. address user; // address of user role
    3. uint64 expires; // unix timestamp, user expires
    4. }
    5. mapping (uint256 => UserInfo) internal _users;

    3. 一个唯一的事件

    事件 UpdateUser 共接收三个参数:NFT id 、被赋予使用权的用户地址 和 使用权的到期时间,该事件将在 NFT 用户使用权发生变更时被触发。

    1. // Logged when the user of a NFT is changed or expires is changed
    2. /// @notice Emitted when the `user` of an NFT or the `expires` of the `user` is changed
    3. /// The zero address for user indicates that there is no user address
    4. event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);

    4. 使用权赋予接口

    接口 setUser 接收三个参数:NFT id 、被赋予使用权的用户地址 和 使用权的到期时间,用于赋予(更新)传入地址对特定NFT在指定时间前的使用权限。

    该接口首先要求调用者是传入 NFT 的 owner 或具备操作该 NFT 的权限,然后将传入的用户地址和到期时间存入数据结构 UserInfo ,并将该数据结构作为 _users 映射中键 NFT id 的值进行存储,最后触发事件 UpdateUser 。

    1. /// @notice set the user and expires of a NFT
    2. /// @dev The zero address indicates there is no user
    3. /// Throws if `tokenId` is not valid NFT
    4. /// @param user The new user of the NFT
    5. /// @param expires UNIX timestamp, The new user could use the NFT before expires
    6. function setUser(uint256 tokenId, address user, uint64 expires) public virtual{
    7. require(_isApprovedOrOwner(msg.sender, tokenId), "ERC4907: transfer caller is not owner nor approved");
    8. UserInfo storage info = _users[tokenId];
    9. info.user = user;
    10. info.expires = expires;
    11. emit UpdateUser(tokenId, user, expires);
    12. }

    5.  使用权查询接口

    接口 userOf 用于查询指定 NFT 的使用者地址。该接口接收 NFT id 作为参数,首先通过映射 _users 找到数据结构中使用权的到期时间,并将其与当前区块时间进行对比,若大于当前区块时间,则返回数据结构中的使用者地址,否则返回 0 地址。

    1. /// @notice Get the user address of an NFT
    2. /// @dev The zero address indicates that there is no user or the user is expired
    3. /// @param tokenId The NFT to get the user address for
    4. /// @return The user address for this NFT
    5. function userOf(uint256 tokenId) public view virtual returns(address){
    6. if( uint256(_users[tokenId].expires) >= block.timestamp){
    7. return _users[tokenId].user;
    8. }
    9. else{
    10. return address(0);
    11. }
    12. }

    6.  使用期限查询接口

    接口 userExpires 用于查询指定 NFT 使用权的到期时间。该接口接收 NFT id 作为参数,并将其作为键,在映射 _users 中找到数据结构,并返回数据结构中的到期时间。

    1. /// @notice Get the user expires of an NFT
    2. /// @dev The zero value indicates that there is no user
    3. /// @param tokenId The NFT to get the user expires for
    4. /// @return The user expires for this NFT
    5. function userExpires(uint256 tokenId) public view virtual returns(uint256){
    6. return _users[tokenId].expires;
    7. }

    7. NFT 所有权转移前的特殊操作

    官方给出的参考实现代码中,还给出了一个 _beforeTokenTransfer 内部接口,用于在进行 NFT 所有权转移前清空该 NFT 的使用权。

    该内部接口接收 NFT 转出地址、转入地址和 id 三个参数,首先调用继承来的同名函数,然后进行两个条件判断:一是转出地址不等于转入地址,二是转入地址不为 0 地址。在满足条件的情况下删除 _users 中键为传入 NFT id 的映射,并触发使用权更新事件 UpdateUser,将使用权声明为 0 地址并将过期时间置 0 。

    1. function _beforeTokenTransfer(
    2. address from,
    3. address to,
    4. uint256 tokenId
    5. ) internal virtual override{
    6. super._beforeTokenTransfer(from, to, tokenId);
    7. if (from != to && _users[tokenId].user != address(0)) {
    8. delete _users[tokenId];
    9. emit UpdateUser(tokenId, address(0), 0);
    10. }
    11. }

    至此,ERC4907 的接口都已介绍完毕,你学会了嘛~

  • 相关阅读:
    《征服数据结构》目录
    一、springcloud-eureka服务注册与发现
    [mit6.1810] lab Utilities
    WinBUGS对多元随机波动率模型:贝叶斯估计与模型比较
    Hadoop3教程(十五):MapReduce中的Combiner
    自行车租赁管理系统
    【postgresql 基础入门】psql客户端的使用方法
    MATLAB——一维离散小波的单层分解
    C++ PrimerPlus 复习 第四章 复合类型(下)
    华为云中对象存储服务软件开发工具包(OBS SDK) C语言介绍
  • 原文地址:https://blog.csdn.net/weixin_45267471/article/details/125633923