Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-2569: 用于通用代币的链上保存和显示图像

一组用于在以太坊中保存 SVG 图像的接口,以及用于从以太坊检索通用代币的图像文件的接口。

Authors Hua Zhang (@dgczhh), Yuefei Tan (@whtyfhas), Derek Zhou (@zhous), Ran Xing (@lemontreeran)
Created 2020-03-28
Discussion Link https://ethereum-magicians.org/t/erc-2569-saving-and-displaying-image-onchain-for-universal-tokens/4167

摘要

这组接口允许智能合约在以太坊中保存 SVG 图像,并允许从以太坊检索用于同质化代币、非同质化代币和基于未来将开发的标准的代币的 SVG 图像。

该接口集有两个接口:一个用于在以太坊中保存 SVG 文件,另一个用于从以太坊检索 SVG 文件。

典型的应用包括但不限于:

  • 一种用于存储同质化代币图标的解决方案。
  • 一种用于存储非同质化代币图标的解决方案。
  • 一种用于存储 DAO 声誉代币的图标/徽标的解决方案。

动机

ERC-721 代币标准是一种流行的标准,用于定义以太坊中的非同质化代币。 该标准被广泛用于指定加密礼物、加密奖章、加密收藏品等。最著名的用例是 cryptokitty

在大多数这些应用中,图像都附加到 ERC-721 代币。 例如,在 cryptokitty 案例中,每只小猫都有一个独特的图像。 虽然代币的代码永久保存在以太坊中,但附加到代币的图像却没有。

现有的解决方案仍然将此类图像保存在中心化服务器中,而不是以太坊中。 当这些应用程序显示代币的图像时,它们会从以太坊检索代币的信息,并使用代币的信息在中心化服务器中搜索代币的关联图像。

虽然这是一种显示代币图像的适用方法,但当图像保存在中心化服务器中时,仍然容易受到损坏或丢失的风险。

因此,我们提出一组接口,用于在以太坊中保存通用代币的图像,以保持图像的永久性和防篡改性,并用于从以太坊检索通用代币的图像。

规范

兼容 EIP-2569 的合约必须具有一个签名为 getTokenImageSvg(uint256) view returns (string memory) 的方法和一个签名为 setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal 的方法。

这些方法定义了智能合约如何在以太坊中保存通用代币的图像,从而保持图像的永久性和防篡改性,以及智能合约如何从以太坊检索通用代币的图像。

通过调用这些方法,用户应该可以访问 SVG 图像。

  • getTokenImageSvg(uint256 tokenId) external view returns (string memory):对于 ERC-721 或 ERC-1155 代币,或者由具有成员 “ID” 的合约实现的代币,以指定其代币类型或代币索引,我们定义了一个接口,用于使用代币的 ID 号获取 SVG 图像。 对于 ERC-20 代币或由没有成员 “ID” 的合约实现的代币,以指定其代币类型或代币索引,如果代币具有成员变量字符串来保存图像,我们定义了一个接口来获取其 SVG 图像。

它具有以下参数:

tokenId:对于非同质化代币(如 ERC-721 代币)或多代币(如 ERC-1155 代币),它们具有成员 “ID” 以指定其代币类型或代币索引,我们提出的接口将 SVG 图像的文件内容分配给代币合约的字符串变量,并将 SVG 图像与此 “ID” 号相关联。 此唯一 ID 用于在 “设置” 操作和 “获取” 操作中访问其 SVG 图像。 对于同质化代币(如 ERC-20 代币),不需要这样的 ID,并且我们提出的接口只是将 SVG 图像的文件内容分配给代币合约的字符串变量。

  • setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal:对于 ERC-721 或 ERC-1155 代币,或者由具有成员 “ID” 的合约实现的代币,以指定其代币类型或代币索引,我们定义了一个接口,用于将 SVG 图像与代币的 ID 号相关联。 对于 ERC-20 代币或由没有成员 “ID” 的合约实现的代币,以指定其代币类型或代币索引,我们定义了一个接口,用于将 SVG 图像分配给此代币合约的成员变量字符串。

它具有以下两个参数:

tokenId:对于非同质化代币(如 ERC-721 代币)或多代币(如 ERC-1155 代币),它们具有成员 “ID” 以指定其代币类型或代币索引,我们提出的接口将 SVG 图像的文件内容分配给代币合约的字符串变量,并将 SVG 图像与此 “ID” 号相关联。 此唯一 ID 用于在 “设置” 操作和 “获取” 操作中访问其 SVG 图像。 对于同质化代币(如 ERC-20 代币),不需要这样的 ID,并且我们提出的接口只是将 SVG 图像的文件内容分配给代币合约的字符串变量。

