Alert Source Discuss
Standards Track: ERC

ERC-5023: 可共享的非同质化代币

用于创建可由多个所有者共享的价值持有代币的接口

Authors Jarno Marttila (@yaruno), Martin Moravek (@mmartinmo)
Created 2022-01-28
Requires EIP-165

摘要

此 EIP 标准化了一个用于非同质化价值持有可共享代币的接口。通过为新的接收者铸造现有代币的副本来实现可共享性。共享和相关事件允许构建一个图,描述谁将什么共享给了哪个参与者。

动机

EIP-721EIP-1155 等 NFT 标准已被开发出来,以标准化稀缺的数字资源。但是,许多非同质化的数字资源不需要稀缺。

我们试图通过新的激励机制来捕捉生态系统中的正外部性,这些机制表现出反竞争逻辑,充当会计单位并充当分享媒介。我们设想可共享代币既可以作为激励,也可以作为通常具有数字性质并且随着共享而获得更多价值的项目的代表。

这些要求促使我们定义可共享的 NFT,更具体地说,是可共享 NFT 的一种变体,称为不可转让的可共享 NFT。这些可共享的 NFT 可以像共享数字商品一样以几乎为零的技术交易成本进行“共享”。我们利用它们来捕获经济系统中正外部性的会计方面的反竞争价值。

典型的 NFT 标准(如 EIP-721 和 EIP-1155)未定义共享模式。相反,ERC 标准定义了典型竞争用例的接口,例如 NFT 合约实现应满足的代币铸造和代币交易。“标准合约实现”可能会将这些标准的功能扩展到接口定义之外。我们在实验中设计和开发的可共享代币被设计为在接口级别上与代币标准兼容。但是,代币合约的实现可能包含扩展功能,以满足实验的要求,例如“可共享性”的要求。在参考标准代币定义时,代币的可共享性可以被认为是将现有代币重新铸造给另一方,同时保留其原始版本。

共享是一个有趣的概念,因为它可以以不同的方式被思考和感知。例如,当我们谈论共享时,我们可以认为它是数字复制,在保留自身版本的同时提供数字资源的副本。共享也可以是部分的,或者共享可能是关于授予使用特定资源的权利。可共享性的概念和可共享性的上下文可以采用不同的形式,并且人们可以对可共享代币的实例使用不同类型的实现。因此,我们没有限制该接口应要求任何特定的代币类型。

可共享代币可以在合约实现级别上设为不可转让。这样做,使它们成为可共享的不可转让代币。在参考实现中,我们从我们的用例中提炼出一个通用案例,该案例使用可共享的 NFT 接口定义了可共享的不可转让 NFT。

我们认为,更广泛的受众应该从更高定义的可共享性的抽象层中受益,例如此接口实现,该接口定义了要实现以满足可共享性概念的最小函数量。

规范

本文档中的关键词“必须(MUST)”,“禁止(MUST NOT)”,“必需(REQUIRED)”,“应该(SHALL)”,“不应该(SHALL NOT)”,“推荐(SHOULD)”,“不推荐(SHOULD NOT)”,“可以(MAY)”和“可选(OPTIONAL)”应按照 RFC 2119 中的描述进行解释。

///  Note: the ERC-165 identifier for this interface is 0xded6338b
interface IERC5023 is IERC165 {

  /// @dev 当代币被共享、重新铸造并给予非函数调用者的其他钱包时,会发出此事件
  event Share(address indexed from, address indexed to, uint256 indexed tokenId, uint256 derivedFromtokenId);

  /// @dev 共享,重新铸造现有代币,为新铸造的代币提供一个新的代币 ID,将原始代币保留在函数调用者的手中,并将新铸造的代币转移给接收者,该接收者应为与函数调用者不同的地址。
  function share(address to, uint256 tokenIdToBeShared) external returns(uint256 newTokenId);

} 

当成功调用函数方法 share 并且在给定代币 ID 的基础上铸造新代币并将其转移给接收者时,预计会发出 Share 事件。

理由

