内容简介:通过本文了解: 什么是ERC-721? ERC-721如何实现? 如何使用?本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
通过本文了解: 什么是ERC-721? ERC-721如何实现? 如何使用?
ERC-20 与 ERC-721的区别
在2017年ICO泡沫最严重的时候,ERC-20代币无处不在。 科技公司将其用作众筹的一种形式,其中一些公司声称将来会在其平台上使用这些代币。
ERC-20代币就像货币。 每美元的价值都与其他美元相同。 将一美元的钞票换成另一美元的钞票,本质上是一样的。 这就是所谓的“可替代Token”。
ERC-721 Token就像收藏品 。 每张口袋妖怪卡与其他口袋妖怪卡都不相同。 甚至代表同一个Pokemon的卡的价值也有所不同。 有些卡的状态比其他卡好,有些是限量版或特别版等等。一张皮卡丘卡并不总是等于另一张皮卡丘卡。 这就是所谓的“不可替代Token”。
ERC721 有什么用呢 ?
ERC-721标准描述了任何不可替代令牌都必须遵守的接口才能被视为ERC-721。
幸运的是,我们每次创建ERC-721时都不需要创建新代码来满足该标准。 使用社区维护如[OpenZeppelin对我们来说是一个捷径。
让我们看一下如何使用OpenZeppelin创建简单数字化模仿Pocket Monsters的游戏。 我们将其称为“Ethermon”游戏。
ERC-721 Ethermon 游戏
首先,让我们对每个Ethermon做一些假设(游戏逻辑描述):
-
每个Ethermon都归某人所有。
-
他们从第一级开始。
-
你和其他口袋妖怪战斗。
-
通过战斗获得升级。
我们还需要围绕战斗的一些逻辑。 为简单起见,假设如果一个Ethermon攻击另一个,则级别更高Ethermon的将获胜 。 如果级别相同,则攻击者获胜。 战斗的胜利者上升两级,失败者升一级。
创建ERC721项目
使用Truffle开发框架创建这个基于ERC721的Pokemon游戏项目
首先创建一个新的文件夹,然后初始化Truffle项目:
mkdir ethermon cd ethermon/ truffle init
使用OpenZeppelin
为了使用OpenZepplin,我们需要利用npm导入这个库。让我们先初始化npm, 然后获取正确版本的OpenZeppelin。我们使用最新的稳定版, 2.5.0
版本的OpenZeppelin, 确保你需要使用的是 0.5.5
版本的Solidity编译器:
npm init npm install @openzeppelin/contracts@2.5.0 --save
扩展 ERC-721
在我们的 contracts/
文件夹,先创建一个新的名为 Ethermon.sol
文件。要使用 OpenZeppelin 代码,我们需要引入并扩展 ERC721.sol
。
当前 Ethermon.sol 代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { }
首先使用 truffle compile
检查确保我们的合约可以正确编译。 接下来,我们编写迁移脚本以便将合约部署到本地区块链。在 migrations/
目录下创建一个新的迁移文件 2_deploy_contracts.js
,代码如下:
const Ethermon = artifacts.require("Ethermon"); module.exports = function(deployer) { deployer.deploy(Ethermon); };
确保 truffle-config.js
配置可以正确连接本地区块链,你可以使用 truffle test
先测试一下。
编写 Ethermon 逻辑
Ethermon合约需要实现如下功能:
- 创建新的妖怪
- 将妖怪分配给主人
- 主人可以安排妖怪与其他妖怪的战斗
让我们先实现第一步。我们需要在 Ethermon
合约中用一个数组保存所有的妖怪。需要保存的妖怪相关的数据包括名字、级别等。因此我们使用一个结构体。
现在 Ethermon 合约的代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
Monster
结构体在第7行定义,数组在第12行定义。我们也添加了一个 gameOwner
变量来保存 Ethermon
合约的部署账户。第19行开始是 createNewMonster()
函数的实现, 该函数负责创建新的妖怪。
首先,它会检查这个函数是否是由合约的部署账号调用的。然后为新妖怪生成一个ID,并将新妖怪存入数组,最后使用 _safeMint()
函数将这个新创建的妖怪分配给其主人,这就完成了第一二步。
_safeMint()
是我们继承的ERC721合约中实现的函数。它可以安全地将一个 ID 分配给指定的账号,在分配之前会检查ID是否已经存在。
好了,现在我们已经可以创建新的妖怪并将其分配给指定的账号。该进行 第三步了:战斗逻辑。
战斗逻辑
正如之前所述,我们的战斗逻辑决定了一个妖怪可以升多少等级。较高等级的妖怪可以获胜并升两级,失败的妖怪升一级。如果两个妖怪处于同一等级,那么进攻者获胜。下面的代码展示了合约中战斗逻辑的实现:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } function battle(uint _attackingMonster, uint _defendingMonster) public { Monster storage attacker = monsters[_attackingMonster]; Monster storage defender = monsters[_defendingMonster]; if (attacker.level >= defender.level) { attacker.level += 2; defender.level += 1; } else{ attacker.level += 1; attacker.level += 2; } } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
第19行开始展示了妖怪的战斗逻辑。目前任何账号都可以调用battle()方法。我们需要对此加以限制,只允许发起进攻的妖怪的主人调用该方法。为此,我们可以添加一个修饰器(参考 Solidity 文档 - 函数修饰器
),该修饰器 onlyOwnerOf
利用 ERC721.sol
合约中的 ownerOf()
函数来检查调用者账号。
修改后的代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } modifier onlyOwnerOf(uint _monsterId) { require(ownerOf(_monsterId) == msg.sender, "Must be owner of monster to battle"); _; } function battle(uint _attackingMonster, uint _defendingMonster) public onlyOwnerOf(_attackingMonster) { Monster storage attacker = monsters[_attackingMonster]; Monster storage defender = monsters[_defendingMonster]; if (attacker.level >= defender.level) { attacker.level += 2; defender.level += 1; } else{ attacker.level += 1; attacker.level += 2; } } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
这样就完成了一个使用ERC721的妖怪战斗游戏:我们可以创建新的怪物并分配给某主人。 怪物的主人可以与其他人战斗以升级他们的怪物。
接下来
- 修复代码中 上下溢出漏洞 。
- 添加测试用例
- 扩展代码,为游戏 创建 React 前端
ERC-20 与 ERC-721的区别
在2017年ICO泡沫最严重的时候,ERC-20代币无处不在。 科技公司将其用作众筹的一种形式,其中一些公司声称将来会在其平台上使用这些代币。
ERC-20代币就像货币。 每美元的价值都与其他美元相同。 将一美元的钞票换成另一美元的钞票,本质上是一样的。 这就是所谓的“可替代Token”。
ERC-721 Token就像收藏品 。 每张口袋妖怪卡与其他口袋妖怪卡都不相同。 甚至代表同一个Pokemon的卡的价值也有所不同。 有些卡的状态比其他卡好,有些是限量版或特别版等等。一张皮卡丘卡并不总是等于另一张皮卡丘卡。 这就是所谓的“不可替代Token”。
ERC721 有什么用呢 ?
ERC-721标准描述了任何不可替代令牌都必须遵守的接口才能被视为ERC-721。
幸运的是,我们每次创建ERC-721时都不需要创建新代码来满足该标准。 使用社区维护如[OpenZeppelin对我们来说是一个捷径。
让我们看一下如何使用OpenZeppelin创建简单数字化模仿Pocket Monsters的游戏。 我们将其称为“Ethermon”游戏。
ERC-721 Ethermon 游戏
首先,让我们对每个Ethermon做一些假设(游戏逻辑描述):
-
每个Ethermon都归某人所有。
-
他们从第一级开始。
-
你和其他口袋妖怪战斗。
-
通过战斗获得升级。
我们还需要围绕战斗的一些逻辑。 为简单起见,假设如果一个Ethermon攻击另一个,则级别更高Ethermon的将获胜 。 如果级别相同,则攻击者获胜。 战斗的胜利者上升两级,失败者升一级。
创建ERC721项目
使用Truffle开发框架创建这个基于ERC721的Pokemon游戏项目
首先创建一个新的文件夹,然后初始化Truffle项目:
mkdir ethermon cd ethermon/ truffle init
使用OpenZeppelin
为了使用OpenZepplin,我们需要利用npm导入这个库。让我们先初始化npm, 然后获取正确版本的OpenZeppelin。我们使用最新的稳定版, 2.5.0
版本的OpenZeppelin, 确保你需要使用的是 0.5.5
版本的Solidity编译器:
npm init npm install @openzeppelin/contracts@2.5.0 --save
扩展 ERC-721
在我们的 contracts/
文件夹,先创建一个新的名为 Ethermon.sol
文件。要使用 OpenZeppelin 代码,我们需要引入并扩展 ERC721.sol
。
当前 Ethermon.sol 代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { }
首先使用 truffle compile
检查确保我们的合约可以正确编译。 接下来,我们编写迁移脚本以便将合约部署到本地区块链。在 migrations/
目录下创建一个新的迁移文件 2_deploy_contracts.js
,代码如下:
const Ethermon = artifacts.require("Ethermon"); module.exports = function(deployer) { deployer.deploy(Ethermon); };
确保 truffle-config.js
配置可以正确连接本地区块链,你可以使用 truffle test
先测试一下。
编写 Ethermon 逻辑
Ethermon合约需要实现如下功能:
- 创建新的妖怪
- 将妖怪分配给主人
- 主人可以安排妖怪与其他妖怪的战斗
让我们先实现第一步。我们需要在 Ethermon
合约中用一个数组保存所有的妖怪。需要保存的妖怪相关的数据包括名字、级别等。因此我们使用一个结构体。
现在 Ethermon 合约的代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
Monster
结构体在第7行定义,数组在第12行定义。我们也添加了一个 gameOwner
变量来保存 Ethermon
合约的部署账户。第19行开始是 createNewMonster()
函数的实现, 该函数负责创建新的妖怪。
首先,它会检查这个函数是否是由合约的部署账号调用的。然后为新妖怪生成一个ID,并将新妖怪存入数组,最后使用 _safeMint()
函数将这个新创建的妖怪分配给其主人,这就完成了第一二步。
_safeMint()
是我们继承的ERC721合约中实现的函数。它可以安全地将一个 ID 分配给指定的账号,在分配之前会检查ID是否已经存在。
好了,现在我们已经可以创建新的妖怪并将其分配给指定的账号。该进行 第三步了:战斗逻辑。
战斗逻辑
正如之前所述,我们的战斗逻辑决定了一个妖怪可以升多少等级。较高等级的妖怪可以获胜并升两级,失败的妖怪升一级。如果两个妖怪处于同一等级,那么进攻者获胜。下面的代码展示了合约中战斗逻辑的实现:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } function battle(uint _attackingMonster, uint _defendingMonster) public { Monster storage attacker = monsters[_attackingMonster]; Monster storage defender = monsters[_defendingMonster]; if (attacker.level >= defender.level) { attacker.level += 2; defender.level += 1; } else{ attacker.level += 1; attacker.level += 2; } } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
第19行开始展示了妖怪的战斗逻辑。目前任何账号都可以调用battle()方法。我们需要对此加以限制,只允许发起进攻的妖怪的主人调用该方法。为此,我们可以添加一个修饰器(参考 Solidity 文档 - 函数修饰器
),该修饰器 onlyOwnerOf
利用 ERC721.sol
合约中的 ownerOf()
函数来检查调用者账号。
修改后的代码如下:
pragma solidity ^0.5.5; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Ethermon is ERC721 { struct Monster { string name; uint level; } Monster[] public monsters; address public gameOwner; constructor() public { gameOwner = msg.sender; } modifier onlyOwnerOf(uint _monsterId) { require(ownerOf(_monsterId) == msg.sender, "Must be owner of monster to battle"); _; } function battle(uint _attackingMonster, uint _defendingMonster) public onlyOwnerOf(_attackingMonster) { Monster storage attacker = monsters[_attackingMonster]; Monster storage defender = monsters[_defendingMonster]; if (attacker.level >= defender.level) { attacker.level += 2; defender.level += 1; } else{ attacker.level += 1; attacker.level += 2; } } function createNewMonster(string memory _name, address _to) public { require(msg.sender == gameOwner, "Only game owner can create new monsters"); uint id = monsters.length; monsters.push(Monster(_name, 1)); _safeMint(_to, id); } }
这样就完成了一个使用ERC721的妖怪战斗游戏:我们可以创建新的怪物并分配给某主人。 怪物的主人可以与其他人战斗以升级他们的怪物。
接下来
- 修复代码中 上下溢出漏洞 。
- 添加测试用例
- 扩展代码,为游戏 创建 React 前端
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
- 发表于 2分钟前
- 阅读 ( 5 )
- 学分 ( 0 )
- 分类:以太坊
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用Akka实现并发
- 使用GOLANG实现猴子排序
- 使用 WebSocket 实现 JsBridge
- 使用 RabbitMQ 实现 RPC
- 使用Kafka实现事件溯源
- 使用 Swift 实现 Promise
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective Java: Second Edition
Joshua Bloch / Addison-Wesley / 2008-05-28 / USD 54.99
Written for the working Java developer, Joshua Bloch's Effective Java Programming Language Guide provides a truly useful set of over 50 best practices and tips for writing better Java code. With plent......一起来看看 《Effective Java: Second Edition》 这本书的介绍吧!