Skip to main content

ARC721

Abstact#

ARC-721 is a standard set of interfaces for issuing non-fungible tokens (NFT) on the Alaya network and is fully compatible with ERC-721.

ARC-721 Token Standard#

ARC-721-compliant smart contracts must all implement the ARC721 and ARC165 interface, and can implement other extended interfaces according to business needs.

ARC-721 & ARC-165 Interfaces#

interface ARC721 /* is ARC165 */ {    //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 ARC165 {        function supportsInterface(bytes4 interfaceID) external view returns (bool);    }
    //optional    interface ARC721TokenReceiver {        function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);    }
    interface ARC721Metadata {        function name() external view returns (string _name);        function symbol() external view returns (string _symbol);        function tokenURI(uint256 _tokenId) external view returns (string);    }
    interface ARC721Enumerable {        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: Count all NFTs assigned to an owner.
  • ownerOf:Find the owner of an NFT.
  • safeTransferFrom:Transfers the ownership of an NFT from one address to another address.
  • transferFrom:Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE.
  • approve:Change or reaffirm the approved address for an NFT.
  • setApprovalForAll:Enable or disable approval for a third party ("operator") to manage.
  • getApproved:Get the approved address for a single NFT.
  • isApprovedForAll:Query if an address is an authorized operator for another address.
  • supportsInterface:Query if a contract implements an interface.

Optionally interfaces#

  • onERC721Received:Handle the receipt of an NFT. If you need to make a secure transfer inside the contract, you must implement the ARC721TokenReceiver interface.
  • name:A descriptive name for a collection of NFTs in this contract.
  • symbol:An abbreviated name for NFTs in this contract.
  • tokenURI:A distinct Uniform Resource Identifier (URI) for a given asset. The URI may point to a JSON file that conforms to the "ERC721 Metadata JSON Schema". This is the “ERC721 Metadata JSON Schema” referenced above.:
    {  "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:Count NFTs tracked by this contract.
  • tokenByIndex:Enumerate valid NFTs.
  • tokenOfOwnerByIndex:Enumerate NFTs assigned to an owner.

Event#

  • Transfer:This emits when ownership of any NFT changes by any mechanism.
  • Approval:This emits when the approved address for an NFT is changed or.
  • ApprovalForAll:This emits when an operator is enabled or disabled for an owner.

Example#

ARC-721 standard is fully compatible with ERC-721, examples are available here.

View Token#

You can view ARC20 Token and transaction history in Alaya Explorer and ATON Wallet.

Contract Deployment#

Please refer to Solidity Getting started.

Method call#

Here's an example of how to call a contract method using the Python SDK.

Install the dependencies#

Use the following command to install the 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.

Instantiation#

from client_sdk_python import Web3, HTTPProvider
rpc, chain_id, hrp = 'http://127.0.0.1:6789', 201030, 'ATP'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": "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": "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": "uint256", "name": "_tokenId", "type": "uint256"}    ],    "name": "Transfer",    "type": "event"  },]arc721 = w3.eth.contract(address='contract address', abi=abi)print([func for func in arc721.functions])print([event for event in arc721.events])

Query Contract Information#

The following is an example of totalSupply, balanceOf, other query methods are similar to this.

# Count all NFTs assigned to an ownerarc721.functions.balanceOf('your address').call()# Find the owner of an NFTarc721.functions.ownerOf('your token id').call()

Sending a contract transaction#

The following is an example of a safeTransferFrom call.

# Transferring 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 = arc721.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#

As an example of a transfer transaction event.

events = arc721.events.Transfer().processReceipt(receipt)

Upload Metadata to IPFS network#

Metadata is the details of the NFT token, whis is stored under the chain. We usually need to specify a URI path as the Metadata data for an NFT token when we issue it.

1. Install IPFS#

Please refer to the IPFS documentation installation and startup.

2. Upload the File#

Upload an picture with the name Alaya.jpeg to the ipfs node.

$ ipfs add Alaya.jpeg

If the above command runs successfully it will output the file ID, as follows.

added QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy Alaya.jpeg

3. Verify that the picture can be downloaded#

Open the following link of the picture in the browser, you can see the picture indicating that the picture can be downloaded successfully: https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=Alaya.jpeg

4. Construct the NFT metadata file#

Next you can use the image link above to construct Metadata for NFT.

Create a JSON file according to the metadata example in the ARC-721 document and name it alaya.json, and replace the description value in the image field with the BTFS download link of the image above, as shown in the figure:

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

Run the following command to upload alaya.json

$ ipfs add alaya.json

You can get the file ID after uploading, as follows:

added QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px alaya.json

Open the URI of the metadata file in the browser: https://ipfs.io/ipfs/QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px?filename=alaya.json

If the Metadata information is displayed in the browser, it means the file was uploaded successfully.