imageSvg:我们使用字符串变量来保存 SVG 图像文件的内容。 将保存在 imageSvg 字符串中的 SVG 图像应至少包括两个属性:”name”、”desc”(描述)。

在以太坊中保存代币图像的过程如下:

步骤 1: 定义一个字符串变量或一个字符串数组来保存一个图像或一个图像数组。

步骤 2: 定义一个函数,用于将 (SVG) 图像的文件内容或图像文件内容的数组设置为字符串变量或字符串数组。

步骤 1:对于诸如 ERC-721 或 ERC-1155 代币之类的代币,该代币具有成员变量 “ID” 以指定代币类型或索引,以及成员变量字符串以保存与 “ID” 关联的 (SVG) 图像,通过调用我们提出的 “get” 接口和代币的 ID 从以太坊检索(SVG)图像。 对于没有成员变量 “ID” 以指定代币类型的索引但具有成员变量字符串以保存 (SVG) 图像的代币,通过调用我们提出的没有 “ID” 的 “get” 从以太坊检索(SVG)图像。

理由

在比特币被创建之后,人们已经找到了通过在他们想要永久保存和防篡改的区块链交易中编码文本消息来保持信息的永久性和防篡改性的方法。 然而,现有的应用程序仅对文本信息执行此操作,并且没有解决方案可以保持图像的永久性和防篡改性。

不这样做的最重要原因之一是一般来说,图像的大小远大于文本文件的大小,因此在以太坊中保存图像所需的 gas 可能会超过区块的 gas 限制。

然而,自从 W3C 自 1999 年开发 SVG(可缩放矢量图形)规范以来,这种情况发生了很大变化。

与光栅图像相比,SVG 规范具有几个优势(有关优势的更多详细信息,请参阅参考链接:https://en.wikipedia.org/wiki/Scalable_Vector_Graphics)。 其中一个优势是其紧凑的文件大小。

“紧凑的文件大小 - 基于像素的图像从一开始就以较大的尺寸保存,因为您只能在缩小图像时保持质量,而不是在放大图像时保持质量。 这可能会影响网站的下载速度。 由于 SVG 是可缩放的,因此可以以最小的文件大小保存”。

此功能很好地解决了在以太坊中保存图像文件的痛点,因此我们认为在以太坊中保存 SVG 图像是保持图像的永久性和防篡改性的一个很好的解决方案。

在大多数与 ERC-721 相关的 DApp 中,它们会显示非同质化代币的图像。 在大多数与 ERC-20 相关的 DApp 中,它们没有同质化代币的图像。 我们认为在许多用例中,基于现有代币标准(如 ERC-20、ERC-721、ERC-1155)或基于未来标准的代币显示图像是必要的。 因此,目前不显示代币图像的那些 DApp 最终将需要这样的功能。

然而,关于大多数可以显示代币图像的现有 DApp,它们将此类图像保存在中心化服务器中,我们认为这只是一个折衷的解决方案。 通过利用 SVG 规范,我们认为将代币的图像转换为 SVG 图像并将其保存在以太坊中,为 DApp 提供了一种更好的解决方案来访问代币的图像。

此解决方案不仅适用于基于 ERC-721、ERC-1155 和 ERC-20 的代币,而且适用于基于未来标准的代币。

向后兼容性

没有向后兼容性问题。

参考实现

tokenId:ERC-721 代币中的代币索引或 ERC-1155 代币中的代币类型/索引。 它是一个 uint256 变量。

imageSvg:SVG 图像的文件内容。 它是一个字符串变量。 注意:SVG 图像应至少包括三个属性:”name”、”description” 和 “issuer”。

setTokenImageSvg:用于将 SVG 图像设置为有或没有 ID 号的代币的接口。

getTokenImageSvg:用于获取有或没有 ID 号的代币的 SVG 图像的接口。

我们建议在现有的 ERC-721 实现中添加三个 sol 文件。 以下是提议的 sol 文件的详细信息。

// ----- IERC721GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional retrieving SVG image extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721GetImageSvg is IERC721 {
    function getTokenImageSvg(uint256 tokenId) external view returns (string memory);
}


// ----- ERC721GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/GSN/Context.sol";
import "@openzeppelin/contracts/token/ERC721/./ERC721.sol";
import "@openzeppelin/contracts/introspection/ERC165.sol";
import "./IERC721GetImageSvg.sol";

