After implementing PetFriendResolver as a PoC of a DApp for Snowflake Dashboard, I’ve started the development of a new DApp for Project Hydro, which will be a good example of a slightly common and actual scenario for blockchain DApps; there are lot of articles about collectible DApps and ERC721 standard assets, and this time I’m going to implement a DApp for registering of owned digital art, allowing both using them as collectible assets, and having the ability of selling them, transferring the ownership to other users.
First of all, we must answer this question: What is the desired behaviour for our application? Let’s see a requirements specification list for Digital Art Ownership DApp:
- Any user can use the DApp for registering owned art
- Art Registering: user creates a piece of original digital art and saves it, preferably as a non-lossy image format (PNG, RAW, etc)
- Via the digital Art Dapp, the user can register the proof of ownership of that image on chain. The info needed to store on chain is:
- Image hash (SHA3/MD5)
- Lightweight version of image for showing it on gallery (to be provider by the user, because some formats as RAW usually are not supported in browsers)
- Associated HydroID (the owner)
- Date and time of creation
- Name and Description of art
- Other metadata associated: color/BN, photo/digital art ,…
- Immutability of Art. Modification of Art data after creation is not allowed.
- About Image: original image (at best resolution) is stored in location of users choice. Source file can be huge and storing it on safe place is user’s duty. A lightweight version of the art must be provided, in a supported format (PNG, jgp..), and must be stored when it will be accessible for DApp to be browsed and shown in gallery.
- Proof of ownership. Registering of art by owner must create a verifiable proof of ownership on chain. This is made by:
- – owner’s signature of Image HASH stored on chain.
- – NTF asset ownership stored on chain.
- – Event logs of creation and transfer of ownership stored on-chain.
- Transfer operations. Users can sell they owned art. Dapp must allow selling of digital arts between registered users, where a transfer price must be paid.
- – Owner can put a sell price to their art
- – Other users can confirm the buy of any sellable art, by making a transaction and paying the corresponding price and fees.
- – Price will be on HYDRO, but payment should be done (in future versions) in ETH or any ERC20 token owned by the buyer (supported via uniswap metatransactions).
- Transfer ownership. Selling the art to other user implies transfer of art ownership to new user. The evidence of ownership change (including the signed hash of original image) must be recorded on-chain.
- History of Art. The Dapp must show a log of ownership changes of an art, since its creation to the last owner.
- Favorite Art. Every art will show a “likes” indicator with the number of votes; any registered user browsing the gallery can vote the art. Every user can only vote every art once. Votes can’t be undone.
- Gallery browsing: art can be filtered by criteria:
- – Owned Art
- – Last created Art
- – My favorite art
- – On-sale Art
Non Fungible Tokens specs: ERC721 and ERC1155
Actually, there are two most widely used specs for implementing NTFs, ERC721 and the newer ERC1155.
ERC721 is the standard followed by successfull Dapps like CryptoKitties, and almost all mainet collectible DApps are implemented over ERC721. This standard is the first-generation NFT spec, and lot of sites for trading of NFT support it. One on most known is openSea.io, so called The largest marketplace for crypto collectibles.
ERC1155 was born after ERC721, trying to supply the lacks of the first. ERC1155 is supported by Enjincoin.io, the creator of the spec and the reference smart contract implementation of ERC1155.
The next table compares different properties of ERC721 and ERC1155:
|Allow transfer multiple tokens in one transaction|
|Supports both NFTs (erc721) and FTs(erc20)|
|Support more than a token type per contract|
|Efficiency||Less efficient than ERC1155, use more on-chain space and requires on contract for each token type.||More efficient, use less on-chain space and allow several token types to be stored in the same contract.|
|Usage||Require deployment of a new contract for every token type. Require one transaction for every token operation.||One contract can be used to store new types of tokens. Allow operate with several tokens at the same time with one unique transaction.|
As seen in this comparison, ERC1155 is a much more advanced and efficient propose for NFTs, and mainly for this, Digital Art Dapp is built over ERC1155 instead of ERC721.
This development also provides base contracts for erc1155 specs, that could be easily reused in other developments, for other token types, reusing the same contract.
When trying to design the architecture for the implemented solution, it’s important to clearly draw the relationships between the snowflake Resolver and the ERC1155 contract.
Selected architecture allows the resolver acting as an “token operator” over erc1155 contract. This solution allows using the low level interface for token operation implemented in ERC1155 spec, while adding more functions to the resolver, as working with snowflake IDs, allowing buy-sell operation of art between snowflakes, dealing with token prices, on-sale tokens and favorite tokens.
- Dealing with Permission. The “creator of art” must call the “AproveForAll” method of erc1155 contract, giving permission to the token operator for transfer tokens. This must be done, as documented in erc1155 spec, if we want our Resolver to operate with tokens owned by “creator of art”.
- CreateArt. Once the operator has control over creator’s tokens, user will call “createArt”, to mint and register a new art token on blockchain. The resolver internally calls erc1155 contract to create and store the token.
- PutOnSale. Eventually, the owner of art can put on-sale any of their tokens. Then, it calls “putOnSale” method, making a transaction that only changes state of Resolver contract (nothing needs to change in erc1155 stored token).
- BuyArt. At last, other users can buy an on-sale token, calling the method “buyArt”. This transaction will be the more complex of all, because it must do several things:
- – change state of token from “on sale” to “not on sale”; this info is stored in resolver contract
- – change ownership of token from seller to buyer, this info is stored in erc1155 contract
- – dealing with the transfer of digital art ownership, from seller (possibly the creator of the art) to the new owner; this may require signing of the doc hash by the new owner, and storing this new signature on-chain.
ERC1155 implements several events that are thrown when operating with the tokens; the diagram shows as red arrows, when “ApproveForAll”, “URI”, and “TransferSingle” events are emitted.
After studying the desired solution, this is the proposed interface of ArtOperatorResolver.sol:
contract ArtOperatorResolver is SnowflakeResolver //get a token by id function getArt(uint256 _id) public view returns(ArtStatus status, uint256 price, string memory name, string memory desc, string memory imgUrl, uint256 ownerEIN);
//================================================================= // Create an Art and associated NFT // Metadata of art in json format must be stored at _uri. //================================================================= function createArt(string memory _uri, string memory _name, string memory _desc, string memory _imgUrl) public _isResolverFor() returns (uint256 _id);
//================================================================= // Token owner put one of their tokens OnSale // uin256 tokenId: id of art token on-sale //================================================================= function putOnSale(uint256 tokenId,uint price) public _isResolverFor() returns(bool); //get a list of on-sale tokens function getOnSaleTokens() public view returns ( uint256 memory); //================================================================= // Snowflake user push the button to buy an on-sale art // uin256 tokenId: id of art token on-sale //================================================================= function buyArt(uint256 tokenId) public _isResolverFor() _canBuy(tokenId) //sender must have funds to pay price of token returns(bool) //============================================================== //List of tokens owned by a snowflake (can be several addresses) //=============================================================== function getOwnedTokens() public view _isResolverFor() returns ( uint memory)
This interface can be modified and redefined during development, as new use cases or attributes can be needed.
Collectibles Dapps: Art… and more
The ability of ERC1155 spec for supporting different token types, allow the existence of several token operators (possibly snowflake Resolvers) that can implement their own logic, all of them using the same erc1155 contract for storing the tokens. You only need a base erc1155 where your tokens are stored; then, imagination is your limit!
Here is a list of common scenarios where NFT can be used:
- – trading card games
- – trading collectibles, as CriptoKitties
- – proof of achievement
- – token airdropping
- – sticker album dapps
- – sellable coupons
One of main’s requeriments of the Dapp is proof of ownership of the Digital Art, but How can be this accomplished?
Proposed solution is:
- – storing a Hash of digital art original file, on-chain.
- – generating a signature of that hash signed by the owner, with their private keys.
This data allows to verify if any given file is the digital art original file, by comparing its hashes.
Also, the stored signature allows to verify the ownership of the digital art; only the owner can generate the same signature as the stored one.
It’s important to recalculate the signature when art ownership changes, to certify the ownership of the new owner.
Tip: Erc1155 contract provides its own implementation of proof of ownership of tokens, implemented by code. Evidence can be verified from emitted events.
That’s all for this time. In next article, we will see:
- – Going to off-chain metadata implementation, by using metadata and URI events to store and access token metadata.
- – uniswap-via payments
- – Reusing erc1155 base contract for other Dapps
plus some code examples, I wish you good coding and Go HYDRO!
Thanks for reading.