forked from DecentralizedClimateFoundation/DCIPs
354 lines
17 KiB
Markdown
354 lines
17 KiB
Markdown
---
|
||
eip: 2569
|
||
title: Saving and Displaying Image Onchain for Universal Tokens
|
||
description: A set of interfaces to save an SVG image in Ethereum, and to retrieve the image file from Ethereum for universal tokens.
|
||
author: Hua Zhang (@dgczhh), Yuefei Tan (@whtyfhas), Derek Zhou (@zhous), Ran Xing (@lemontreeran)
|
||
discussions-to: https://ethereum-magicians.org/t/erc-2569-saving-and-displaying-image-onchain-for-universal-tokens/4167
|
||
status: Stagnant
|
||
type: Standards Track
|
||
category: ERC
|
||
created: 2020-03-28
|
||
---
|
||
|
||
## Abstract
|
||
This set of interfaces allow a smart contract to save an SVG image in Ethereum and to retrieve an SVG image from Ethereum for fungible tokens, non-fungible tokens and tokens based on standards that will be developed in the future.
|
||
|
||
The interface set has two interfaces: one to save an SVG file in Ethereum and the other to retrieve an SVG file from Ethereum.
|
||
|
||
Typical applications include but not limited to:
|
||
* A solution for storage of a fungible token's icon.
|
||
* A solution for storage of a non-fungible token's icon.
|
||
* A solution for storage of the icon/logo of a DAO's reputation token.
|
||
|
||
## Motivation
|
||
The ERC-721 token standard is a popular standard to define a non-fungible token in Ethereum. This standard is widely used to specify a crypto gift, crypto medal, crypto collectible etc. The most famous use case is the [cryptokitty](https://www.cryptokitties.co/).
|
||
|
||
In most of these applications an image is attached to an ERC-721 token. For example, in the cryptokitty case each kitty has a unique image. While the token's code is saved in Ethereum permanently, the image attached to the token is not.
|
||
|
||
The existing solutions still keep such an image in a centralized server instead of Ethereum. When these applications display an image for a token they retrieve the token's information from Ethereum and search the centralized server for the token's associated image by using the token's information.
|
||
|
||
Although this is an applicable way to display an image for a token, the image is still vulnerable to risks of being damaged or lost when saved in a centralized server.
|
||
|
||
Hence we propose a set of interfaces to save an image for a universal token in Ethereum to keep the image permanent and tamper-resistant, and to retrieve an image for a universal token from Ethereum.
|
||
|
||
## Specification
|
||
|
||
An EIP-2569 compatible contract MUST have a method with the signature getTokenImageSvg(uint256) view returns (string memory) and a method with the signature setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal.
|
||
|
||
These methods define how a smart contract saves an image for a universal token in Ethereum which keeps the image permanent and tamper-resistant, and how a smart contract retrieves an image from Ethereum for a universal token.
|
||
|
||
By calling the methods users should access an SVG image.
|
||
|
||
* getTokenImageSvg(uint256 tokenId) external view returns (string memory): for an ERC-721 or ERC-1155 token or a token implemented by a contract which has a member "ID" to specify its token type or token index we define an interface to get an SVG image by using the token's ID number. For an ERC-20 token or a token implemented by a contract which doesn't have a member "ID" to specify its token type or token index we define an interface to get an SVG image for it if the token has a member variable string to save the image.
|
||
|
||
It has the following parameter:
|
||
|
||
tokenId: for a non-fungible token such as an ERC-721 token or a multi-token such as an ERC-1155 token which has a member "ID" to specify its token type or token index our proposed interface assigns an SVG image's file content to a string variable of the token's contract and associates the SVG image to this "ID" number. This unique ID is used to access its SVG image in both a "set" operation and a "get" operation.
|
||
For a fungible token such as an ERC-20 token no such an ID is needed and our proposed interface just assigns an SVG image's file content to a string variable of the token's contract.
|
||
|
||
* setTokenImageSvg(uint256 tokenId, string memory imagesvg) internal: for an ERC-721 or ERC-1155 token or a token implemented by a contract which has a member "ID" to specify its token type or token index we define an interface to associate an SVG image to the token's ID number. For an ERC-20 token or a token implemented by a contract which doesn't have a member "ID" to specify its token type or token index we define an interface to assign an SVG image to a member variable string of this token's contract.
|
||
|
||
It has the following two parameters:
|
||
|
||
tokenId: for a non-fungible token such as an ERC-721 token or a multi-token such as an ERC-1155 token which has a member "ID" to specify its token type or token index our proposed interface assigns an SVG image's file content to a string variable of the token's contract and associates the SVG image to this "ID" number. This unique ID is used to access its SVG image in both a "set" operation and a "get" operation.
|
||
For a fungible token such as an ERC-20 token no such an ID is needed and our proposed interface just assigns an SVG image's file content to a string variable of the token's contract.
|
||
|
||
imageSvg: we use a string variable to save an SVG image file's content.
|
||
An SVG image that will be saved in the imageSvg string should include at least two attributes:"name", "desc"(description).
|
||
|
||
The procedure to save an image for a token in Ethereum is as follows:
|
||
|
||
**Step1:** define a string variable or an array of strings to hold an image or an array of images.
|
||
|
||
**Step 2:** define a function to set an (SVG) image's file content or an array of image file's contents to the string variable or the array of strings.
|
||
|
||
Step 1: for a token such as an ERC-721 or ERC-1155 token which has a member variable "ID" to specify a token type or index and a member variable string to keep an (SVG) image associated with the "ID", retrieve the (SVG) image from Ethereum by calling our proposed "get" interface with the token's ID;
|
||
for a token which doesn't have a member variable "ID" to specify a token type of index but has a member variable string to keep an (SVG) image, retrieve the (SVG) image from Ethereum by calling our proposed "get" without an "ID".
|
||
|
||
## Rationale
|
||
After Bitcoin was created people have found ways to keep information permanent and tamper-resistant by encoding text messages they want to preserve permanently and tamper-resistantly in blockchain transactions. However existing applications only do this for text information and there are no solutions to keep an image permanent and tamper-resistant.
|
||
|
||
One of the most significant reasons for not doing so is that in general the size of an image is much bigger than the size of a text file, thus the gas needed to save an image in Ethereum would exceed a block's gas limit.
|
||
|
||
However this changed a lot after the SVG(Scalable Vector Graphics) specification was developed by W3C since 1999.
|
||
|
||
The SVG specification offers several advantages (for more details about the advantages please refer to a reference link:https://en.wikipedia.org/wiki/Scalable_Vector_Graphics) over raster images. One of these advantages is its compact file-size.
|
||
|
||
"Compact file-size – Pixel-based images are saved at a large size from the start because you can only retain the quality when you make the image smaller, but not when you make it larger. This can impact a site’s download speed. Since SVGs are scalable, they can be saved at a minimal file size".
|
||
|
||
This feature well fixes the painpoint of saving an image file in Ethereum, therefore we think saving an SVG image in Ethereum is a good solution for keep the image permanent and tamper-resistant.
|
||
|
||
In most ERC-721 related DAPPs they display an image for a non-fungible token. In most ERC-20 related DAPPs they don't have an image for a fungible token. We think displaying an image for a token either based on existing token standards such as ERC-20, ERC-721, ERC-1155 or based on future standards is needed in many use cases. Therefore those DAPPs which currently don't display an image for a token will eventually need such a function.
|
||
|
||
However with regard to most of the existing DAPPs which can display an image for a token they save such an image in a centralized server which, we think, is just a compromised solution. By utilizing the SVG specification we think converting a token's image to an SVG image and saving it in Ethereum provides a better solution for DAPPs to access an image for a token.
|
||
|
||
This solution not only works for tokens based on ERC-721, ERC-1155 and ERC-20 but will work for tokens based on future standards.
|
||
|
||
## Backwards Compatibility
|
||
There are no backward compatibility issues.
|
||
|
||
## Reference Implementation
|
||
`tokenId`: a token index in an ERC-721 token or a token type/index in an ERC-1155 token. It is a uint256 variable.
|
||
|
||
`imageSvg`: an SVG image's file content. It is a string variable. Note: the SVG image should include at least three attributes:"name", "description" and "issuer".
|
||
|
||
`setTokenImageSvg`: interface to set an SVG image to a token with or without an ID number.
|
||
|
||
`getTokenImageSvg`: interface to get an SVG image for a token with or without an ID number.
|
||
|
||
We propose to add three sol files in the existing ERC-721 implementation.
|
||
Here are the details for the proposed sol files.
|
||
|
||
```solidity
|
||
// ----- 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
|
||
*/
|
||
constructor () public {
|
||
// register the supported interfaces to conform to ERC721 via ERC165
|
||
_registerInterface(_INTERFACE_ID_ERC721_GET_TOKEN_IMAGE_SVG);
|
||
}
|
||
|
||
/**
|
||
* @dev Returns an SVG Image for a given token ID.
|
||
* Throws if the token ID does not exist. May return an empty string.
|
||
* @param tokenId uint256 ID of the token to query
|
||
*/
|
||
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.
|
||
* Reverts if the token ID does not exist.
|
||
* @param tokenId uint256 ID of the token to set its SVG image
|
||
* @param imagesvg string SVG to assign
|
||
*/
|
||
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.
|
||
*/
|
||
contract ERC721ImageSvgMintable is ERC721, ERC721Metadata, ERC721GetImageSvg, MinterRole {
|
||
/**
|
||
* @dev Function to mint tokens.
|
||
* @param to The address that will receive the minted tokens.
|
||
* @param tokenId The token id to mint.
|
||
* @param tokenImageSvg The token SVG image of the minted token.
|
||
* @return A boolean that indicates if the operation was successful.
|
||
*/
|
||
function mintWithTokenImageSvg(address to, uint256 tokenId, string memory tokenImageSvg) public onlyMinter returns (bool) {
|
||
_mint(to, tokenId);
|
||
setTokenImageSvg(tokenId, tokenImageSvg);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
|
||
We propose to add three sol files in the existing ERC-1155 implementation.
|
||
Here are the details for the proposed sol files.
|
||
|
||
// ----- 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
|
||
*/
|
||
constructor () public {
|
||
// register the supported interfaces to conform to ERC1155 via ERC165
|
||
_registerInterface(_INTERFACE_ID_ERC1155_GET_TOKEN_IMAGE_SVG);
|
||
}
|
||
|
||
|
||
/**
|
||
* @dev Returns an SVG Image for a given token ID.
|
||
* Throws if the token ID does not exist. May return an empty string.
|
||
* @param tokenId uint256 ID of the token to query
|
||
*/
|
||
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.
|
||
* Reverts if the token ID does not exist.
|
||
* @param tokenId uint256 ID of the token to set its SVG image
|
||
* @param imagesvg string SVG to assign
|
||
*/
|
||
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
|
||
Shows how easy it is to mint new items with SVG images
|
||
*/
|
||
|
||
contract ERC1155MixedFungibleWithSvgMintable is ERC1155, ERC1155MixedFungibleMintable, ERC1155GetImageSvg {
|
||
/**
|
||
* @dev Function to mint non-fungible tokens.
|
||
* @param _to The address that will receive the minted tokens.
|
||
* @param _type The token type to mint.
|
||
* @param tokenImageSvg The token SVG image of the minted token.
|
||
*/
|
||
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.
|
||
* @param _to The address that will receive the minted tokens.
|
||
* @param _id The token type to mint.
|
||
* @param _quantities The number of tokens for a type to mint.
|
||
* @param tokenImageSvg The token SVG image of the minted token.
|
||
*/
|
||
function mintFungibleWithImageSvg(uint256 _id, address[] calldata _to, uint256[] calldata _quantities, string memory tokenImageSvg) external creatorOnly(_id) {
|
||
mintFungible(_id, _to, _quantities, tokenImageSvg) {
|
||
setTokenImageSvg(_id, tokenImageSvg);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
We propose to add three sol files in the existing ERC-20 implementation.
|
||
Here are the details for the proposed sol files.
|
||
|
||
|
||
// ----- 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.
|
||
*/
|
||
function getTokenImageSvg() external view returns (string memory) {
|
||
return _tokenImageSvg;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
```
|
||
|
||
## Copyright
|
||
Copyright and related rights waived via [CC0](../LICENSE.md).
|
||
|