contract ERC721GetImageSvg is Context, ERC165, ERC721, IERC721GetImageSvg {
    // Mapping for token Images
    // 代币图像的映射
    mapping(uint256 => string) private _tokenImageSvgs;

    /*
     *     bytes4(keccak256('getTokenImageSvg(uint256)')) == 0x87d2f48c
     *
     *     => 0x87d2f48c == 0x87d2f48c
     */
    bytes4 private constant _INTERFACE_ID_ERC721_GET_TOKEN_IMAGE_SVG = 0x87d2f48c;

    /**
     * @dev Constructor function
     * @dev 构造函数
     */
    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        // 注册支持的接口以通过 ERC165 符合 ERC721
        _registerInterface(_INTERFACE_ID_ERC721_GET_TOKEN_IMAGE_SVG);
    }

    /**
     * @dev Returns an SVG Image for a given token ID.
     * 如果代币 ID 不存在,则抛出异常。 可能会返回空字符串。
     * @param tokenId uint256 ID of the token to query
     * @param tokenId uint256 要查询的代币的 ID
     */
    function getTokenImageSvg(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId), "ERC721GetImageSvg: SVG Image query for nonexistent token");
        return _tokenImageSvgs[tokenId];
    }

    /**
     * @dev Internal function to set the token SVG image for a given token.
     * @dev 用于为给定代币设置代币 SVG 图像的内部函数。
     * Reverts if the token ID does not exist.
     * 如果代币 ID 不存在,则恢复。
     * @param tokenId uint256 ID of the token to set its SVG image
     * @param tokenId uint256 要设置其 SVG 图像的代币的 ID
     * @param imagesvg string SVG  to assign
     * @param imagesvg 字符串 SVG  分配
     */
    function setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal {
        require(_exists(tokenId), "ERC721GetImageSvg: SVG image set of nonexistent token");
        _tokenImageSvgs[tokenId] = imagesvg;
    }

}


// ----- ERC721ImageSvgMintable.sol -------------------------

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC721/ERC721Metadata.sol";
import "@openzeppelin/contracts/access/roles/MinterRole.sol";
import "./ERC721GetImageSvg.sol";

/**
 * @title ERC721ImageSvgMintable
 * @dev ERC721 minting logic with imagesvg.
 * @dev 具有 imagesvg 的 ERC721 铸造逻辑。
 */
contract ERC721ImageSvgMintable is ERC721, ERC721Metadata, ERC721GetImageSvg, MinterRole {
    /**
     * @dev Function to mint tokens.
     * @dev 用于铸造代币的函数。
     * @param to The address that will receive the minted tokens.
     * @param to 将接收铸造代币的地址。
     * @param tokenId The token id to mint.
     * @param tokenId 要铸造的代币 ID。
     * @param tokenImageSvg The token SVG image of the minted token.
     * @param tokenImageSvg 铸造代币的代币 SVG 图像。
     * @return A boolean that indicates if the operation was successful.
     * @return 一个布尔值,指示操作是否成功。
     */
    function mintWithTokenImageSvg(address to, uint256 tokenId, string memory tokenImageSvg) public onlyMinter returns (bool) {
        _mint(to, tokenId);
        setTokenImageSvg(tokenId, tokenImageSvg);
        return true;
    }
}


我们建议在现有的 ERC-1155 实现中添加三个 sol 文件。
以下是提议的 sol 文件的详细信息。

// ----- IERC1155GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;

import "./IERC1155.sol";

/**
 * @title ERC-1155 Multi Token Standard, retrieving SVG image for a token
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
 */
contract IERC1155GetImageSvg is IERC1155 {
    function getTokenImageSvg(uint256 tokenId) external view returns (string memory);
}


// ----- ERC1155GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;

import "./ERC1155.sol";
import "./IERC1155GetImageSvg.sol";

