Skip to content

Latest commit

 

History

History
443 lines (355 loc) · 11.3 KB

nep-11.mediawiki

File metadata and controls

443 lines (355 loc) · 11.3 KB

  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

Table of Contents

Abstract

This NEP defines a standard non-fungible token system for the NEO Smart Economy.

Motivation

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.

Specification

Common methods

symbol

{
  "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.

decimals

{
  "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.

totalSupply

{
  "name": "totalSupply",
  "safe": true,
  "parameters": [],
  "returntype": "Integer"
}

Returns the total token supply currently in the system.

balanceOf

{
  "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.

tokensOf

{
  "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.

transfer

{
  "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.

Non-divisible NFT methods

ownerOf

{
  "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.

Divisible NFT methods

transfer

{
  "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.

ownerOf

{
  "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.

balanceOf

{
  "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.

Optional methods

tokens

{
  "name": "tokens",
  "safe": true,
  "parameters": [],
  "returntype": "InteropInterface<iterator>"
}

Returns an iterator that contains all of the tokens minted by the contract.

properties

{
  "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}"
}

Receiver methods

onNEP11Payment

{
  "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.

Events

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.

Implementation

https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.SmartContract.Framework/Nep11Token.cs