Using non-fungible ERC-721 tokens in labeling and sales of physical assets.
Hello, World.
In this post, I'm going to discuss non-fungible tokens, or title deeds, implemented on the Ethereum platform. As a relatively new standard, these types of tokens offer an important extension in Ethereum smart contracts, giving way to automating many aspects of a modern society.
I'll first walk you through the technical side, and then discuss the business and social benefits of non-fungible tokens in practical applications.
What is a non-fungible ERC-721 token
The ERC-721 token standard was formed to address the need within the Ethereum core developer community to aid in creating applications for trading and tracking ownership of non-fungible digital or physical assets. Unlike in the ERC-20 token standard where individual tokens represent units of currency, the ERC-721 tokens are distinct from one another. The individuality of the ERC-721 tokens is explained by additional fields in the token standard;
The token has a specified name.
The token is given an individual token ID.
The contracts implemented in the token standard can track an arbitrarily large number of ERC-721 tokens, known as NFT's or non-fungible tokens, or deeds, simultaneously. This means that a single contract can contain one or more such tokens.
Full description of the ERC-721 token standard:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-Benefits of non-fungible tokens in labeling and sales of physical assets
Non-fungible tokens, or deeds, are ownership titles to property in the form of digital assets.
Title deeds open up a world of opportunities in digital contracts not seen before, with fungible, ERC-20 -type tokens. As ERC-721 -tokens represent user-defined real-world assets, the tokens can be used to mark, track and license ownership of these assets, and to label them by assigning the token's corresponding real-world item the token's TokenID and reading the token's transaction hash. This is done via the ERC-821 standard, or Distinguishable Assets Registry (DAR for short):
https://github.com/decentraland/erc721/blob/master/ERC821.md
A reference implementation is produced for example by the Decentraland project:
https://github.com/decentraland/erc821
-ERC-721 token structure
Every ERC-721 -token must contain the following definition (I've copypasted this from https://github.com/m0t0k1ch1/ERC721-token-sample so author information included):
pragma solidity ^0.4.18;
/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
/// @author Dieter Shirley [email protected] (https://github.com/dete)
contract ERC721 {
// Required methods
function totalSupply() public view returns (uint256 total);
function balanceOf(address _owner) public view returns (uint256 balance);
function ownerOf(uint256 _tokenId) external view returns (address owner);
function approve(address _to, uint256 _tokenId) external;
function transfer(address _to, uint256 _tokenId) external;
function transferFrom(address _from, address _to, uint256 _tokenId) external;
// Events
event Transfer(address from, address to, uint256 tokenId);
event Approval(address owner, address approved, uint256 tokenId);
// Optional
// function name() public view returns (string name);
// function symbol() public view returns (string symbol);
// function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds);
// function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl);
// ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
function supportsInterface(bytes4 _interfaceID) external view returns (bool);
}
This definition can - and often is - imported into the token contract as follows:
pragma solidity ^0.4.18;
import "./ERC721.sol";
// The token definition as mentioned above.
contract MyNonFungibleToken is ERC721 {
// Tell the virtual machine about the standard.
A sample token:
contract MyNonFungibleToken is ERC721 {
/*** CONSTANTS ***/
string public constant name = "MyNonFungibleToken";
string public constant symbol = "MNFT";
bytes4 constant InterfaceID_ERC165 =
bytes4(keccak256('supportsInterface(bytes4)'));
bytes4 constant InterfaceID_ERC721 =
bytes4(keccak256('name()')) ^
bytes4(keccak256('symbol()')) ^
bytes4(keccak256('totalSupply()')) ^
bytes4(keccak256('balanceOf(address)')) ^
bytes4(keccak256('ownerOf(uint256)')) ^
bytes4(keccak256('approve(address,uint256)')) ^
bytes4(keccak256('transfer(address,uint256)')) ^
bytes4(keccak256('transferFrom(address,address,uint256)')) ^
bytes4(keccak256('tokensOfOwner(address)'));
/*** DATA TYPES ***/
struct Token {
address mintedBy;
uint64 mintedAt;
}
/*** STORAGE ***/
Token[] tokens;
mapping (uint256 => address) public tokenIndexToOwner;
mapping (address => uint256) ownershipTokenCount;
mapping (uint256 => address) public tokenIndexToApproved;
/*** EVENTS ***/
event Mint(address owner, uint256 tokenId);
/*** INTERNAL FUNCTIONS ***/
function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
return tokenIndexToOwner[_tokenId] == _claimant;
}
function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {
return tokenIndexToApproved[_tokenId] == _claimant;
}
function _approve(address _to, uint256 _tokenId) internal {
tokenIndexToApproved[_tokenId] = _to;
Approval(tokenIndexToOwner[_tokenId], tokenIndexToApproved[_tokenId], _tokenId);
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
ownershipTokenCount[_to]++;
tokenIndexToOwner[_tokenId] = _to;
if (_from != address(0)) {
ownershipTokenCount[_from]--;
delete tokenIndexToApproved[_tokenId];
}
Transfer(_from, _to, _tokenId);
}
function _mint(address _owner) internal returns (uint256 tokenId) {
Token memory token = Token({
mintedBy: _owner,
mintedAt: uint64(now)
});
tokenId = tokens.push(token) - 1;
Mint(_owner, tokenId);
_transfer(0, _owner, tokenId);
}
/*** ERC721 IMPLEMENTATION ***/
function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
return ((_interfaceID == InterfaceID_ERC165) || (_interfaceID == InterfaceID_ERC721));
}
function totalSupply() public view returns (uint256) {
return tokens.length;
}
function balanceOf(address _owner) public view returns (uint256) {
return ownershipTokenCount[_owner];
}
function ownerOf(uint256 _tokenId) external view returns (address owner) {
owner = tokenIndexToOwner[_tokenId];
require(owner != address(0));
}
function approve(address _to, uint256 _tokenId) external {
require(_owns(msg.sender, _tokenId));
_approve(_to, _tokenId);
}
function transfer(address _to, uint256 _tokenId) external {
require(_to != address(0));
require(_to != address(this));
require(_owns(msg.sender, _tokenId));
_transfer(msg.sender, _to, _tokenId);
}
function transferFrom(address _from, address _to, uint256 _tokenId) external {
require(_to != address(0));
require(_to != address(this));
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
_transfer(_from, _to, _tokenId);
}
function tokensOfOwner(address _owner) external view returns (uint256[]) {
uint256 balance = balanceOf(_owner);
if (balance == 0) {
return new uint256[](0);
} else {
uint256[] memory result = new uint256[](balance);
uint256 maxTokenId = totalSupply();
uint256 idx = 0;
uint256 tokenId;
for (tokenId = 1; tokenId <= maxTokenId; tokenId++) {
if (tokenIndexToOwner[tokenId] == _owner) {
result[idx] = tokenId;
idx++;
}
}
}
return result;
}
/*** OTHER EXTERNAL FUNCTIONS ***/
function mint() external returns (uint256) {
return _mint(msg.sender);
}
function getToken(uint256 _tokenId) external view returns (address mintedBy, uint64 mintedAt) {
Token memory token = tokens[_tokenId];
mintedBy = token.mintedBy;
mintedAt = token.mintedAt;
}
}
PRACTICAL APPLICATIONS OF NON-FUNGIBLE ERC-721 TOKENS:
Non-fungible tokens are in practical sense, title deeds to any property or certificate. The token doesn't define whether the property or certificate is digital or physical - or civil - in nature. It is up to the user to choose and define the practical use of the non-fungible token.
To successfully implement an ERC-721 -token into a business application, the user should consider some recurring issues.
-Smart contracts
For automating business contracts, the token should be governed with a smart contract that refers to and imports the token for practical purposes.
These contracts are often found in the following types of applications:
-Proof of origin
-Proof of ownership
-Proof of authenticity
-Licensing and royalties
-Leasing and renting, subscriptions
-Legal contracts
-Civil and public documents
-Notary documents on sales contracts
-KYC/AML
-Installments, obligations and loan contracts
-Auctions
-Supply chain management
The community may dream up many more possible use case scenarios.
-Labeling
Information contained within the token can be imported into a product label, which gives the user an instant access to the smart contract. Labeling can be used to scan the contract state, to verify the token's authenticity and to perform functions on the contract through an appropriate app that may import the contract.
Common ways to use labeling in practical sense include:
-RFID or NFC tags
-QR codes
-Sales of non-fungible ERC-721 tokens:
Non-fungible tokens require a wallet that supports them, ie. Metamask at the time of writing this document. A good rule of thumb is that what supports Cryptokitties, supports every non-fungible token.
Sales of non-fungible tokens on an exchange is closer to an application of a marketplace than speculative asset exchange.
-Decentralized asset exchanges
Decentralized asset exchanges may benefit from non-fungible tokens, by allowing peer-to-peer transfer of title deeds. This is especially useful in games or in civil contracts, or in simple business contracts that do not require a notary or a public third party for compliance or verification.
There are proposed atomic swaps for non-fungible tokens as follows:
https://github.com/ethereum/EIPs/issues/875
-Internal asset exchanges
An e-commerce application may be built to support non-fungible tokens as certificates of products offered by the seller within an internal marketplace. This kind of closed-loop merchant-customer asset exchange is relevant especially in e-commerce, real estate development, rental, sharing economy and utilities industries, and also in fine art and media industries. Internal asset exchanges provide a practical way to distribute valid certificates of ownership and proofs of authenticity.
-Art gallery example of non-fungible ERC-721 tokens in a practical business application.
An art gallery hosts a marketplace for paintings. The platform of the art gallery transfers ownership of the paintings to the customer, governed by a licensing contract set by the artist. Each painting is represented by a non-fungible token, encoded within the artwork itself.
The non-fungible token can track:
-The origin of the work, or who painted it.
-The current owner.
-The licensing contract and whether the conditions are met.
-Relevant information about the artwork.
-The sales contract(s) associated with the token.
The non-fungible token and the sales contract(s) associated with it provide the artist means of copyright and licensing in the digital world, and fine artists means of distinguishing their original artwork from forgery.
The non-fungible token provide the gallerist means to prove that their hosted artwork is indeed authentic, as well as means of offering custom contracts such as renting, licensing, exhibitions and direct sales.
The non-fungible token provides the customer proof of authenticity and flexible deals on fine art both in collection and commerce.
-Public asset exchanges
Public asset exchanges benefit from non-fungible tokens especially in e-commerce and related activities. Non-fungible tokens can incorporate data of the attributes and supply chain of the product, which makes product certification and enterprise resource planning more streamlined, through a trustless blockchain -enabled platform.
For example, a food product or an industrial may be tracked all the way to the origin and processes and ingredients, and middlemen may be identified and tracked through a contract associated with a non-fungible token representing a product.
Media distributors benefit from non-fungible tokens by offering licenses associated with the token directly on a public platform.
Sharing economy operators, real estate developers and rental agencies may distribute contracts associated with their fleet of assets directly on their public platform, for example within a mobile app.
Possible business applications of non-fungible ERC-721 tokens:
-Fine art
-Film and music royalties
-Online gaming
-Diamond and gemstone market
-Ticketing
-Physical property
-Loans and obligations
-Digital goods
-Distributed orders
-E-commerce
-Certified goods
-Civil certificates
-Decentralized ERP
What is required for the applications to pan out in real life?
-App development
App developers may integrate ERC-721 tokens in their platforms, though to streamline this development, public API's and public network nodes could make non-fungible blockchain tokens accessible to the bulk of mobile and web developers - most of whom use JavaScript.
-Pilot projects
Successful pilot projects have been proven to inspire further development within the blockchain developer community, namely through successful startups, and socially aware projects such as ConsenSys. Pioneers often reap rewards, which encourage other players to enter a new, competitive market.
-More 'kitties
Cryptokitties was the first successful implementation of a non-fungible token standard into a real world application. The game took the Internet by storm, and at one point represented the bulk of Ethereum transactions. Hit products such as Cryptokitties can bring the technology into the public view probably more effectively than the more boring methods. However, to make sure the public will adopt the application, it should be intuitive to use.
I cannot stress enough how important it is to have an accessible mobile and web wallet. The wallet is the first experience the user encounters, therefore the wallet should be as non-technical as possible for widepread adoption.
Conclusion
Non-fungible tokens may transform our society in ways never seen before since the invention of the printing press, by taking out the middleman in business contracts and bureaucracy.
Many if not most tasks today delegated to public servants, accountants, secretaries, commercial agents and opaque middlemen can be automated with a transparent, trustless system. This new method will liberate us from boring tasks and uncertainty in many aspects of modern life.
The transition will be rapid, once the foundation is laid.