contract ERC1155GetImageSvg is ERC165, ERC1155, IERC1155GetImageSvg {
    // Mapping for token Images
    // 代币图像的映射
    mapping(uint256 => string) private _tokenImageSvgs;

    /*
     *     bytes4(keccak256('getTokenImageSvg(uint256)')) == 0x87d2f48c
     *
     *     => 0x87d2f48c == 0x87d2f48c
     */
    bytes4 private constant _INTERFACE_ID_ERC1155_GET_TOKEN_IMAGE_SVG = 0x87d2f48c;

    /**
     * @dev Constructor function
     * @dev 构造函数
     */
    constructor () public {
        // register the supported interfaces to conform to ERC1155 via ERC165
        // 注册支持的接口以通过 ERC165 符合 ERC1155
        _registerInterface(_INTERFACE_ID_ERC1155_GET_TOKEN_IMAGE_SVG);
    }


    /**
     * @dev Returns an SVG Image for a given token ID.
     * 如果代币 ID 不存在,则抛出异常。 可能会返回空字符串。
     * @param tokenId uint256 ID of the token to query
     * @param tokenId uint256 要查询的代币的 ID
     */
    function getTokenImageSvg(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId), "ERC1155GetImageSvg: SVG Image query for nonexistent token");
        return _tokenImageSvgs[tokenId];
    }

    /**
     * @dev Internal function to set the token SVG image for a given token.
     * @dev 用于为给定代币设置代币 SVG 图像的内部函数。
     * Reverts if the token ID does not exist.
     * 如果代币 ID 不存在,则恢复。
     * @param tokenId uint256 ID of the token to set its SVG image
     * @param tokenId uint256 要设置其 SVG 图像的代币的 ID
     * @param imagesvg string SVG  to assign
     * @param imagesvg 字符串 SVG  分配
     */
    function setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal {
        require(_exists(tokenId), "ERC1155GetImageSvg: SVG image set of nonexistent token");
        _tokenImageSvgs[tokenId] = imagesvg;
    }

}



// ----- ERC1155MixedFungibleWithSvgMintable.sol -------------------------

pragma solidity ^0.5.0;

import "./ERC1155MixedFungibleMintable.sol";
import "./ERC1155GetImageSvg.sol";

/**
    @dev Mintable form of ERC1155 with SVG images
    @dev 具有 SVG 图像的 ERC1155 的可铸造形式
    Shows how easy it is to mint new items with SVG images
    显示了使用 SVG 图像铸造新项目是多么容易
*/

contract ERC1155MixedFungibleWithSvgMintable is ERC1155, ERC1155MixedFungibleMintable, ERC1155GetImageSvg {
    /**
     * @dev Function to mint non-fungible tokens.
     * @dev 用于铸造非同质化代币的函数。
     * @param _to The address that will receive the minted tokens.
     * @param _to 将接收铸造代币的地址。
     * @param _type The token type to mint.
     * @param _type 要铸造的代币类型。
     * @param tokenImageSvg The token SVG image of the minted token.
     * @param tokenImageSvg 铸造代币的代币 SVG 图像。
     */
    function mintNonFungibleWithImageSvg(uint256 _type, address[] calldata _to, string memory tokenImageSvg) external creatorOnly(_type) {
        mintNonFungible(_type, _to);
        setTokenImageSvg(_type, tokenImageSvg);
    }


    /**
     * @dev Function to mint fungible tokens.
     * @dev 用于铸造同质化代币的函数。
     * @param _to The address that will receive the minted tokens.
     * @param _to 将接收铸造代币的地址。
     * @param _id The token type to mint.
     * @param _id 要铸造的代币类型。
     * @param _quantities The number of tokens for a type to mint.
     * @param _quantities 要铸造的类型代币的数量。
     * @param tokenImageSvg The token SVG image of the minted token.
     * @param tokenImageSvg 铸造代币的代币 SVG 图像。
     */
    function mintFungibleWithImageSvg(uint256 _id, address[] calldata _to, uint256[] calldata _quantities, string memory tokenImageSvg) external creatorOnly(_id) {
        mintFungible(_id, _to, _quantities, tokenImageSvg)  {
        setTokenImageSvg(_id, tokenImageSvg);
    }
}



我们建议在现有的 ERC-20 实现中添加三个 sol 文件。
以下是提议的 sol 文件的详细信息。


// ----- IERC20GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title ERC-20 Fungible Token Standard, retrieving SVG image for a token
 * @dev See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol
 */
contract IERC20GetImageSvg is IERC20 {
    function getTokenImageSvg() external view returns (string memory);
}


// ----- ERC20GetImageSvg.sol -------------------------

pragma solidity ^0.5.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./IERC20GetImageSvg.sol";

contract ERC20GetImageSvg is ERC20, IERC20GetImageSvg {
    string private _tokenImageSvg;
//将图片实现写在构造器中
//将图像实现写在构造器中
    constructor(string calldata svgCode) public {
_tokenImageSvg = svgCode
}

    /**
     * @dev Returns an SVG Image.
     * @dev 返回 SVG 图像。
     */
    function getTokenImageSvg() external view returns (string memory) {
        return _tokenImageSvg;
    }

}


版权

CC0 下放弃版权及相关权利。

Citation

Please cite this document as:

Hua Zhang (@dgczhh), Yuefei Tan (@whtyfhas), Derek Zhou (@zhous), Ran Xing (@lemontreeran), "ERC-2569: 用于通用代币的链上保存和显示图像 [DRAFT]," Ethereum Improvement Proposals, no. 2569, March 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2569.