NFT不仅是图像所有权的加密保证。在相同的技术支持下,事情会根据我们如何工作、互动而改变。说到实用NFT,在某些情况下,所有者和用户并不总是相同的的。NFT的所有者可以将它租给用户一段时间。在此期间,用户暂时获得了NFT给予的特权,但不能转让其所有权。
NFT不仅是图像所有权的加密保证。在相同的技术支持下,事情会根据我们如何工作、互动而改变。
这里所说的是实用NFT,它们赋予所有者某些特权、权利或奖励。
例如,在游戏领域,实用NFT提供了一种管理游戏内资产所有权的新方法,或者在社交空间中,它们有助于确保用户能够安全地进入专属社区。
另一个用例可能是绑定到“可租赁的智能物理资产”(例如储物柜、度假屋或汽车)相关联的 NFT,在证明他是 NFT 的当前所有者之后,用户可以对其发送命令(例如“锁门”、“解锁门”)。
说到实用NFT,在某些情况下,所有者和用户并不总是相同的的。NFT的所有者可以将它租给用户一段时间。在此期间,用户暂时获得了NFT给予的特权,但不能转让其所有权。
现在有一个用于可租赁的 NFT 的 EIP(EIP- 4907),它指出:
“该标准是EIP-721的扩展。它提出了一个可以授予地址的附加角色(用户),以及该角色被自动撤销(到期)的时间。用户角色代表“使用”NFT的权限,但不代表转移或设置用户的能力。
该标准旨在与 ERC-721 完全兼容,并且基本上引入了一个接口来实现(IERC4907.sol),方法如下:
function setUser(uint256 tokenId, address user, uint64 expires)
如果调用者是NFT的所有者或已被授予的地址,则此方法可以设置新用户和NFT的到期时间。
function userOf(uint256 tokenId) external view returns(address);
这将返回NFT当前用户的地址,其中的零地址表示没有用户或租期已过。
function userExpires(uint256 tokenId) external view returns(uint256);
最后一个方法返回NFT用户的到期时间,其中0表示没有用户。
在此期间,我们会注意到合约是如何扩展ERC721标准的,并也会注意到使用 NFT 与其最终用户之间的映射以及到期时间。
contract ERC4907 is ERC721, IERC4907 {
struct UserInfo
{
address user; // address of user role
uint64 expires; // unix timestamp, user expires
}
mapping (uint256 => UserInfo) internal _users;
…
“如果EIP的标题是Rental NFT,那为什么IERC4907或参考实现缺乏一个“租赁”方法呢”?
有一个setUser方法,但是使用它时,只有NFT的所有者(或已被批准的地址)才可以设置用户。在本例中,这个过程听起来更像一个贷款过程,所有者将与公用事业NFT绑定的特权借给用户,此外,还为此支付gas费用。
我的想法类似于:
在这里,所有者可以选择:
将他的NFT设置为可租赁。
设置在一段时间内租用他的 NFT 所需的以太币数量。
如果NFT被列为可租赁,用户就有能力租它,并为此向所有者支付费用。
想要租用NFT的用户必须向合约发送一个交易,指定他想要租用的NFT以及租用的时间。此外,交易必须在所选时间间隔内具有正确数量的以太币。
让我们看看solidity代码的相关部分:
contract RentableNFT is ERC4907, Ownable
当然,RentableNFT合约扩展了参考实现ERC4907和OpenZeppelin Ownable合约(Ownable扩展不是绝对必要的,但在这个合约中,我希望只允许合约的所有者铸币)。
uint256 public baseAmount = 1000000000000000; //0.001 ethers
struct RentableItem {
bool rentable;
uint256 amountPerMinute;
}
mapping(uint256 => RentableItem) public rentables;
baseAmount是租赁一分钟的默认支付金额。
RentableItem是一个结构,用于存储关于某个NFT的可租性和费用的信息。
rentables是NFT和RentableItem结构之间的映射。
function mint() public onlyOwner {
currentTokenId.increment();
uint256 newItemId = currentTokenId.current();
_safeMint(owner(), newItemId);
rentables[newItemId] = RentableItem({
rentable: false,
amountPerMinute: baseAmount
});
}
默认情况下,在mint函数中,新创建的NFT:
是给合约的所有者的;
被设定为不可租;
它的费用设置为baseAmount。
function setRentFee(uint256 _tokenId, uint256 _amountPerMinute) public {
require(_isApprovedOrOwner(_msgSender(), _tokenId), "Caller is not token owner nor approved");
rentables[_tokenId].amountPerMinute = _amountPerMinute;
}
这是NFT的amountPerMinute值的设置方法。此方法只能由NFT的所有者(或已被批准的地址)调用。
function setRentable(uint256 _tokenId, bool _rentable) public {
require(_isApprovedOrOwner(_msgSender(), _tokenId), "Caller is not token owner nor approved");
rentables[_tokenId].rentable = _rentable;
}
这个方法会设置一个NFT的可租赁布尔值。此方法只能由NFT的所有者(或已被批准的地址)调用。
function rent(uint256 _tokenId, uint64 _expires) public payable virtual {
uint256 dueAmount = rentables[_tokenId].amountPerMinute * _expires;
require(msg.value == dueAmount, "Uncorrect amount");
require(userOf(_tokenId) == address(0), "Already rented");
require(rentables[_tokenId].rentable, "Renting disabled for the NFT");
payable(ownerOf(_tokenId)).transfer(dueAmount);
UserInfo storage info = _users[_tokenId];
info.user = msg.sender;
info.expires = block.timestamp + (_expires * 60);
emit UpdateUser(_tokenId, msg.sender, _expires);
}
这里的核心租用方法:
计算租赁NFT的到期金额
验证发送的金额是否正确
验证NFT是否已经被其他人租用
核实NFT是否被其所有者更改为可租赁
将应付金额转给NFT所有者
更新用户信息和到期时间
Source:https://medium.com/coinmonks/rentable-nft-eip-4907-how-can-be-improved-b20a1b5a27bf
ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!