NEP: 11 Title: Non-Fungible Token Standard Author: Joe Stewart <[email protected]>, Shane Mann <[email protected]>, Wyatt Mufson <[email protected]>, Erik Zhang <[email protected]> Type: Standard Status: Final Created: 2018-04-18
This NEP defines a standard non-fungible token system for the NEO Smart Economy.
NFTs are required to track, exchange and enforce ownership of digital assets. A non-fungible token (NFT) can be thought of like a property deed - each one is unique and carries some non-mutable information (e.g. the physical address of the property). Other information, such as the owner of the property, can be changed. Also, we provide built-in optional divisibility within each non-fungible asset. This allows for high value objects to be tokenized more effectively.
{ "name": "symbol", "safe": true, "parameters": [], "returntype": "String" }
Returns a short string symbol of the token managed in this contract. e.g. "MNFT"
.
This symbol SHOULD be short (3-8 characters is recommended), with no whitespace characters or new-lines and SHOULD be limited to the uppercase latin alphabet (i.e. the 26 letters used in English).
This method MUST always return the same value every time it is invoked.
{ "name": "decimals", "safe": true, "parameters": [], "returntype": "Integer" }
Returns the number of decimals used by the token - e.g. 8
, means to divide the token amount by 100,000,000
to get its user representation.
If the token managed in this contract is indivisible, the function SHOULD return 0
.
If this method returns 0
, the "Non-divisible NFT methods" must be implemented.
Otherwise, the "Divisible NFT methods" must be implemented.
This method MUST always return the same value every time it is invoked.
{ "name": "totalSupply", "safe": true, "parameters": [], "returntype": "Integer" }
Returns the total token supply currently in the system.
{ "name": "balanceOf", "safe": true, "parameters": [ { "name": "owner", "type": "Hash160" } ], "returntype": "Integer" }
Returns the total amount of NFTs owned by the specified address.
The parameter owner
SHOULD be a 20-byte address.
If not, this method SHOULD throw
an exception.
{ "name": "tokensOf", "safe": true, "parameters": [ { "name": "owner", "type": "Hash160" } ], "returntype": "InteropInterface<iterator>" }
Returns an iterator
that contains all of the token ids owned by the specified address.
Each of these IDs SHOULD be a ByteString with a length of no more than 64 bytes.
The parameter owner
SHOULD be a 20-byte address.
If not, this method SHOULD throw
an exception.
{ "name": "transfer", "safe": false, "parameters": [ { "name": "to", "type": "Hash160" }, { "name": "tokenId", "type": "ByteString" }, { "name": "data", "type": "Any" } ], "returntype": "Boolean" }
It transfers the token with id tokenId
to address to
.
The parameter to
SHOULD be a 20-byte address.
If not, this method SHOULD throw
an exception.
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
The function SHOULD return false
if the token that will be transferred has more than one owner.
If the method succeeds, it MUST fire the Transfer
event, and MUST return true
, even if the token is sent to the owner.
If the receiver is a deployed contract, the function MUST call onNEP11Payment
method on receiver contract with the data
parameter from transfer
AFTER firing the Transfer
event.
The function SHOULD check whether the owner address equals the caller contract hash.
If so, the transfer SHOULD be processed; If not, the function SHOULD use the SYSCALL Neo.Runtime.CheckWitness
to verify the transfer.
If the transfer is not processed, the function SHOULD return false
.
{ "name": "ownerOf", "safe": true, "parameters": [ { "name": "tokenId", "type": "ByteString" } ], "returntype": "Hash160" }
Returns the owner of the specified token.
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
{ "name": "transfer", "safe": false, "parameters": [ { "name": "from", "type": "Hash160" }, { "name": "to", "type": "Hash160" }, { "name": "amount", "type": "Integer" }, { "name": "tokenId", "type": "ByteString" }, { "name": "data", "type": "Any" } ], "returntype": "Boolean" }
It transfers an amount
of tokens with id tokenId
from address from
to address to
.
The parameters from
and to
SHOULD be 20-byte addresses.
If not, this method SHOULD throw
an exception.
The parameter amount
SHOULD be greater than or equal to 0
and SHOULD be less than or equal to pow(10, decimals())
.
If not, this method SHOULD throw
an exception.
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
The function SHOULD return false
if the from
account balance does not have enough tokens to spend.
If the method succeeds, it MUST fire the Transfer
event, and MUST return true
, even if the amount
is 0
, or the token is sent to the owner.
If the receiver is a deployed contract, the function MUST call onNEP11Payment
method on receiver contract with the data
parameter from transfer
AFTER firing the Transfer
event.
The function SHOULD check whether the from
address equals the caller contract hash.
If so, the transfer SHOULD be processed; If not, the function SHOULD use the SYSCALL Neo.Runtime.CheckWitness
to verify the transfer.
If the transfer is not processed, the function SHOULD return false
.
{ "name": "ownerOf", "safe": true, "parameters": [ { "name": "tokenId", "type": "ByteString" } ], "returntype": "InteropInterface<iterator>" }
Returns an iterator
that contains all the co-owners that own the specified token.
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
{ "name": "balanceOf", "safe": true, "parameters": [ { "name": "owner", "type": "Hash160" }, { "name": "tokenId", "type": "ByteString" } ], "returntype": "Integer" }
This method returns the balance of the specified token for the specified owner
's account.
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
The parameter owner
SHOULD be a 20-byte address.
If not, this method SHOULD throw
an exception.
If the owner
is an unused address, or it's not the owner of the specified token, this method SHOULD return 0
.
{ "name": "tokens", "safe": true, "parameters": [], "returntype": "InteropInterface<iterator>" }
Returns an iterator
that contains all of the tokens minted by the contract.
{ "name": "properties", "safe": true, "parameters": [ { "name": "tokenId", "type": "ByteString" } ], "returntype": "Map" }
Returns a serialized NVM object containing the properties for the given NFT. The NVM object must conform to the "NEO NFT Metadata JSON Schema".
The parameter tokenId
SHOULD be a valid NFT ID (64 or less bytes long).
If not, this method SHOULD throw
an exception.
Following is a description of the JSON Schema:
{ "title": "Asset Metadata", "type": "object", "required": ["name"], "properties": { "name": { "type": "string", "description": "Identifies the asset to which this NFT represents." }, "description": { "type": "string", "description": "Optional. Describes the asset to which this NFT represents." }, "image": { "type": "string", "format": "uri", "description": "Optional. A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." }, "tokenURI": { "type": "string", "format": "uri", "description": "Optional. A distinct URI for a given asset that adheres to RFC 3986" } } }
Given this schema, the simplest json object that can be constructed is the following:
{ "name": "Slime 1" }
And if all the properties are included:
{ "name": "Slime 2", "description": "A slime", "image": "{some image URI}", "tokenURI": "{some URI}" }
{ "name": "onNEP11Payment", "parameters": [ { "name": "from", "type": "Hash160" }, { "name": "amount", "type": "Integer" }, { "name": "tokenId", "type": "ByteString" }, { "name": "data", "type": "Any" } ], "returntype": "Void" }
If a contract is to receive NFTs, it must implement the receiver method. Transferring NFTs to any contract that does not implement the receiver method will cause the transaction to fail. If the receiver doesn't want to receive this transfer it MUST abort the execution.
The meaning of the parameters of the onNEP11Payment
method is consistent with that of transfer
.
{ "name": "Transfer", "parameters": [ { "name": "from", "type": "Hash160" }, { "name": "to", "type": "Hash160" }, { "name": "amount", "type": "Integer" }, { "name": "tokenId", "type": "ByteString" } ] }
MUST trigger when tokens are transferred, including zero value transfers.
A token contract which creates new tokens MUST trigger a Transfer
event with the from
address set to null
when tokens are created.
A token contract which burns tokens MUST trigger a Transfer
event with the to
address set to null
when tokens are burned.