Skip to main content

PRC-721

PRC-721 Contract#

PRC-721 is a standard interface for issuing non-fungible tokens (NFT) on the PlatON network and is fully compatible with ERC-721.

Protocol Standards#

Each PRC-721-compliant smart contract must implement the PRC721 and PRC165 interfaces, and can implement other extended interfaces according to business needs.

PRC-721 & PRC-165 Interface#

interface PRC721 /* is PRC165 */ {    //events    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
    //required    function balanceOf(address _owner) external view returns (uint256);    function ownerOf(uint256 _tokenId) external view returns (address);    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;    function approve(address _approved, uint256 _tokenId) external payable;    function setApprovalForAll(address _operator, bool _approved) external;    function getApproved(uint256 _tokenId) external view returns (address);    function isApprovedForAll(address _owner, address _operator) external view returns (bool);    interface PRC165 {        function supportsInterface(bytes4 interfaceID) external view returns (bool);    }
    //optional    interface PRC721TokenReceiver {        function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);    }    //The metadata extension interface is optional for PRC-721 smart contracts and allows users to query the name of the smart contract as well as the details of the asset represented by the NFT.    interface PRC721Metadata {        function name() external view returns (string _name);        function symbol() external view returns (string _symbol);        function tokenURI(uint256 _tokenId) external view returns (string);    }    //The enumeration extension is optional for PRC-721 smart contracts and allows a user's smart contract to publish its full list of NFTs and make them visible.    interface PRC721Enumerable {        function totalSupply() external view returns (uint256);        function tokenByIndex(uint256 _index) external view returns (uint256);        function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);    }}

Required interfaces#

  • balanceOf

    Counts the number of NFTs held by users.

  • ownerOf

    Query the holder of the NFT.

  • safeTransferFrom

    Transfer ownership of the NFT from one address to another.

  • transferFrom

    Transferring NFT ownership, the caller is responsible for confirming that the recipient has the ability to receive NFTs that might otherwise be permanently lost.

  • approve

    Authorize a third party to operate an NFT asset.

  • setApprovalForAll

    Authorize a third party to operate an NFT asset.

  • getApproved

    Get which address management is authorized for a single NFT.

  • isApprovedForAll

    Queries whether an address is authorized to manage token by another address.

  • supportsInterface

    Queries whether an address is authorized to manage token by another address.

Optionally interfaces#

  • onERC721Received

    Contracts that need to accept secure transfers must implement the PRC721TokenReceiver interface.

  • name

    The name of the contract.

  • symbol

    The abbreviated code for the contract.

  • tokenURI

    Give the token a Uniform Resource Identifier (URI) that points to a JSON file that conforms to the "PRC721 Metadata JSON Schema", which needs to be assigned a unique URI for each token when minting it.

    {  "title": "Asset Metadata",  "type": "object",  "properties": {      "name": {          "type": "string",          "description": "Identifies the asset to which this NFT represents"      },      "description": {          "type": "string",          "description": "Describes the asset to which this NFT represents"      },      "image": {          "type": "string",          "description": "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."      }  }}
  • totalSupply

    Query the total number of tokens owned by this contract.

  • tokenByIndex

    Query token by index.

  • tokenOfOwnerByIndex

    Find the user's token based on the index.

Event#

  • Transfer

    This event is triggered when the ownership of any NFT changes (either way), and a log of ownership change information is recorded on the chain.

  • Approval

    Triggered when the authorized address of the NFT is changed or confirmed, logging this information on the chain.

  • ApprovalForAll

