- 概述
- 初步了解
- 进阶了解
- PlatON 节点
- 开发者
- 数据分析
- 示例教程
- 以太坊 DApp 快速迁移教程
- PRC721NFT 发行教程
- Wasm教程
- WalletConnect
- 获取随机数教程
- EIP55 和 Bech32 地址格式兼容方案
- 钱包
- 社区项目
PRC-721
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论