使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP

来自:开源中国 翻译频道,英文原文

欢迎来到另一个教程!在本教程中,我们将讨论如何使用 Ethereum、Web3js、VueJS 和 Vuex 创建一个简单的、响应式的去中心化应用程序。您可能需要对 javascript 和 web 应用程序有一些了解才能真正享受本教程。如果您不了解 Vue,不用担心,我们将在实现应用程序时简要地介绍一下基础知识。

我们的应用将会很简单。用户可以在 1 到 10 之间下注以太币。当用户猜对时,他得到了他的奖励 x10(略低于庄家切牌)。

第一部分,我们将讨论项目设置和智能合约的创建。第二部分,我们将介绍 web3js API 和 VueJS/Vuex,第三部分,我们将融会贯通并将应用程序连接到合约中。跟着一起,享受旅程,会很棒的。

我们的应用程序最终看起来像这样:

640


我们的最终应用程序。

前提条件

由于项目比较简单,我们不会使用 truffle。我们将在测试网络上使用 MetaMask 和 Remix(https://remix.ethereum.org)编写和部署智能合约。

我们需要做的第一件事是安装 nodeJS 和 NPM,在您的操作系统上按照步骤进行安装:https://nodejs.org/en/。在终端窗口运行如下命令检查 node 是否正确安装:

接下来,如果您还没安装 metamask,则安装 metamask:https://metamask.io/

我们最后一个条件是 vue-cli,它将帮助我们轻松设置 VueJS 项目:


项目设置

我们将使用 remix 编写和部署智能合约,并通过 metamask 插件部署到 Ropsten 测试网络。在前端应用程序中,需要与合约交互的是合同地址和 ABI ( ABI 定义了如何在机器代码中访问数据结构或计算程序)。

我们的前端将是一个 vue-cli 生成的 vueJS 应用程序。我们也将使用 web3 来与合约通信。遵循以下简单步骤,为客户端应用程序创建 backbone :

  1. 打开一个终端,并将目录更改为您想要创建应用程序的地方。

  2. 在终端窗口输入以下命令来创建我们的项目,并输入“回车”来完成向导:

  1. 现在我们将进入我们的项目文件夹并安装 web3,vuex 和 font-awesome:

我们没有使用 web3 1.0.0 测试版,因为它在写入时与 MetaMask 不兼容。

编写智能合约

在我们毫无头绪地编码之前,我们必须首先分析我们需要的组件:

  1. 我们需要知道合约的所有者并拥有访问权限(为简单起见,我们将不再修改所有者)

  2. 合约的所有者可以销毁合约并提取余额

  3. 用户可以在 1 – 10 之间下注

  4. 在合约创建时,所有者能够设置最低下注金额和庄家上风(为简单起见,创建后不可更改)

第一步和第二步非常简单,我们已经添加了注释,这样就没问题了。 打开 [Remix](http://remix.ethereum.org)开始工作(文章结尾处的要点链接):

首先我们创建合约 Ownable,构造函数 _Ownable()_将在创建时被调用,并将状态变量 ‘owner’ 设置为创建者的地址。 我们还定义了一个访问控制,当我们附加的函数的调用者不是合约所有者时,它将抛出异常。

我们将此功能传递到 Mortal 合约中(Mortal 继承自 Ownabe )。 它有一个函数,允许合约所有者(访问控制)销毁合约并将剩余资金发回给他。

你已经走到这一步了?你做的很好!我们的合约差不多准备好了。

现在我们在步骤3和步骤4将创建 Casino 合约:

首先我们需要 minBet 和 houseEdge,可以在创建合约时设置。通过将参数传递给构造函数 _Casino() 实现。我们将会使构造函数为 payable,这样我们就可以在部署时使用 Ether 预先加载合约。我们也会实现回退过程:

这还不够,所以接下来我们将添加函数用于下注一个数字。此函数将生成一个随机数(此方式不安全!),然后计算并发送赢得的奖励。在你的回退函数下面加上如下部分:

为了在 1 – 10 之间生成一个随机数,我们取当前区块编号,并取当前区块号的模量(除数余数)。这总是会产生 0-9 之间的一个数,所以我们加1,从而得到一个 1 – 10 之间的“随机”数字。

例如:如果我们在新的匿名窗口中使用 javascript VM 在 remix 上部署合约,并在部署后调用 bet 函数,我们将总是得到 2 作为中奖号码。这是因为第一个块是 #1。1 的模是 1,加 1 等于 2。

** 请注意,这并不是真正随机的,因为很容易预测下一个区块号。更多地了解 solidity 的随机性,请查看[https:/ /www.youtube.com/watch?v=3wY5PRliphE].(https://www.youtube.com/watch?v=3wY5PRliphE)

为了计算赢取的奖金,我们只需计算一个乘数:

如果庄家上风为 0,我们的乘数是 10;如果庄家上风是 10%,则乘数是 9。

最后,我们将为所有者添加一个函数,以检查合约的余额,理想情况下,我们还希望为所有者添加一个提取函数,但我们现在就不做了。在你的 bet 函数下面添加以下几行:

**伟大的工作!**合约现在已经准备好进行测试了!

在 remix 上测试我们的合约

在 remix 的右上角单击 run 选项卡。确保将环境设置为 Javascript VM。在 value 字段中输入 20 并从下拉列表中选择 Ether而不是 Wei 。这将在部署时使用 20 Eth 预加载合约。下面,在 create 按钮旁边输入我们的构造器参数 minBet 和 houseEdge (比如,10000 wei 和 10% 的庄家上风)。

做完它应该是这样的:

641


在点击“创建”之前,它应该是这样的。

现在单击 create 按钮,合约实例应该出现在屏幕的右下角。将会有四个函数可见,点击 getContractBalance() 检查一切是否正常,应该返回 20000000000000000000,这是我们发送的 20 ether 转换成 wei 得到的。你也会在右上角的账户旁边看到你的余额,现在将略低于80 ether。

642


点击“创建”合约后,余额应该是 20*1e18 wei。

好了!一切运行正常。就像前面提到的,当使用 javascript VM 时,第一个块总是 1,所以第一个中奖号码总是 2。我们可以通过在 value 字段中输入 1 ether 来测试,并将 2 作为参数传递给 bet。

当点击 bet 时,我们应该看到余额再次增加,在控制台点击详情,并滚动到“日志”。我们应该看到一个我们已经赢了的事件:

643


我们赢了 9 以太币!

在下一节中,我们将在 Ropsten 测试网络上部署我们的合约,并获取合约地址和 ABI ,以便在我们的客户端应用程序中使用。

欢迎回到这个很牛的教程系列的第2部分,在教程中我们亲手构建我们的第一个分布式应用程序。 在第二部分中,我们将介绍VueJS和Vuex的核心概念,并引入web3js以与metamask进行交互。

    正事: VueJS

    VueJS是一个用于构建UI的javascript框架。乍一看,它看起来与经典的moustache模板类似,但在底层为了使Vue变得响应式发生了很多事情。

    这将是一个非常基础的Vue应用程序的结构。数据对象中的消息属性将渲染到id为’app’的元素的屏幕区域,当我们更改此消息时,它将在屏幕上更新并无需刷新。你可以在这个jsfiddle中查看它(须打开自动运行):https://jsfiddle.net/tn1mfxwr/2/ 。

    VueJS的另一个重要特性是组件。组件是小规模的、可重用的和自包含的代码片断。本质上,Web应用程序可以抽象为一颗更小的组件树。当我们开始编写我们的前端应用程序时,这将会变得更加清晰。

    649


    将网页抽象成组件的示例。该网页由三部分组成。其中两个组件具有子组件。

    状态的联合:Vuex

    我们将使用Vuex来管理我们的应用程序的状态。与redux类似,Vuex实现了一个仓库,作为我们app相关数据的“唯一真实数据源”。Vuex允许我们以可预测的方式操作和提供我们的应用程序所使用的数据。

    它的工作方式非常简单。组件在渲染时是需要数据的,它会派发一个动作(action)来获取它所需要的数据。获取数据的API调用发生在action的async中。 一旦数据被提取完成,action就会将这些数据提交给mutation。 之后mutation会改变我们仓库中的状态。当该组件所使用的数据在仓库中发生更改时,它将重新渲染。

    648

    Vuex的状态管理模式

    在继续之前…

    在第一部分中,我们使用 vue-cli 生成了 Vue 应用程序,同时还安装了需要的依赖项。 如果你还没有完成这一部分,请点击的顶部的链接。

    如果你正确地完成了一切,目录结构应该如下所示:

    647


    新生成的 vue 应用

    注意: 如果你打算从这里复制粘贴代码,添加/src/ 到 .eslintignore 文件中,避免缩进错误。

    你可以在终端输入‘npm start’来启动这个App。这个App会包含默认的vue应用,因此我们可以将它放出来。
    注意:我们正在使用vue Router尽管只有一个route,我们不需要它,但是因为它太简单了,我认为将它放到教程里挺好的。
    提示:在.vue文件将你的atom语法(例如 bottom right)添加到HTML。
    现在来清理一下这个新项目:

    • 在app.vue中删除img-tag,同时删除在style-tags之间的所有东西。

    • 删除components/HelloWorld.vue,新建两个文件分别名为casino-dapp.vue(我们的主模块)和hello-metamask.vue(会包括我们的metamask数据)

    • 在我们的新文件hello-metamask.vue中粘贴以下代码,这些代码现在只是在一个p-tag中显示文字‘Hello’。

    • 通过引入文件,我们现在要加载hello-metamask模块到我们的主模块casino-dapp模块中,然后在我们的vue实例中关联这个模块,因此我们可以将它作为一个tag加到我们的模板中。将下面代码粘贴到casino-dapp.vue文件中:

    • 现在如果你打开了router/index.js,你就会看到我们根目录下只有一个route,它仍然指向我们已经删掉的HelloWorld.vue模块。我们需要将它改为指向我们的casino-dapp.vue模块。

    关于Vue Router:你可以添加其他的路径以及绑定模块,当你访问定义的路径他们会进行渲染。因为我们App.vue文件中有route-view tag,正确的模块会被渲染。

    • 在src中创建一个名为util的新文件夹。在这个文件夹中创建另一个文件夹名为constants。创建一个名为network.js的新文件,然后将下面代码粘贴进去。当我们代码在清理的时候,这会让我们显示Ethereum 网络名称而不是它的id。

    646


    • 最后但同样重要的是(现在其实并不重要),在src中创建一个名为store的新文件夹。在下一章我们再来谈论这个。

    如果你在终端运行‘npm start’,然后在浏览器访问localhost:8080,你应该就能在屏幕上看到‘Hello’。如果是这样的,你就可以准备继续了。

    设置我们的Vuex store

    在这一章我们要设置我们的store。现在开始在我们的全新的store目录(上一章的最后一部分)创建两个文件:index.js和state.js;我们由state.js开始,这个文件将会作为一个新的我们检索数据的代表。645

    好的,现在我们开始在index.js中配置我们的store。我们要引入vuex库供vueJS使用。我们还要引入state,然后也加入我们的store中。

    最后一步来编辑main.js来包含我们的store:

    做得不错,完成了这么多的配置,给自己一点表扬。现在我们准备好了开始通过web3 API获取我们的metamask数据,然后让他为我们的应用服务。就要实现了!

    从 Web3 和 Metamask 开始

    就像之前提到的,为了将数据获取到我们的Vue app,我们需要发送一个action来做异步API调用。我们使用promises将一些调用连接到一起,然后将其抽象成一个文件。因此在util文件夹中创建一个名为getWeb.js的新文件。将下面的代码粘贴到里面,这些代码包含了你要遵循的相当多的注解。我们在代码块下面也会提到。

    首先要注意的是我们使用promises来连接回调,如果你不知道promises,查看相关链接。下一步我们检查用户是否有Metamask(或者 Mist)在运行。Metamase注入他自己的web3的实例,我们因此确认window.web3(被注入的实例)已经定义了。

    如果没有定义的话,我们要使用Metamask创建一个web3实例作为当前provider,因此我们不依赖被注入的实例的版本。我们将我们新创建的实例传给下一个promises,在这里我们做几个API调用:

    • web3.version.getNetwork() 会返回我们连接的网络ID。

    • web3.eth.coinbase() 返回我们节点属于的地址,当使用Metamask的时候这会是我们选择的账户。

    • web3.eth.getBalance(

      ) 返回我们作为参数传过去的地址的balance。

    还记得我们说的在我们的Vuex store中需要在一个action产生异步API调用吗?我们现在会把它hook出来,之后从我们的组件dispatch出去。在store/index.js中我们会引入我们的getWeb3.js文件,调用它然后将它commit给一个mutation,然后在我们的store中保存。
    在你的引用语句中添加

    644


    然后在action对象(在你的sotre中)中我们会调用getWeb3然后commit结果。我们在逻辑中添加了大量的console.logs,因此我们可以看到进程的步骤,这会让我们对完全的dispatch-action-commit-mutation-statechange流程了解的更加透彻。

    643


    现在开始创建我们的mutation,它会在我们的store中将数据保存到state。通过访问第二个参数,我们可以在mutation中访问传进commit的数据。在mutations对象添加下面的函数。

    642


    不错!现在还要做的就剩下从我们的组件将action dispatch给实际检索数据,然后把它渲染到我们的应用。为了dispatch我们的actions,我们要利用Vue的生命周期hooks。

    在我们的例子中,我们需要从main casino-dapp组件dispatch 我们的action,在组件被创建之前。因此在components/casino-dapp.vue 的name属性之后添加下面的函数:

    641


    好了,现在我们要从hello-metamask组件渲染这些数据,我们所有的账户数据都会在这个组件中被渲染。为了从我们的store获取数据,我们需要将一个getter函数传入computed。然后我们可以在我们的模板中使用curly-braces关联数据。

    不错,现在都可以工作了。在你的终端使用‘npm start’启动项目,然后访问localhost:8080。我们现在应该可以看到我们的metamask数据。当我们打开控制台的时候,我们应该看到在state管理模式下控制台log输出的信息,就像是在文章的vuex部分描述的一样。

    640


    如果你能做到这一点,一切都很好,那么就认真的做下去。目前这块是这个系列最难的部分。在下一部分,我们将学习如何轮询Metamask的更改(如更换账户)和将我们在第一部分写的智能合约连接到我们的应用。

    推荐↓↓↓
    区块链技术学习
    上一篇:长文解惑:区块链与比特币 下一篇:一文读懂区块链整体架构及应用案例分析