    Triggered when the owner enables or disables the operator (the operator can manage the NFTs held by the owner), logging this information in the chain.

Example#

The PRC-721 standard is fully compatible with ERC-721, examples of which can be found here.

View#

It can be viewed through PlatON browser and also through ATON to view the PRC-721 contract transactions.

Deploy#

please refer to Solidity Contracts Getting Started Manual

Invoking functions#

Using python as an example.

Installing python dependencies#

Use the following command to install the PlatON python library, Python version 3.7.5+ is recommended:

pip install client-sdk-python

During the installation process, some dependency packages will require c++14 compilation, please download cppbuildtools after you see the relevant prompt, use the default value to install it, and then re-execute the pip install command.

Instantiate the contract#

The following is a sample python code.

from client_sdk_python import Web3, HTTPProvider
rpc, chain_id, hrp = 'http://127.0.0.1:6789', 100, 'lat'w3 = Web3(HTTPProvider(rpc), chain_id=chain_id, hrp_type=hrp)abi = [  {    "inputs": [      { "internalType": "string", "name":"_name", "type": "string"}      {"internalType": "string", "name":"_symbol", "type": "string"}    ],    "stateMutability": "nonpayable",    "type": "constructor"  },  {    "inputs": [      { "internalType": "address", "name": "_to", "type": "address" }      {"internalType": "uint256", "name":"_tokenId", "type": "uint256"}, {"internalType": "uint256", "name":"_tokenId", "type": "uint256"},      {"internalType": "string", "name":"_uri", "type": "string"}    ],    "name": "mint",    "outputs": [],    "stateMutability": "nonpayable",    "type": "function"  },  {    "inputs": [{"internalType": "address", "name": "_owner", "type": "address"}],    "name": "balanceOf",    "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],    "stateMutability": "view",    "type": "function"  },  {    "inputs": [{"internalType": "uint256", "name": "_tokenId", "type": "uint256"}],    "name": "ownerOf",    "outputs": [{"internalType": "address", "name": "_owner", "type": "address"}],    "stateMutability": "view",    "type": "function"  },  {    "inputs": [      { "internalType": "address", "name": "_from", "type": "address" }      {"internalType": "address", "name":"_to", "type": "address"}, {"internalType": "address", "name":"_to", "type": "address"}, {"internalType": "address", "name":"_to", "type": "address"},      {"internalType": "uint256", "name":"_tokenId", "type": "uint256"}, {"internalType": "uint256", "name":"_tokenId", "type": "uint256"}    ],    "name": "safeTransferFrom",    "outputs": [],    "stateMutability": "nonpayable",    "type": "function"  },  {    "anonymous": false,    "inputs": [      { "indexed": true, "internalType": "address", "name": "_from", "type": "address" }      {"indexed": true, "internalType": "address", "name":"_to", "type": "address"}, "indexed": true, "internalType": "address", "name":"_to", "type": "address"},      {"indexed": true, "internalType": "uint256", "name":"_tokenId", "type": "uint256"}    ],    "name": "Transfer",    "type": "event"  },]prc721 = w3.eth.contract(address='contract address', abi=abi)# View all functions and events of the contractprint([func for func in prc721.functions])print([event for event in prc721.events])

Query contract information#

With balanceOf, ownerOf example, other query methods are similar to this.

# Count the number of NFTs held by usersprc721.functions.balanceOf('your address').call()# Query the holder of NFTsprc721.functions.ownerOf('your token id').call()

Sending contract transactions#

Using the safeTransferFrom example, other transaction methods are similar to this.

# Transfer ownership of NFT from one address to anothertx = {    'chainId': w3.chain_id,    'nonce': w3.eth.getTransactionCount('your address'),    'gas': 4012388,    'value': 0,    'gasPrice': 1000000000,}txn = prc721.functions.safeTransferFrom(_from='your address', _to='to address', _tokenId='your token id').buildTransaction(tx)signed_txn = w3.eth.account.signTransaction(txn, private_key='your private key')tx_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()receipt = w3.eth.waitForTransactionReceipt(tx_hash)

Get contract events#

Using the safeTransferFrom transaction event example, other event fetching methods are similar to this.

events = prc721.events.Transfer().processReceipt(receiveipt)

Upload Metadata to IPFS network#

Metadata is the metadata of NFT tokens in order to display more detailed information about NFT assets, stored under the chain, generally the issuance of an NFT token will specify a URI path to the Metadata data of this token.

1. Install IPFS#

Refer to the IPFS installation instructions to install and start.

2. Adding files to ipfs#

Prepare an image, name it PlatON.jpeg, and upload it to the ipfs node

$ ipfs add PlatON.jpegadd QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy PlatON.jpeg//QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy is the unique ID of the file, generated after adding it to ipfs

If you open the link to the image in your browser and see the image, it means that the image was successfully downloaded: https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=PlatON.jpeg

With the image link above, you can use it to construct the metadata for NFT.

First, follow the instructions in the PRC-721 document metadata to create a json file named PlatON.json:

{    "name": "PlatON.jpg",    "author": "PlatON",    "description": "use for prc721",    "image": "https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=PlatON.jpeg"}

Upload to the ipfs node:

$ ipfs add PlatON.jsonadded QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px PlatON.json

Open the uri of the metadata file in your browser: https://ipfs.io/ipfs/QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px?filename=PlatON.json

Above, the upload is complete.