# 源码解读：以太坊新标准EIP-4907是如何实现NFT租赁的？

By [shisi.eth](https://paragraph.com/@shisi-eth) · 2022-10-01

---

内容概要
----

在这周，NFT 租赁市场 Double Protocol 提交的可租赁 NFT 标准“EIP-4907”通过了以太坊开发团队的最终审核，成为第 30 个 ERC 标准“Final”的状态。

让我们一起来阅读这极简的源代码，来缕清其他是如何实现NFT租赁的？

**目录大纲**

1.  为什么需要租赁?
    
2.  源码解读 2.1 实现原理&数据结构 2.2 设置用户 2.3 查询用户&过期时间 2.4 租赁关系的强制性设计
    
3.  总结
    

为什么需要租赁？
--------

NFT 的爆发毋庸置疑，而伴随普及引发了对其资产实用性的需求，尤其是在元宇宙和边玩边赚 (P2E) 的场景下，仅仅单纯的资产所有权并不足以支撑更多的应用玩法的诞生。

一直的痛点是供给不平衡，导致的好项目少，浮于金融玩法的韭菜项目多，既然如今web3有大量web2行业精英在涌入，也必然需要快速的新标准推出，来将创造力的供给释放。

NFT流动性的紧缺，使得他风风火火的同时也备受诟病，他之前产权一体化的金融化操作，市场各类安全问题欺诈、剽窃、钓鱼、跑路、资产被盗层出不穷。

而Eip-4907，想要解决的就是分离NFT的资产价值和使用价值，释放出NFT的市场流动性

### 源码解读

由于Eip4907极其简单，因此对代码的解读无论是否技术同学均可来尝试理解其细节设计。

### 2.1 、实现原理：

他作为 ERC-721 的扩展， EIP-4907 增加了一个变量UserInfo，让应用可以查询此NFT当前被租出去的目标地址“user”和出租时间”expires"。如果发现已经超出出租时间，则租赁关系宣告失效。

代码极为简单仅有72行，使用这个标准，就是在原来的ERC721之上新增

*   1个事件（用于通知链下应用称为事件）
    
*   3个方法（用于实现链上数据管理功能）
    

分别是

*   UpdateUser 事件：当NFT转移，租赁校色设置时，发出租赁用户改变的通知
    
*   setUser 方法：NFT所有者授权者可用，设置此NFTID的出租用户和过期时间
    
*   userOf 方法：任何人可用，查询此NFTID的出租用户
    
*   userExpires 方法：任何人可用，查询此NFTID的过期时间
    

### 2.1 、数据结构：

理解ERC标准协议的最佳方式就是理解他管理数据的最底层数据结构

例如：前文[【源码解读】你买的NFT到底是什么？](https://mp.weixin.qq.com/s?__biz=MzIyMTQ5MTg5Mw==&mid=2247483815&idx=1&sn=5f91df631b450944739419be185e597c&chksm=e83aa67ddf4d2f6bf24b9f6139bd685db9b5f3ff5a131f84c179a5166ad42337f0b2aabe0bf0&scene=21#wechat_redirect)

其实NFT只是通过2个映射（\_owners，\_balances），即一种字典形式的key-value对应关系的存储结构去记录数据

    mapping(uint256 => address)  _owners;// 记录每一个NFTID当前对应的所有者地址
    mapping(address => uint256)  _balances; //记录了当前所有者总计持有的NFT数量
    

而Eip-4907则是新增了一个数据对象UserInfo在所有权的概念之外**增加“用户”的维度**

数据结构简单，就意味着管理的方法实现也非常简单

### 2.2、设置用户setUser 方法

设置用户仅有3个步骤

*   【审计】此交易的发起者其是否持有此NFTid或是有Approved自动扣款权利
    
*   【设置】设置UserInfo中用户的用户地址和到期时间
    
*   【通知】发出设置成功的UpdateUser事件
    

    function setUser(uint256 tokenId, address user, uint64 expires) public virtual{
      require(_isApprovedOrOwner(msg.sender, tokenId),"ERC721: transfer caller is not owner nor approved");
      UserInfo storage info =  _users[tokenId];//新增存储登记信息
      info.user = user;   
      info.expires = expires;
      emit UpdateUser(tokenId,user,expires); //发出事件通知链下应用
    }
    

### 2.3、查询NFTid的用户信息

媒体处处宣传的超时自动失效，而无需二次链上交易登记失效节约gas的逻辑就在这了。

查询的逻辑很简单，按指定的NFTID查询\_users的user信息即可，但他增加了，if判断，当前块的时间block.timestamp是否会超过设置的过期时间expires，所以此查询仅在时间内有效。

### 2.4、查询NFTid的用户过期时间信息

此处无需类似user查询时候判断是否过期，因为得知上一次过期时间，也是加快NFT用户使用率的一种方式。

    function userExpires(uint256 tokenId) public view virtual returns(uint256){
            return _users[tokenId].expires;//执行此函数，返回此ID的用户过期时间
        }
    

### 2.5、租赁关系的强制性设计

此eip4907的协议，对标准交易方法Transfer增加了一部分内容，通过\_beforeTokenTransfer实现，就是强制在进行Transfer交易转移后就删除掉这部分对用户的信息，并且发出事件通知已经用户失效了。

    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);// 发出事件通知已删除
            }
        }
    

总结
--

没想到吧，这么快就代码讲完了，因为确实他写完了，对的，不像是之前的通过限制转移权的方法EIP-5058，见前文[【EIP-5058 能否防止NFT项目方提桶跑路？】](https://mp.weixin.qq.com/s?__biz=MzIyMTQ5MTg5Mw==&mid=2247483797&idx=1&sn=8bdd641eb4316baad1e91fb0e815c613&chksm=e83aa64fdf4d2f59e8f76f5dd54c1c287b230a2201fd80e9d21b8752fdd53c02494beff533ef&scene=21#wechat_redirect)

其实他EIP-4907只是多了个变量，并称之为租赁用户而已，可以声明，但是其他应用认不认就是另一码事了，毕竟其强制性有限，转移就能强行终止出租授权

当然你或许会问，为什么这么简单反而火速成为了难得一见，且每次都能掀起一番波浪的Final标准呢？

这也就是web3的哲学：**越简单，越优雅，剩下的交给共识。**

我个人认可这样的哲学与趋势

web3过去爆发或是得益于金融操作，但是好的生态不能只是金融价值，还需要更有商业价值，需要更广大的用户融入于生活生产形成价值闭环，货币终究只是手段而不是目的本身

关注十四，用技术的眼光发现价值。

看到这里，帅气的你不点个赞吗?

![](https://storage.googleapis.com/papyrus_images/b48f70bbbea572ee015d69b3cc0cb9b004349b41bd23b1e91ba285c352944d08.png)

---

*Originally published on [shisi.eth](https://paragraph.com/@shisi-eth/eip-4907-nft)*