当前的 NFT 标准定义了可转让的非同质化代币,但没有定义可共享的非同质化代币。为了能够创建可共享的 NFT,我们认为现有的 NFT 合约可以使用一个接口进行扩展,该接口定义了共享的基本原则,即共享事件和共享的函数方法。关于如何处理代币的可转让性的定义留给合约实施者。如果允许转让,则可共享代币的行为与现有代币类似,除非在共享时,会保留代币的一个版本。如果禁用转让,则可共享代币将变为可共享的不可转让代币,可以将其铸造和给予或共享给其他人,但不能将其转让出去。

假设 Bob 与 Alice 合作完成一个项目。Bob 获得一个独特的 NFT,表明他为该项目做出了努力,但 Bob 认为他的成就不完全是他自己的功劳。Bob 希望与 Alice 共享他的代币,以表明 Alice 也应该因对他们的项目所做的努力而获得认可。Bob 通过调用合约上的 Share 方法来启动代币共享,该合约具有他的代币,并通过传递地址和代币 ID 参数来指示他希望共享他的哪个代币以及共享给谁。为 Alice 铸造了一个新代币,并启动了一个 Share 事件,以通过记录将代币 ID 共享给谁的地址以及这个新代币源自哪个代币 ID 来传达是 Bob 将他的代币共享给了 Alice。

随着时间的推移,可以从 Share 事件信息中形成树状结构。如果 Bob 共享给 Alice,而 Alice 进一步共享给 Charlie,并且 Alice 也共享给 David,则从共享活动中形成一个基本的树结构。此共享事件数据稍后可用于获得有关代币所代表的共享活动的更多信息。

B -> A -> C 
      \
       >  D

这些树结构可以进一步聚合和折叠成网络表示,例如,基于谁在一段时间内共享给谁的社交图。例如,如果 Bob 将一个代币共享给 Alice,而 Alice 将一个不同的代币共享给 Charlie,并且 Bob 将一个代币共享给 Charlie,则所有这些参与者之间会通过共享活动形成连接。

 B----A----C         
  \_______/

向后兼容性

此提案与 EIP-721 和 EIP-1155 向后兼容。

参考实现

以下参考实现演示了我们其中一个试点的通用用例。在这种情况下,可共享的不可转让代币表示对社区的贡献,合约所有者已决定使用代币来奖励该贡献。合约所有者可以铸造一个奖励代币并将其给予某人。接收者可以进一步将此代币共享给其他方,例如,将收到的优点共享给参与或影响了他的贡献的其他人。

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

import "./IERC5023.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract ShareableERC721 is ERC721URIStorage, Ownable, IERC5023 /* EIP165 */ {

  string baseURI;

  uint256 internal _currentIndex;
    
  constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {}

  function mint(
        address account,
        uint256 tokenId
    ) external onlyOwner {
        _mint(account, tokenId);
  }

  function setTokenURI(
        uint256 tokenId, 
        string memory tokenURI
    ) external {
        _setTokenURI(tokenId, tokenURI);
  }

  function setBaseURI(string memory baseURI_) external {
        baseURI = baseURI_;
  }
    
  function _baseURI() internal view override returns (string memory) {
        return baseURI;
  }

  function share(address to, uint256 tokenIdToBeShared) external returns(uint256 newTokenId) {
      require(to != address(0), "ERC721: mint to the zero address");
      require(_exists(tokenIdToBeShared), "ShareableERC721: token to be shared must exist");
      
      require(msg.sender == ownerOf(tokenIdToBeShared), "Method caller must be the owner of token");

      string memory _tokenURI = tokenURI(tokenIdToBeShared);
      _mint(to, _currentIndex);
      _setTokenURI(_currentIndex, _tokenURI);

      emit Share(msg.sender, to, _currentIndex, tokenIdToBeShared);

      return _currentIndex;
  }

  function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        revert('In this reference implementation tokens are not transferrable');
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        revert('In this reference implementation tokens are not transferrable');
    }
}

安全注意事项

参考实现不应按原样用于生产。 没有其他与此标准的实施直接相关的安全注意事项。

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Jarno Marttila (@yaruno), Martin Moravek (@mmartinmo), "ERC-5023: 可共享的非同质化代币," Ethereum Improvement Proposals, no. 5023, January 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5023.