返回介绍

PRC-721

发布于 2023-07-01 15:28:54 字数 11667 浏览 0 评论 0 收藏 0

PRC-721合约

PRC-721是在PlatON网络上发行非同质化代币(non-fungible token, NFT)一套标准接口,与ERC-721完全兼容。

协议标准

每个符合PRC-721标准的智能合约都必须实现PRC721与PRC165接口,并可以根据业务需要实现其他扩展接口。

PRC-721 & PRC-165接口


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);
    }
    //metadata extension接口对于PRC-721智能合约来说是可选的,用户可以查询智能合约的名称以及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);
    }
    //enumeration extension对于PRC-721智能合约是可选的,允许用户的智能合约发布其NFT的完整列表并使其可见。
    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);
    }
}

必须实现的接口

  • balanceOf

    统计用户持有的NFT数量。

  • ownerOf

    查询NFT的持有者。

  • safeTransferFrom

    将NFT的所有权从一个地址转移到另一个地址。

  • transferFrom

    转移NFT所有权,调用者负责确认接收者是否有能力接收NFT,否则可能永久丢失。

  • approve

    授权第三方操作某个NFT资产。

  • setApprovalForAll

    启用或禁用第三方管理交易发起者的所有资产。

  • getApproved

    获取单个NFT的被授权给哪个地址管理。

  • isApprovedForAll

    查询一个地址是否被另一个地址授权管理token。

  • supportsInterface

    查询合约是否实现了某个接口。

可选实现的接口

  • onERC721Received

    合约如果需要接受安全转账,必须实现PRC721TokenReceiver接口。

  • name

    合约的名字。

  • symbol

    合约的缩写代号。

  • tokenURI

    给token一个统一资源标识符(URI),指向符合 "PRC721 元数据 JSON Schema" 的 JSON 文件,铸造代币时需要给每个代币指定唯一的URI。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

    根据索引查询token。

  • tokenOfOwnerByIndex

    根据索引来查找用户的token。

事件

  • Transfer

    任何NFT的所有权更改时(不管哪种方式),就会触发此事件,在链上记录所有权更改信息日志。

  • Approval

    当更改或确认NFT的授权地址时触发,在链上记录此信息日志。

  • ApprovalForAll

    所有者启用或禁用操作员时触发(操作员可管理所有者所持有的NFTs),在链上记录此信息日志。

示例

PRC-721标准与ERC-721完全兼容,示例可参考这里

查看

可以通过PlatON浏览器查看,也可以通过ATON查看PRC-721合约交易。

合约发行

请参考Solidity合约入门手册

调用方法

以python为例:

安装python依赖

使用下列命令,安装PlatON 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', 210425, '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": "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"
  },
]
prc721 = w3.eth.contract(address='contract address', abi=abi)
# 查看合约所有的function 和 event
print([func for func in prc721.functions])
print([event for event in prc721.events])

查询合约信息

以balanceOf、ownerOf示例,其他查询方法与此类似:


# 统计用户持有的NFT数量
prc721.functions.balanceOf('your address').call()
# 查询NFT的持有者
prc721.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 = 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)

获取合约事件

以safeTransferFrom交易事件示例,其他事件获取方法与此类似:


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

上传Metadata到IPFS网络

Metadata 是NFT代币的元数据,以便更丰富地显示NFT资产的详细信息, 存储在链下,一般发行一枚NFT代币会指定一个URI路径,指向这枚代币的Metadata数据。

1.安装IPFS

参照IPFS安装说明进行安装与启动。

2.添加文件到ipfs

准备一张图片,将图片命名为PlatON.jpeg,上传到ipfs节点上


$ ipfs add  PlatON.jpeg
added QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy PlatON.jpeg
//QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy 是文件的唯一ID,添加到ipfs后生成

在浏览器里面打开图片的链接,能看到图片说明图片能成功被下载: https://ipfs.io/ipfs/QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy?filename=PlatON.jpeg

有了上面的图片链接,就可以用它来构造用于NFT的metadata了。

首先按照PRC-721文档中metadata的说明创建一个json文件,命名为PlatON.json:


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

上传到ipfs节点上:


$ ipfs add  PlatON.json
added QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px PlatON.json

在浏览器里面打开metadata文件的uri: https://ipfs.io/ipfs/QmQXqTVCb1w7CmdsYxHWR1T1qyaCHHgWwiPmoZDcQL39Px?filename=PlatON.json

以上,上传完毕。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文