买不起2.6亿一只的加密猫 他用10分钟生了一窝
不知道多少人和营长一样,在结束一天的工作后,就想瘫在沙发上玩玩游戏,一扫一天的疲惫。不过现在的游戏都越来越氪金了,就像玩家们常说的:不充钱你怎么能变强!!!
但要说氪金,很少有哪个游戏能比得上区块链游戏,因为区块链上的游戏都建立在一笔笔真实的加密货币交易之上。
就拿最火的去中心化游戏加密猫来说,其刚上线时一只加密猫能卖到上千元人民币,最贵的一只竟卖到了 125673 个以太币,在当时约合人民币 2.6 亿元(太可怕了)。
当时最贵的一只加密猫
不禁让人直呼:玩不起,玩不起。
玩不起又想玩怎么办?
手把手开发一款区块链游戏,不就OK了,何况又那么简单,10分钟就够了
这是一款怎样的 DApp?
从现在开始,我们将构建一个类似于加密猫的简单 DApp,我们称之为加密毒蛇
你可能会问为什么是蛇呢,但为什么不能是蛇呢?Python 翻译过来也是蛇呀。
在这个 DApp 中,你可以购买毒蛇和养殖毒蛇,应用页面是这样的:
加密毒蛇程序的页面
其功能列表如下:
创建加密毒蛇,你至少需要用到以下工具
此外,你还需要使用 Git 来克隆一些代码模板。
在进行编程之前,这里先假定你已经对以下的知识有了基本的了解。
当然了,如果你对这一些知识还有欠缺,也不用担心,本文会详细介绍每一个细节。
深入了解 ERC-721 标准
ERC-721 是一个用来描述如何在以太坊区块链上制造不可替代 token 的标准。满足 ERC-721 标准的每个 token 或其他数字资产都是唯一的,这意味着它不等同于任何其他 token。你可以把它们想象成一种特殊的,独一无二的收藏品。(如果你已了解 ERC-721,可选择跳过这一部分)
ERC-721 标准的接口
根据标准的官方文档,ERC-721 规定了智能合约用以管理、持有和交易唯一 token 必须实现的最小接口:
此外,它还定义了两个事件:Transfer 和 Approval。当 token 从一个钱包转移到另一个钱包时,会触发转移事件。另一方面,当一个账户批准另一个账户声明他拥有的某个 token 的所有权时,会触发批准事件。
OpenZeppelin 的 ERC-721 token 实现
OpenZeppelin 是一款开源智能合约开发框架,它提供了可重复使用的智能合约模板,包括 ERC-20 和 ERC-721 等标准 token 的实现模板。在这里,我们将导入他们的 ERC-721 token 实现,这样我们就不必从头开始编写它,避免了重复造轮子。
创建智能合约
此 DApp 是基于以太坊平台开发,所以需要使用 Solidity 语言发行 token。
首先,在开源智能合约开发环境 Remix 中,创建一个名为 ViperToken.sol 的新文件并在其中添加以下代码:
pragma solidity ;
import ;
import ;
contract ViperToken is ERC721Full {
using SafeMath uint256;
struct Viper {
uint8 genes;
uint256 matronId;
uint256 sireId;
}
Viper[] vipers;
event Birth(
address owner,
uint256 viperId,
uint256 matronId,
uint256 sireId,
uint8 genes
);
constructor() ERC721Full(, ) {
}
{
}
{
uint8(matron.add(sire)) % ;
}
{
(viperOwner !=address());
uint8 newGenes=generateViperGenes(matron, sire);
Viper memory newViper=Viper({
genes: newGenes,
matronId: matron,
sireId: sire
});
uint256 newViperId=vipers.push(newViper).sub();
super._mint(viperOwner, newViperId);
emit Birth(
viperOwner,
newViperId,
newViper.matronId,
newViper.sireId,
newViper.genes
);
newViperId;
}
{
(msg.value== ether);
createViper(, , msg.sender);
}
{
(msg.value== ether);
createViper(matronId, sireId, msg.sender);
}
{
Viper storage viper=vipers[viperId];
(viperId, viper.genes, viper.matronId, viper.sireId);
}
{
uint256 viperCount=balanceOf(msg.sender);
(viperCount==) {
uint256[]();
} {
uint256[] memory result= uint256[](viperCount);
uint256 totalVipers=vipers.length;
uint256 resultIndex=;
uint256 viperId=;
(viperId < totalVipers) {
(ownerOf(viperId)==msg.sender) {
result[resultIndex]=viperId;
resultIndex=resultIndex.add();
}
viperId=viperId.add();
}
result;
}
}
}
由 GitHub 托管的 ViperToken.sol
在上面的代码中,我们套用了 OpenZeppelin 的 ERC-721 token 实现,并在其中添加了自定义函数。此外,还在代码中导入了 SafeMath 库以避免出现整数的上溢和下溢漏洞(去年四月份,美图的 BEC token 就因为存在整数溢出漏洞,一夜间被黑客盗取了64亿)。
接下来,详细介绍一下代码的功能:
首先,函数 generateViperGenes 用来确定新出生毒蛇的基因,主要用在两条毒蛇繁育新毒蛇时(结合其双亲的基因)。我们选择了一种非常简单的实现方式,在这种情况下,我们使用1到6这几个简单的数字来确定新出生毒蛇的长相。当然了,你也可以修改代码,创造出更多独具特色的毒蛇。
然后,我们实现了一个 createViper 函数,这个函数用来创建一条新的毒蛇,并通过传入函数的参数“ viperOwner ”指定该新创建毒蛇的所有者。
函数 buyViper 是一个可以接受以太币付款的函数( payable function ),函数中调用了我们之前定义的 createViper 函数。Payable 这个标记是一个修饰符,用于指出此函数在执行时可以接收以太币付款。相信你能从这行明摆着就是要钱的代码中看出来:
(msg.value== ether);
代码中的 require 语句会检查是否满足给定的条件,并在不满足条件时报错。在 Solidity 语言中,msg.value 语句用来存储调用该函数的用户发送的以太币数量。
在上面的代码中,我们要求用户支付 0.02 个以太币来购买一条随机分配的毒蛇。在这里,你就是上帝,你可以随意修改这个金额,如果你愿意的话,甚至还可以删除这条语句,这样每个用户都可以访问这个函数来免费得到一条毒蛇。
函数 breedVipers 在调用时代价更为昂贵,它需要用户支付 0.05 个以太币,不过这并不是为了蒙骗小白,因为该函数允许用户根据两条毒蛇父母的基因创建一条新的毒蛇,也就是说可以让用户得到一条高身价的毒蛇。
当然了,我们还需要定义一个能够查看毒蛇详细信息的函数。函数 getViperDetails 在被调用时会返回给定毒蛇的基因和父母 ID 之类的细节。
最后是一个 ownVipers 函数,该函数可以返回调用者拥有的毒蛇的 ID 列表。具体的实现是通过 msg.sender 这个语句,它用来标记调用函数的用户的地址。
现在,所有的函数都已定义完毕,接下来,我们需要编译 ViperToken 智能合约,这里需要注意的是,请在 Remix 界面的右侧选择编译器的版本,指定版本为 0.5.3 commit.10d17f24 ,因为我们使用的是 0.5.3 版本的 Solidity 语言,完成后我们就可以将智能合约部署到以太坊 Ropsten 测试网络上了。
这里我们编译并部署了 ViperToken 智能合约,由于操作步骤较多,你最好检查一下每一步是否都已正确完成。
如果所有的步骤都没有出错,智能合约得到了正确的部署,你会看到如下页面:
智能合约编译成功的页面
智能合约已被成功部署并加入到“已部署智能合约”中
构建 Web 应用程序
到这里,智能合约就可以正常运行了,但如果没有一个与之交互的 Web 应用程序,那么运行起来就只能看到一些数字。为了让这个 DApp 更有意思,接下来营长带你制作一个简单的 Web 应用程序。
配置开发环境
构建 Web 应用程序首先需要配置开发环境,在这里废话不多说,让我们直接切入正题。让我们在终端(或者Windows中的命令提示符/ Powershell)中执行以下操作来克隆 GitHub 上的代码模板:
git clone -b boilerplate --single-branch https:thub.com/openberry-ac/cryptovipers.git
cd cryptovipers
install
install -s web3@-beta
run dev
克隆 GitHub 上的代码模板
这可能需要几分钟的执行时间,操作完成后,你的 Web 应用程序就运行起来了。
你可以在浏览器中访问 http:// localhost:8080 看到它,应用程序界面长这样:
加密毒蛇的页面
连接到智能合约实例
为了使我们的 Web 应用程序能够与先前部署的智能合约进行交互,这里我们会用到与本地以太坊节点进行通信的 js 库 web3.js 。在配置开发环境时我们已经安装好了软件包,现在我们要在“ contracts”文件夹下名为 web3.js 的文件中加入如下代码来调用它:
Web3 ;
getWeb3= ( {
.addEventListener(, ()=> {
currentWeb3;
(.ethereum) {
currentWeb3= Web3(.ethereum);
{
.ethereum.enable();
resolve(currentWeb3);
} (error) {
alert();
}
} (.web3) {
.web3= Web3(web3.currentProvider);
resolve(currentWeb3);
} {
.log();
}
});
});
getWeb3;
由 GitHub 托管的 web3.js
上面的代码加载了 MetaMask 浏览器扩展初始化的 web3 实例,稍后我们将用它来和先前部署的智能合约进行交互。
在这个过程中你可能会遇到 MetaMask 的弹出窗口,它会要求获取访问权限。这是因为我们在代码中加入了 ethereum.enable(),所以在 Web 应用程序请求访问帐户时窗口就会自动弹出,这时你只需要像下图一样点击“Connect”按钮即可:
MetaMask 的弹出窗口
现在,我们需要让这个 Web 应用程序连接到智能合约的 ABI (Application Binary Interface,应用程序二进制接口)上。要获取 ABI 我们需要返回到 Remix 的界面,转到 Compile 选项卡,然后单击 Details 按钮旁边的 ABI 按钮,具体操作如下图所示:
点击 ABI 按钮来复制智能合约的 ABI
获取了 ABI 后,在 contract 文件夹下打开名为 abi.js 的文件,然后将 ABI 粘贴为变量 contractAbi 的值,如下所示:
contractAbi=
contractAbi;
由 GitHub 托管的 abi.js
文件中应该会有一个示例代码,遇到问题时你可以随时参考它。然后,我们还必须指定智能合约实例的地址,你需要回到 Remix 界面的 Deploy 选项卡,然后单击已部署智能合约上的复制图标,具体操作如下图所示:
点击“复制”按钮复制智能合约实例地址
在 src 文件夹下找到的 App.vue ,打开并将你的智能合约地址粘贴到第 86 行,作为变量 contractAddress 的值(文件中也应该有注释,你可以随时参考这些注释):
contractAddress=;
定义实现的方法
现在你可能会注意到用户界面一切都正常,但点击按钮却不起任何作用。这是因为我们还没有定义 Web 应用程序的功能,接下来我们就开动。首先返回到 App.vue 文件中,转到第 116 行,你可以在其中查到所有的方法,但所有方法的实现都只包含一个输出方法名的 console.log()。
Web 应用程序的第一个功能是购买毒蛇。让我们用以下代码修改 buyViper()方法:
buyViper() {
.isLoading=;
.contractInstance.methods.buyViper().send({
from: .account,
value: web3.toWei(, ),
}).( {
.addViperFromReceipt(receipt);
.isLoading=;
}).( {
.log(err, );
.isLoading=;
});
},
由 GitHub 托管的 App.vue
还记得我们在智能合约中的规定么?购买一条毒蛇我们需要收取 0.02 个以太币的费用,因此在代码中我们需要同时发送我们的帐户信息和 0.02 个以太币来进行支付。然后我们就可以调用智能合约中的 buyViper()函数,该函数会返回新生成毒蛇的详细信息,紧接着我们将这些细节保存在 vipers 数组中。
接下来,修改繁殖毒蛇的功能 breedVipers():
breedVipers() {
.isLoading=;
.contractInstance.methods.breedVipers(.matron, .sire).send({
from: .account,
value: web3.toWei(, ),
}).( {
.addViperFromReceipt(receipt);
.isLoading=;
}).( {
.log(err, );
.isLoading=;
});
},
由 GitHub 托管的 App.vue
在智能合约中,我们规定了用户需要支付 0.05 个以太币才能访问繁殖毒蛇的函数,同时,在调用 breedVipers 函数时需要传入两个整数参数, matron (该新出生毒蛇的母亲)和 sire (父亲),所以在上面的代码中我们将两个整数参数传递给函数。这个函数在执行后会返回新出生毒蛇的详细信息,我们需要将其保存到 vipers 数组中。
最后,定义检索自己拥有毒蛇的详细信息的方法,称为 getVipers():
getVipers() {
.isLoading=;
.contractInstance.methods.ownedVipers().call({
from: .account,
}).( {
(let i=; i < receipt.length; i=) {
.contractInstance.methods.getViperDetails(receipt[i]).call({
from: .account,
}).( {
.vipers.push({
id: viper[],
genes: viper[],
matron: viper[],
sire: viper[],
url: vipersMap[viper[]],
});
}).( {
.log(err, );
});
}
.isLoading=;
}).( {
.log(err, );
.isLoading=;
});
},
由 GitHub 托管的 App.vue
想要获取你所拥有毒蛇的详细信息,你可以采用以下两种方法:ownedVipers 方法和 getViperDetails()方法。第一种方法能获取存有我们毒蛇详细信息的数组,而第二方法能获取每条毒蛇的详细信息。在获取每条毒蛇的详细信息后,我们将其保存到 vipers 数组中。
恭喜你,完成了所有的开发工作!
加密毒蛇游戏的玩法示范:花费 0.02 个以太币购买一条新的毒蛇(编号为16 ),然后让编号为15和编号为16的毒蛇繁殖一条毒蛇宝宝(编号为17),恭喜你,你做到了!
写在最后
刚刚我们开发了一个类似于加密猫的 DApp!同时,也学习了如何创建自己的 ERC-721 标准实现,并定义了 DApp 的自定义函数,学习了如何使用 Vue.js 开发项目,并创建了一个简单的 Web 应用程序。
如果你觉得这样太简单了,还想挑战一下自己,这是我的一点建议:
首先,你可以锻炼一下自己的 token 开发能力,在本文中我们直接使用了现成的 ERC-721 token 代码,你可以试着自己从头来开始编写,在这个过程中你可以参考开源智能合约开发框架 OpenZeppelin 的实现或以太坊 ERC-721 token 的标准规范。
或者,你可能试着扩展一下我们已经完成的工作,在这个去中心化应用程序中添加更多的功能,就比如说加入与其他用户进行毒蛇交易的功能,这也是一个不错的主意。
老铁们,学到干货了吗?