Appearance
ERC721
我们之前讨论了如何用ERC20来创建可替换token,但并不是所有的token都是如此。在房地产,投票权,收藏品领域中,由于实用性,稀有性等原因,某些的价值会比其他更高。ERC721是用来表述不可替换token的标准,也就是说每个token都是唯一的。
ERC721标准比ERC20标准更加复杂一些,它具有多个扩展项,并且被拆分成多个智能合约。OpenZeppelin合约为如何组合这些方面提供了灵活性,以及有用的自定义扩展。请参考API Reference获取更多信息。
构建ERC721智能合约
我们会用ERC72来追踪游戏中的物品,每个物品都有独特的属性。当要给予玩家奖励时,token会被挖出来并发送给玩家。玩家可以自由保留他们的代币或在他们认为合适的时候与其他人交易,就像他们对区块链上的任何其他资产一样。请注意任何人都可以调用awardItem
来铸造物品。我们可以通过访问控制来限制哪些账户可以铸造物品。
下面是token化合约的示例代码:
solidity
// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract GameItem is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("GameItem", "ITM") {}
function awardItem(address player, string memory tokenURI)
public
returns (uint256)
{
uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
_setTokenURI(newItemId, tokenURI);
_tokenIds.increment();
return newItemId;
}
}
ERC721URIStorage 合约是 ERC721 的实现,包括元数据标准扩展 (IERC721Metadata) 以及每个令牌元数据的机制。这就是_setTokenURI
方法的作用,我们用它来设置物品的元数据。
同时请注意,和ERC20不同,ERC721没有decimals
字段,因为每个token都是唯一的,并且不能被分割。
新物品可以这样生成:
sh
> gameItem.awardItem(playerAddress, "https://game.example/item-id-8u5h2m.json")
Transaction successful. Transaction hash: 0x...
Events emitted:
- Transfer(0x0000000000000000000000000000000000000000, playerAddress, 7)
并且每个物品的所有者和元数据都可以被查询:
sh
> gameItem.ownerOf(7)
playerAddress
> gameItem.tokenURI(7)
"https://game.example/item-id-8u5h2m.json"
tokenURI
是一个json格式的数据,如下所示:
json
{
"name": "Thor's hammer",
"description": "Mjölnir, the legendary hammer of the Norse god of thunder.",
"image": "https://game.example/item-id-8u5h2m.png",
"strength": 20
}
更多关于tokenURI
元数据JSON文件的格式,请参考ERC721说明书
注意
你可能已经注意到了,物品属性的元数据并没有存在链上。所以游戏开发者可以在链下修改元数据从而修改游戏的规则。
提示
如果您想将所有项目信息放在链上,您可以通过提供带有 JSON 模式编码的 Base64 数据 URI 来扩展 ERC721 以这样做(尽管它会相当昂贵)。您还可以利用 IPFS 来存储 tokenURI 信息,但这些技术超出了本概述指南的范围。
预设ERC721合约
预设ERC721合约是可以做到的,可以使用ERC721PresetMinterPauserAutoId。它可以让token挖矿(create)时自动设置token ID 和 URI,还可以停止所有代币转移(pause)并允许持有者销毁(destroy)他们的代币。合约通过访问控制来限定访问挖矿和暂停的方法。部署合约的账户将被授予 minter 和 pauser 角色,以及默认的 admin 角色。
该合约无需编写任何 Solidity 代码即可部署。它可以按原样用于快速原型设计和测试,但也适用于生产环境。