ARC721
#
ARC-721ARC-721是 Alaya 网络上发行非同质化代币(NFT)的一套标准接口,与 ERC-721完全兼容。
#
协议标准每个符合 ARC-721 标准的智能合约都必须实现 ARC721 与 ARC165 接口,并可以根据业务需要实现其他扩展接口。
#
ARC-721 & ARC-165接口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); } //metadata extension接口对于ARC-721智能合约来说是可选的,用户可以查询智能合约的名称以及NFT代表的资产的详细信息。 interface ARC721Metadata { function name() external view returns (string _name); function symbol() external view returns (string _symbol); function tokenURI(uint256 _tokenId) external view returns (string); } //enumeration extension对于ARC-721智能合约是可选的,允许用户的智能合约发布其NFT的完整列表并使其可见 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); }}
#
必须实现的接口balanceOf
:统计用户持有的NFT数量ownerOf
:查询NFT的持有者safeTransferFrom
:将NFT的所有权从一个地址转移到另一个地址transferFrom
:转移NFT所有权,调用者负责确认接收者是否有能力接收NFT,否则可能永久丢失approve
:授权第三方操作某个NFT资产setApprovalForAll
:启用或禁用第三方管理交易发起者的所有资产getApproved
:获取单个NFT的被授权给哪个地址管理isApprovedForAll
:查询一个地址是否被另一个地址授权管理tokensupportsInterface
:查询合约是否实现了某个接口
#
可选实现的接口onERC721Received
:合约如果需要接受安全转账,必须实现ARC721TokenReceiver接口name
:合约的名字symbol
:合约的缩写代号tokenURI
:给token一个统一资源标识符(URI),指向符合 "ARC721 元数据 JSON Schema" 的 JSON 文件,JSON 结构如下:{ "title": "Asset Metadata", "type": "object", "properties": { "name": { "type": "string", "description": "指示NFT代表什么" }, "description": { "type": "string", "description": "描述NFT 代表的资产" }, "image": { "type": "string", "description": "指向NFT表示资产的资源的URI(MIME 类型为 image/*) , 可以考虑宽度在320到1080像素之间,宽高比在1.91:1到4:5之间的图像 } }}
totalSupply
:查询此合约拥有的token的总数tokenByIndex
:根据索引查询tokentokenOfOwnerByIndex
:根据索引来查找用户的token
#
事件- Transfer:任何NFT的所有权更改时(不管哪种方式),就会触发此事件,在链上记录所有权更改信息日志
- Approval:当更改或确认NFT的授权地址时触发,在链上记录此信息日志
- ApprovalForAll:所有者启用或禁用操作员时触发(操作员可管理所有者所持有的NFTs),在链上记录此信息日志
#
示例ARC-721标准与ERC-721完全兼容,示例可参考这里。
#
查看可以通过Alaya浏览器查看,也可以通过ATON查看ARC-721合约交易。
#
合约发行请参考Solidity合约入门手册。
#
调用方法以python为例:
#
安装python依赖使用下列命令,安装 python library
,建议 Python 版本在3.7.5+:
pip install client-sdk-python
在安装过程中,部分依赖包会需要 c++14
编译,请在看到相关提示后,下载cppbuildtools,使用默认值安装后,重新执行 pip 安装命令即可。
#
实例化合约以下为python代码示例:
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)# 查看合约所有的function 和 eventprint([func for func in arc721.functions])print([event for event in arc721.events])
#
查询合约信息以 balanceOf
、ownerOf
示例,其他查询方法与此类似:
# 统计用户持有的NFT数量arc721.functions.balanceOf('your address').call()# 查询NFT的持有者arc721.functions.ownerOf('your token id').call()
#
发送合约交易以safeTransferFrom
示例,其他交易方法与此类似:
# 将NFT的所有权从一个地址转移到另一个地址tx = { '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)
#
获取合约事件以safeTransferFrom
交易事件示例,其他事件获取方法与此类似:
events = arc721.events.Transfer().processReceipt(receipt)
#
上传Metadata到IPFS网络Metadata
是NFT代币的详细信息, 存储在链下,一般发行一枚 NFT 代币会指定一个 URI 路径,指向这枚代币的 Metadata 数据。
#
1. 安装IPFS参照IPFS安装说明进行安装与启动。
#
2. 添加文件到ipfs准备一张图片,将图片命名为 Alaya.jpeg,通过以下命令上传到 ipfs 节点上
$ ipfs add Alaya.jpeg
输出以下文件ID:
added QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy Alaya.jpeg
#
3. 验证文件是否上传成功在浏览器里面打开图片的链接,能看到图片说明图片能成功被下载: https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=Alaya.jpeg
#
4. 构造NFT的 Metadata首先按照ARC721 元数据 JSON Schema 创建一个json文件,命名为Alaya.json,示例如下:
{ "name":"Alaya.jpg", "author":"Alaya", "description":"use for arc721", "image":"https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=Alaya.jpeg"}
将 Alaya.json 上传到 IPFS 节点上:
$ ipfs add Alaya.json
输出以下文件ID:
added QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px Alaya.json
在浏览器里面打开metadata文件的uri: https://ipfs.io/ipfs/QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px?filename=Alaya.json
以上,上传完毕。