ERC20出现之后,我开始去了解什么是ERC20。但是在2017年,一种名为CryptoKitties(加密猫)的以太坊游戏在顷刻间吸引了全球众多虚拟游戏世界里面的玩家,占据了各大媒体以及网站的头条,一只加密猫的价格最高峰竟然达到1亿RMB,究竟是什么东西的存在使得这款游戏变得如此疯狂,使得众多游戏玩家为之而痴迷,接下来就有我来给大家简单的剖析一下CryptoKitties(加密猫)游戏背后的主谋吧。首先CryptoKitties(加密猫)是一款玩家可以在游戏里进行加密猫的买、卖、交易以及培养出新的加密猫的区块链游戏。但是,我们童年时代曾经玩过的数码宝贝也是有这样类似的功能,只不过存在于单机游戏里面,包括现在有很多游戏也有这样的游戏体验功能。能够使得CryptoKitties(加密猫)变得如此有魅力,如此让玩家为之投放RMB是因为其背后的ERC721所起到的作用。如果ERC721换成了ERC20,我相信这款游戏的吸引力应该不会有巅峰时那么高,虽然CryptoKitties(加密猫)是以太坊推出的首款区块链游戏。
由于有ERC721的支撑,CryptoKitties(加密猫)变得更有收藏价值,更有意义,因为每只加密猫都有一个ERC721 Token,而这个token是唯一且不能重复生成,好比与每个人的基因,是独一无二的。而ERC721 Token的id就好比加密码中的DNA,所以每个加密猫都是独一无二的。正是唯一性以及稀有性才促使加密猫收藏价值的形成。
回溯历史,收藏已经成为个别人的一种爱好,人们喜欢收藏是源自于商品的稀缺性以及唯一性(不可再生性——此处不谈及仿制品),同样地,我们通过采用以太坊的ERC721 Token对某些商品进行标记并使其产生稀缺性。 与ERC20相似,ERC721是一种标准的协议且充当交易Token能够实现智能合约以及外部应用交易。
可替代性——是商品中的一种性质(金钱和商品),能够让其他等价或等性质的商品来替代。一般而言,可替代性是货币或者Token的一种性质,去确定相同或相似类型的物品或数量在交换或使用过程中是否可以实现互换。举个例子,我们可以用RMB在现实生活中的某一家便利店购买一瓶苏打水。
但是,当我们用一件科比的秋衣去超市兑换一件商品,也许老板不会卖给你,有人会问为什么呢?虽然科比
的球衣是你用300元买回来的,而且你觉得这球衣对于你来说是有收藏价值的。但是,超市的老板也许连科比都不知道是谁,他更不认为一件球服具有收藏价值。
就收藏品而言,如果收藏品具有不同的特征,则收藏品中的两件物品不可替代。 对于物理硬币,金币不能与铜币相互替换,因为它们的不同特征赋予了它们与收藏者不同的价值。
ERCToken 可以用到任何交易,但其价值是由每个Token的唯一性和罕见性所致。这一标准定义了相关函数:name , symbol , totalSupply , balanceOf , ownerOf , approve , takeOwnership , transfer , tokenOfOwnerByIndex 以及定义了两个时间:Transfer and Approval。下面就简单的介绍介绍ERC721:
contract ERC721 {
// ERC20 compatible functions
function name() constant returns (string name);
function symbol() constant returns (string symbol);
function totalSupply() constant returns (uint256 totalSupply);
function balanceOf(address _owner) constant returns (uint balance);
// Functions that define ownership
function ownerOf(uint256 _tokenId) constant returns (address owner);
function approve(address _to, uint256 _tokenId);
function takeOwnership(uint256 _tokenId);
function transfer(address _to, uint256 _tokenId);
function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId);
// Token metadata
function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl);
// Events
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
}
细分如下:(这些例子仅在发文章时候引用,没有测试过,请不要把这些运用到实际开发中去)
ERC721定义的某些函数也遵循了ERC20的标准,这样使得现有的钱包能够更容易显示token简单的信息,这些功能可以让符合这个标准的智能合约充当像比特币或以太坊这样的通用加密货币,通过定义允许用户执行诸如向他人发送令牌和检查账户余额的功能。
name:
这个函数作用于告诉外部智能合约以及应用Token的名字,如下是该函数使用的一个例子:
contract MyNFT {
function name() constant returns (string name){
return "My Non-Fungible Token";
}
}
symbol:
该功能还有助于提供与ERC20令牌标准的兼容性。 它为外部程序提供令牌的简写名称或符号。
contract MyNFT {
function symbol() constant returns (string symbol){
return "MNFT";
}
}
totalSupply:
该函数返回区块链上可用的硬币总数。
contract MyNFT {
// This can be an arbitrary number
uint256 private totalSupply = 1000000000;
function totalSupply() constant returns (uint256 supply){
return totalSupply;
}
}
balanceOf:
该函数是用户提供钱包地址去搜索账户中的Token的数目。
contract MyNFT {
mapping(address => uint) private balances;
function balanceOf(address _owner) constant returns (uint balance)
{
return balances[_owner];
}
}
该函数定义了智能合约如何去处理一个token的所有者,而且所有者如何转换。最为显著的函数是:takeOwnership和transfer二者起到的是提款以及账户与账户之间转账的作用。
ownerOf:
该函数是返回Token拥有者的地址,由于每个ERC721令牌都是不可替代的,因此它们是唯一的,它通过唯一ID在区块链中引用,我们可以使用其ID来确定Token的所有者。
contract MyNFT {
mapping(uint256 => address) private tokenOwners;
mapping(uint256 => bool) private tokenExists;
function ownerOf(uint256 _tokenId)
constant returns (address owner) {
require(tokenExists[_tokenId]);
return tokenOwners[_tokenId];
}
}
approve:
该功能批准或授予另一实体代表所有者转让代币的权限。 例如,如果爱丽丝拥有1个NFT,她可以为她的朋友鲍勃拨打批准功能。 通话成功后,鲍勃可以代表爱丽丝以后对该令牌进行所有权或执行操作。
contract MyNFT {
mapping(address => mapping (address => uint256)) allowed;
function approve(address _to, uint256 _tokenId){
require(msg.sender == ownerOf(_tokenId));
require(msg.sender != _to);
allowed[msg.sender][_to] = _tokenId;
Approval(msg.sender, _to, _tokenId);
}
}
takeOwnership:
这个功能就像一个提款功能,因为外部用户可以调用它来从另一个用户的帐户中取出Token。 因此,当用户被批准拥有一定数量的Token(该Token属于当前用户但存于另一用户)并希望从另一用户的余额中提取所述Token时,可以takeOwnership函数。
contract MyNFT {
function takeOwnership(uint256 _tokenId){
require(tokenExists[_tokenId]);
address oldOwner = ownerOf(_tokenId);
address newOwner = msg.sender;
require(newOwner != oldOwner);
require(allowed[oldOwner][newOwner] == _tokenId);
balances[oldOwner] -= 1;
tokenOwners[_tokenId] = newOwner;
balances[newOwner] += 1;
Transfer(oldOwner, newOwner, _tokenId);
}
}
transfer:
该方法是用于转换Token,transfer让Token的所有者将其发送给其他用户,类似于独立的加密货币。但是,只有当接收账户先前已被发送账户批准拥有该Token时才能启动转账。
contract MyNFT {
mapping(address => mapping(uint256 => uint256)) private ownerTokens;
function removeFromTokenList(address owner, uint256 _tokenId) private {
for(uint256 i = 0;ownerTokens[owner][i] != _tokenId;i++){
ownerTokens[owner][i] = 0;
}
}
function transfer(address _to, uint256 _tokenId){
address currentOwner = msg.sender;
address newOwner = _to;
require(tokenExists[_tokenId]);
require(currentOwner == ownerOf(_tokenId));
require(currentOwner != newOwner);
require(newOwner != address(0));
removeFromTokenList(_tokenId);
balances[oldOwner] -= 1;
tokenOwners[_tokenId] = newOwner;
balances[newOwner] += 1;
Transfer(oldOwner, newOwner, _tokenId);
}
}
tokenOfOwnerByIndex (优先推荐):
每个人同时可以拥有一个或多个Token,因为每个Token的ID都是唯一的,所以很难跟踪到每个人所拥有的Token的ID。为此,该智能合约记录了每个人所拥有Token的ID,因此,用户拥有的每个单独的Token都可以通过其索引在用户拥有的Token列表(数组)中检索。tokenOfOwnerByIndex可以帮助我们检索出任意令牌。
contract MyNFT {
mapping(address => mapping(uint256 => uint256)) private ownerTokens;
function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId){
return ownerTokens[_owner][_index];
}
}
正如我们之前所说的,一张人民币和一件科比的球服之间是不可替换的,因为它们有着各自不同的属性。在可以告知Token属性的区块链上存储数据是相当的昂贵以及不推荐此方法,为了解决这个问题,我们可以将引用(如IPFS哈希或HTTP(S)链接)存储到链上的每个Token的属性,以便链外的程序可以执行逻辑来查找有关Token的更多信息。
tokenMetadata(优先推荐):
这方法可以让我们查看Token的元数据或者数据的链接。
contract MyNFT {
mapping(uint256 => string) tokenLinks;
function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl) {
return tokenLinks[_tokenId];
}
}
只要合同调用,事件都会被出发。而且一旦触发事件,将会广播到所有的监听中去。外部程序监听区块链事件,以便在事件触发后使用事件提供的信息执行逻辑。ERC712定义的两个事件如下:
Transfer:
只要Token的持有者发生改变,都会触发此事件,同时会被广播。 广播里会详细说明哪个帐户发送Token,哪个帐户收到Token,以及哪个Token(通过ID)被传送。
contract MyNFT {
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
}
Approval:
只要Token的所有者同意另一用户获得Token的所有权,事件将会被触发。它详细说明哪个帐户当前拥有该Token,哪个帐户将来拥有该Token,以及哪个Token(通过Token的ID)被批准转让其所有权。
contract MyNFT {
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
}
与ERC20类似,新提出的ERC721标准为新的智能合约开辟了一个通道,作为不可互换的东西。 正如在CryptoKitties(ERC721),Decentraland(ERC20),CryptoPunks(ERC20)和其他应用程序中可以看到的,不可互换的令牌已被证明是非常高需求的产品。 即使维基解密拥有几个高价值的CryptoKitties! 但是,最终这一标准将进一步扩大加密货币经济并有助于推动这一领域的进一步发展。
本篇文章作者大部分内容引用了Gerald Nash 的文章,也加入了自己的一些看法以及理解,本篇文章仅代表个人意见,如有不得之处请在评论区告知。