脚本宝典收集整理的这篇文章主要介绍了

以太坊开发实战学习-Web3.js(十)

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <blockquote><p>接上篇 <a href="https://segmentfault.com/a/1190000015310963#articleHeader18">Web3.js</a>,这节课继续学习Web3.js 的相关知识。</p></blockquote> <h2 id="articleHeader0">一、发送事务</h2> <p>这下我们的界面能检测用户的 MetaMask 账户,并自动在首页显示它们的僵尸大军了,有没有很棒?</p> <p>现在我们来看看用 <code>send</code> 函数来修改我们智能合约里面的数据。</p> <p>相对 <code>c<a href="http://www.js-code.com/tag/all" title="all" target="_blank">all</a></code> 函数,<code>send</code> 函数有如下主要区别:</p> <ul> <li>1、<code>send</code> 一个事务需要一个 <code>from</code> 地址来表明谁在调用这个函数(也就是你 Solidity 代码里的 <code>msg.sender</code> )。 我们需要这是我们 DApp 的用户,这样一来 MetaMask 才会弹出提示让他们对事务签名。</li> <li>2、send 一个事务将花费 gas</li> <li>3、在用户 <code>send</code> <strong>一个事务到该事务对区块链产生实际影响之间有一个不可忽略的延迟</strong>。这是因为我们必须等待事务被包含进一个区块里,以太坊上一个区块的时间平均下来是15秒左右。如果当前在以太坊上有大量挂起事务或者用户发送了过低的 <code>gas</code> 价格,我们的事务可能需要等待数个区块才能被包含进去,往往可能花费数分钟。</li> </ul> <p>所以在我们的代码中我们需要编写逻辑来处理这部分异步特性。</p> <h3 id="articleHeader1">生成一个僵尸</h3> <p>我们来看一个合约中一个新用户将要调用的第一个函数: <code>createRan<a href="http://www.js-code.com/tag/do" title="do" target="_blank">do</a>mZombie</code>.</p> <p>作为复习,这里是合约中的 <code>Solidity</code> 代码:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="function createRandomZombie(string _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; _createZombie(_name, randDna); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code><span class="hljs-function"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/function" title="浏览关于“function”的文章" target="_blank" class="tag_link">function</a></span> <span class="hljs-title">createRan<a href="http://www.js-code.com/tag/do" title="浏览关于“do”的文章" target="_blank" class="tag_link">do</a>mZombie</span>(<span class="hljs-params"><span class="hljs-built_in">str<a href="http://www.js-code.com/tag/in" title="浏览关于“in”的文章" target="_blank" class="tag_link">in</a>g</span> _<a href="http://www.js-code.com/tag/name" title="浏览关于“name”的文章" target="_blank" class="tag_link">name</a></span>) <span class="hljs-title"><a href="http://www.js-code.com/tag/public" title="浏览关于“public”的文章" target="_blank" class="tag_link">public</a></span> </span>{ <span class="hljs-built_in">require</span>(ownerZombieCount[msg.sender] == <span class="hljs-number">0</span>); u<a href="http://www.js-code.com/tag/int" title="浏览关于“int”的文章" target="_blank" class="tag_link">int</a> randDna = _generateRandomDna(_name); randDna = randDna - randDna % <span class="hljs-number">100</span>; _createZombie(_name, randDna); }</code></pre> <p>这是如何在用 MetaMask 在 Web3.js 中调用这个函数的示例:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="function createRandomZombie(name) { // 这将需要一段时间,所以在界面中告诉用户这一点 // 事务被发送出去了 $(&quot;#txStatus&quot;).text(&quot;正在区块链上创建僵尸,这将需要一会儿...&quot;); // 把事务发送到我们的合约: return CryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;成功生成了 &quot; + name + &quot;!&quot;); // 事务被区块链接受了,重新渲染界面 getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { // 告诉用户合约失败了 $(&quot;#txStatus&quot;).text(error); }); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createRandomZombie</span>(<span class="hljs-params">name</span>) </span>{ <span class="hljs-comment">// 这将需要一段时间,所以在界面中告诉用户这一点</span> <span class="hljs-comment">// 事务被发送出去了</span> $(<span class="hljs-string">"#txStatus"</span>).<a href="http://www.js-code.com/tag/text" title="浏览关于“text”的文章" target="_blank" class="tag_link">text</a>(<span class="hljs-string">"正在区块链上创建僵尸,这将需要一会儿..."</span>); <span class="hljs-comment">// 把事务发送到我们的合约:</span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/return" title="浏览关于“return”的文章" target="_blank" class="tag_link">return</a></span> CryptoZombies.methods.createRandomZombie(name) .send({ <span class="hljs-attr">from</span>: userAccount }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"成功生成了 "</span> + name + <span class="hljs-string">"!"</span>); <span class="hljs-comment">// 事务被区块链接受了,重新渲染界面</span> getZombiesByOwner(userAccount).then(displayZombies); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ <span class="hljs-comment">// 告诉用户合约失败了</span> $(<span class="hljs-string">"#txStatus"</span>).text(error); }); }</code></pre> <p>我们的函数 <code>send</code> 一个事务到我们的 <code>Web3</code> 提供者,然后链式添加一些事件监听:</p> <ul> <li> <code>receipt</code> 将在合约被包含进以太坊区块上以后被触发,这意味着僵尸被创建并保存进我们的合约了。</li> <li> <code>error</code> 将在事务未被成功包含进区块后触发,比如用户未支付足够的 gas。我们需要在界面中通知用户事务失败以便他们可以再次尝试。</li> </ul> <blockquote><p>注意:你可以在调用 <code>send</code> 时选择指定 <code>gas</code> 和 <code>gasPrice</code>, 例如: <code>.send({ from: userAccount, gas: 3000000 })</code>。如果你不指定,<code>MetaMask</code> 将让用户自己选择数值。</p></blockquote> <h4>实战演练</h4> <p>我们添加了一个<a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a>, 指定 ID 为 <code>txStatus</code> — 这样我们可以通过更新这个 <code><a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a></code> 来通知用户事务的状态。</p> <ul> <li>1、在 <code>displayZombies</code>下面, 复制粘贴上面 <code>createRan<a href="http://www.js-code.com/tag/do" title="do" target="_blank">do</a>mZombie </code>的代码。</li> <li>2、我们来实现另外一个函数 feedOnKitty:</li> <li>调用 <code>feedOnKitty</code> 的逻辑几乎一样 — 我们将发送一个事务来调用这个函数,并且成功的事务会为我们创建一个僵尸,所以我们希望在成功后重新绘制界面。</li> <li>在 <code>createRandomZombie</code> 下面复制粘贴它的代码,改动这些地方:</li> <li>a) 给其命名为 feedOnKitty, 它将接收两个参数 zombieId 和 kittyId</li> <li>b) #txStatus 的文本内容将更新为: "正在吃猫咪,这将需要一会儿..."</li> <li>c) 让其调用我们合约里面的 feedOnKitty 函数并传入相同的参数</li> <li>d) #txStatus 里面的的成功信息应该是 "吃了一只猫咪并生成了一只新僵尸!"</li> </ul> <p><code><a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>dex.html</code></p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<!DOCTYPE html><br /> <html lang=&quot;en&quot;><br /> <head><br /> <meta charset=&quot;UTF-8&quot;><br /> <title>CryptoZombies front-end</title><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;web3.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;cryptozombies_abi.js&quot;></script><br /> </head><br /> <body></p> <div id=&quot;txStatus&quot;></div> <div id=&quot;zombies&quot;></div> <p> <script> <a href="http://www.js-code.com/tag/var" title="var" target="_blank">var</a> <a href="http://www.js-code.com/tag/crypto" title="crypto" target="_blank">crypto</a>Zombies; <a href="http://www.js-code.com/tag/var" title="var" target="_blank">var</a> userAccount;</p> <p> <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a> startApp() { <a href="http://www.js-code.com/tag/var" title="浏览关于“var”的文章" target="_blank" class="tag_link">var</a> <a href="http://www.js-code.com/tag/crypto" title="crypto" target="_blank">crypto</a>ZombiesAddress = &quot;YOUR_CONTRACT_ADDRESS&quot;; <a href="http://www.js-code.com/tag/crypto" title="浏览关于“crypto”的文章" target="_blank" class="tag_link">crypto</a>Zombies = <a href="http://www.js-code.com/tag/new" title="new" target="_blank">new</a> web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress);</p> <p> var accountInterval = <a href="http://www.js-code.com/tag/setInterval" title="setInterval" target="_blank">setInterval</a>(<a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a>() { // Check <a href="http://www.js-code.com/tag/if" title="if" target="_blank">if</a> account has changed <a href="http://www.js-code.com/tag/if" title="if" target="_blank">if</a> (web3.eth.accounts[0] !== userAccount) { userAccount = web3.eth.accounts[0]; // C<a href="http://www.js-code.com/tag/all" title="all" target="_blank">all</a> a <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a> to update the UI with the <a href="http://www.js-code.com/tag/new" title="new" target="_blank">new</a> account getZombiesByOwner(userAccount) .then(displayZombies); } }, 100); }</p> <p> <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a> displayZombies(ids) { $(&quot;#zombies&quot;).empty(); <a href="http://www.js-code.com/tag/for" title="for" target="_blank">for</a> (id of ids) { // Look up zombie details from our contract. Returns a `zombie` object getZombieDetails(id) .then(function(zombie) { // Us<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>g ES6's &quot;template literals&quot; to inject variables <a href="http://www.js-code.com/tag/int" title="int" target="_blank">int</a>o the <a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a>. // Append each one to our #zombies <a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a> $(&quot;#zombies&quot;).append(`</p> <div class=&quot;zombie&quot;> <ul> <li>Name: ${zombie.<a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>}</li> <li>DNA: ${zombie.dna}</li> <li>Level: ${zombie.level}</li> <li>Wins: ${zombie.winCount}</li> <li>Losses: ${zombie.lossCount}</li> <li>Ready Time: ${zombie.readyTime}</li> </ul></div> <p>`); }); } }</p> <p> // Start here function createRandomZombie(<a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>) { // 这将需要一段时间,所以在界面中告诉用户这一点 // 事务被发送出去了 $(&quot;#txStatus&quot;).<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>(&quot;正在区块链上创建僵尸,这将需要一会儿...&quot;); // 把事务发送到我们的合约: <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> CryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;成功生成了 &quot; + name + &quot;!&quot;); // 事务被区块链接受了,重新渲染界面 getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { // 告诉用户合约失败了 $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function feedOnKitty(zombieId, kittyId) { // 这将需要一段时间,所以在界面中告诉用户这一点 // 事务被发送出去了 $(&quot;#txStatus&quot;).text(&quot;正在吃猫咪,这将需要一会儿...&quot;); // 把事务发送到我们的合约: <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;吃了一只猫咪并生成了一只新僵尸!&quot;); // 事务被区块链接受了,重新渲染界面 getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { // 告诉用户合约失败了 $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function getZombieDetails(id) { <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> cryptoZombies.methods.zombies(id).c<a href="http://www.js-code.com/tag/all" title="浏览关于“all”的文章" target="_blank" class="tag_link">all</a>() }</p> <p> function zombieToOwner(id) { <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> cryptoZombies.methods.zombieToOwner(id).call() }</p> <p> function getZombiesByOwner(owner) { return cryptoZombies.methods.getZombiesByOwner(owner).call() }</p> <p> <a href="http://www.js-code.com/tag/window" title="window" target="_blank">window</a>.addEventListener('load', function() {</p> <p> // Checking <a href="http://www.js-code.com/tag/if" title="浏览关于“if”的文章" target="_blank" class="tag_link">if</a> Web3 has been injected by the browser (Mist/MetaMask) if (<a href="http://www.js-code.com/tag/typeof" title="typeof" target="_blank">typeof</a> web3 !== '<a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a>') { // Use Mist/MetaMask's provider web3js = <a href="http://www.js-code.com/tag/new" title="浏览关于“new”的文章" target="_blank" class="tag_link">new</a> Web3(web3.currentProvider); } <a href="http://www.js-code.com/tag/else" title="else" target="_blank">else</a> { // Handle the <a href="http://www.js-code.com/tag/case" title="case" target="_blank">case</a> where the user doesn't have Metamask installed // Probably show them a message <a href="http://www.js-code.com/tag/prompt" title="prompt" target="_blank">prompt</a>ing them to install Metamask }</p> <p> // Now you can start your app &amp; access web3 freely: startApp()</p> <p> }) </script><br /> </body><br /> </html><br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-meta">&lt;!DOCTYPE html&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr"><a href="http://www.js-code.com/tag/char" title="浏览关于“char”的文章" target="_blank" class="tag_link">char</a>set</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CryptoZombies front-end<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"<a href="http://www.js-code.com/tag/java" title="浏览关于“java”的文章" target="_blank" class="tag_link">java</a>script"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"javascript"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"web3.min.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"javascript"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"cryptozombies_abi.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"txStatus"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"zombies"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">var</span> cryptoZombies; <span class="hljs-keyword">var</span> userAccount; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startApp</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> cryptoZombiesAddress = <span class="hljs-string">"YOUR_CONTRACT_ADDRESS"</span>; cryptoZombies = <span class="hljs-keyword">new</span> web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); <span class="hljs-keyword">var</span> accountInterval = <a href="http://www.js-code.com/tag/setInterval" title="浏览关于“setInterval”的文章" target="_blank" class="tag_link">setInterval</a>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// Check if account has changed</span> <span class="hljs-keyword">if</span> (web3.eth.accounts[<span class="hljs-number">0</span>] !== userAccount) { userAccount = web3.eth.accounts[<span class="hljs-number">0</span>]; <span class="hljs-comment">// Call a function to update the UI with the new account</span> getZombiesByOwner(userAccount) .then(displayZombies); } }, <span class="hljs-number">100</span>); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayZombies</span>(<span class="hljs-params">ids</span>) </span>{ $(<span class="hljs-string">"#zombies"</span>).empty(); <span class="hljs-keyword"><a href="http://www.js-code.com/tag/for" title="浏览关于“for”的文章" target="_blank" class="tag_link">for</a></span> (id <span class="hljs-keyword">of</span> ids) { <span class="hljs-comment">// Look up zombie details from our contract. Returns a `zombie` object</span> getZombieDetails(id) .then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">zombie</span>) </span>{ <span class="hljs-comment">// Using ES6's "template literals" to inject variables into the <a href="http://www.js-code.com/tag/html" title="浏览关于“HTML”的文章" target="_blank" class="tag_link">HTML</a>.</span> <span class="hljs-comment">// Append each one to our #zombies div</span> $(<span class="hljs-string">"#zombies"</span>).append(<span class="hljs-string">`&lt;div class="zombie"&gt; &lt;ul&gt; &lt;li&gt;Name: <span class="hljs-subst">${zombie.name}</span>&lt;/li&gt; &lt;li&gt;DNA: <span class="hljs-subst">${zombie.dna}</span>&lt;/li&gt; &lt;li&gt;Level: <span class="hljs-subst">${zombie.level}</span>&lt;/li&gt; &lt;li&gt;Wins: <span class="hljs-subst">${zombie.winCount}</span>&lt;/li&gt; &lt;li&gt;Losses: <span class="hljs-subst">${zombie.lossCount}</span>&lt;/li&gt; &lt;li&gt;Ready Time: <span class="hljs-subst">${zombie.readyTime}</span>&lt;/li&gt; &lt;/ul&gt; &lt;/div&gt;`</span>); }); } } <span class="hljs-comment">// Start here</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createRandomZombie</span>(<span class="hljs-params">name</span>) </span>{ <span class="hljs-comment">// 这将需要一段时间,所以在界面中告诉用户这一点</span> <span class="hljs-comment">// 事务被发送出去了</span> $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"正在区块链上创建僵尸,这将需要一会儿..."</span>); <span class="hljs-comment">// 把事务发送到我们的合约:</span> <span class="hljs-keyword">return</span> CryptoZombies.methods.createRandomZombie(name) .send({ <span class="hljs-attr">from</span>: userAccount }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"成功生成了 "</span> + name + <span class="hljs-string">"!"</span>); <span class="hljs-comment">// 事务被区块链接受了,重新渲染界面</span> getZombiesByOwner(userAccount).then(displayZombies); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ <span class="hljs-comment">// 告诉用户合约失败了</span> $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">feedOnKitty</span>(<span class="hljs-params">zombieId, kittyId</span>) </span>{ <span class="hljs-comment">// 这将需要一段时间,所以在界面中告诉用户这一点</span> <span class="hljs-comment">// 事务被发送出去了</span> $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"正在吃猫咪,这将需要一会儿..."</span>); <span class="hljs-comment">// 把事务发送到我们的合约:</span> <span class="hljs-keyword">return</span> CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ <span class="hljs-attr">from</span>: userAccount }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"吃了一只猫咪并生成了一只新僵尸!"</span>); <span class="hljs-comment">// 事务被区块链接受了,重新渲染界面</span> getZombiesByOwner(userAccount).then(displayZombies); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ <span class="hljs-comment">// 告诉用户合约失败了</span> $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZombieDetails</span>(<span class="hljs-params">id</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.zombies(id).call() } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">zombieToOwner</span>(<span class="hljs-params">id</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.zombieToOwner(id).call() } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZombiesByOwner</span>(<span class="hljs-params">owner</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.getZombiesByOwner(owner).call() } <span class="hljs-built_in"><a href="http://www.js-code.com/tag/window" title="浏览关于“window”的文章" target="_blank" class="tag_link">window</a></span>.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// Checking if Web3 has been injected by the browser (Mist/MetaMask)</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword"><a href="http://www.js-code.com/tag/typeof" title="浏览关于“typeof”的文章" target="_blank" class="tag_link">typeof</a></span> web3 !== <span class="hljs-string">'<a href="http://www.js-code.com/tag/undefined" title="浏览关于“undefined”的文章" target="_blank" class="tag_link">undefined</a>'</span>) { <span class="hljs-comment">// Use Mist/MetaMask's provider</span> web3js = <span class="hljs-keyword">new</span> Web3(web3.currentProvider); } <span class="hljs-keyword"><a href="http://www.js-code.com/tag/else" title="浏览关于“else”的文章" target="_blank" class="tag_link">else</a></span> { <span class="hljs-comment">// Handle the <a href="http://www.js-code.com/tag/case" title="浏览关于“case”的文章" target="_blank" class="tag_link">case</a> where the user doesn't have Metamask installed</span> <span class="hljs-comment">// Probably show them a message <a href="http://www.js-code.com/tag/prompt" title="浏览关于“prompt”的文章" target="_blank" class="tag_link">prompt</a>ing them to install Metamask</span> } <span class="hljs-comment">// Now you can start your app &amp; access web3 freely:</span> startApp() }) </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span> </code></pre> <h2 id="articleHeader2">二、调用Payable函数</h2> <p><code>attack</code>, <code>changeName</code>, 以及 <code>changeDna</code> 的逻辑将非常雷同,所以本课将不会花时间在上面。</p> <blockquote><p>实际上,在调用这些函数的时候已经有了非常多的重复逻辑。所以最好是重构代码把相同的代码写成一个函数。(并对txStatus使用模板系统——我们已经看到用类似 <code><a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>.js</code> 类的框架是多么整洁)</p></blockquote> <p>我们来看看另外一种 Web3.js 中需要特殊对待的函数 — <code>payable</code> 函数。</p> <h3 id="articleHeader3">升级</h3> <p>回忆一下在 <code>ZombieHelper</code> 里面,我们添加了一个 <code>payable</code> 函数,用户可以用来升级:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); zombies[_zombieId].level++; }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs fortran"><code><span class="hljs-function"><span class="hljs-keyword">function</span></span> levelUp(uint _zombieId) <span class="hljs-keyword">external</span> payable { require(msg.<span class="hljs-keyword">value</span> == levelUpFee); zombies[_zombieId].level++; }</code></pre> <p>和函数一起发送以太非常简单,只有一点需要注意: 我们需要指定发送多少 <code>wei</code>,而不是以太。</p> <h3 id="articleHeader4">啥是 Wei?</h3> <p>一个 <code>wei</code> 是以太的最小单位 — <code>1 ether</code> 等于 <code>10^18 wei</code></p> <p>太多0要数了,不过幸运的是 Web3.js 有一个转换工具来帮我们做这件事:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// 把 1 ETH 转换成 Wei web3js.utils.toWei(&quot;1&quot;, &quot;ether&quot;);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs objectivec"><code><span class="hljs-comment">// 把 1 ETH 转换成 Wei</span> web3js.utils.toWei(<span class="hljs-string">"1"</span>, <span class="hljs-string">"ether"</span>);</code></pre> <p>在我们的 DApp 里, 我们设置了 <code>levelUpFee = 0.001 ether</code>,所以调用 <code>levelUp</code> 方法的时候,我们可以让用户用以下的代码同时发送 <code>0.001</code> 以太:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="CryptoZombies.methods.levelUp(zombieId) .send({ from: userAccount, value: web3js.utils.toWei(&quot;0.001&quot;,&quot;ether&quot;) })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs css"><code><span class="hljs-selector-tag">CryptoZombies</span><span class="hljs-selector-class">.methods</span><span class="hljs-selector-class">.levelUp</span>(<span class="hljs-selector-tag">zombieId</span>) <span class="hljs-selector-class">.send</span>({ <span class="hljs-attribute">from</span>: userAccount, value: web3js.utils.<span class="hljs-built_in">toWei</span>(<span class="hljs-string">"0.001"</span>,<span class="hljs-string">"ether"</span>) })</code></pre> <h4>实战演练</h4> <p>在 <code>feedOnKitty</code> 下面添加一个 <code>levelUp</code> 方法。代码和 <code>feedOnKitty</code> 将非常相似。不过:</p> <ul> <li>1、函数将接收一个参数, <code>zombieId</code> </li> <li>2、在发送事务之前,<code>txStatus</code> 的文本应该是 "正在升级您的僵尸..."</li> <li>3、当它调用合约里的levelUp时,它应该发送"0.001" ETH,并用 <code>toWei</code> 转换,如同上面例子里那样。</li> <li>4、成功之后应该显示 "不得了了!僵尸成功升级啦!"</li> <li>5、我们 不 需要在调用 <code>getZombiesByOwner</code> 后重新绘制界面 — 因为在这里我们只是修改了僵尸的级别而已。</li> </ul> <p><code>index.html</code></p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-text="<!DOCTYPE html><br /> <html lang=&quot;en&quot;><br /> <head><br /> <meta charset=&quot;UTF-8&quot;><br /> <title>CryptoZombies front-end</title><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;web3.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;cryptozombies_abi.js&quot;></script><br /> </head><br /> <body></p> <div id=&quot;txStatus&quot;></div> <div id=&quot;zombies&quot;></div> <p> <script> var cryptoZombies; var userAccount;</p> <p> function startApp() { var cryptoZombiesAddress = &quot;YOUR_CONTRACT_ADDRESS&quot;; cryptoZombies = new web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress);</p> <p> var accountInterval = <a href="http://www.js-code.com/tag/setInterval" title="setInterval" target="_blank">setInterval</a>(function() { // Check if account has changed if (web3.eth.accounts[0] !== userAccount) { userAccount = web3.eth.accounts[0]; // Call a function to update the UI with the new account getZombiesByOwner(userAccount) .then(displayZombies); } }, 100); }</p> <p> function displayZombies(ids) { $(&quot;#zombies&quot;).empty(); <a href="http://www.js-code.com/tag/for" title="for" target="_blank">for</a> (id of ids) { // Look up zombie details from our contract. Returns a `zombie` object getZombieDetails(id) .then(function(zombie) { // Using ES6's &quot;template literals&quot; to inject variables <a href="http://www.js-code.com/tag/int" title="int" target="_blank">int</a>o the <a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a>. // Append each one to our #zombies div $(&quot;#zombies&quot;).append(`</p> <div class=&quot;zombie&quot;> <ul> <li>Name: ${zombie.name}</li> <li>DNA: ${zombie.dna}</li> <li>Level: ${zombie.level}</li> <li>Wins: ${zombie.winCount}</li> <li>Losses: ${zombie.lossCount}</li> <li>Ready Time: ${zombie.readyTime}</li> </ul></div> <p>`); }); } }</p> <p> function createRandomZombie(name) { // This is going to take a <a href="http://www.js-code.com/tag/while" title="while" target="_blank">while</a>, so update the UI to <a href="http://www.js-code.com/tag/let" title="let" target="_blank">let</a> the user know // the transaction has been sent $(&quot;#txStatus&quot;).text(&quot;Creating new zombie on the blockchain. This may take a <a href="http://www.js-code.com/tag/while" title="while" target="_blank">while</a>...&quot;); // Send the tx to our contract: return CryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;Successfully created &quot; + name + &quot;!&quot;); // Transaction was accepted into the blockchain, <a href="http://www.js-code.com/tag/let" title="let" target="_blank">let</a>'s redraw the UI getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { // Do something to <a href="http://www.js-code.com/tag/alert" title="alert" target="_blank">alert</a> the user their transaction has failed $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function feedOnKitty(zombieId, kittyId) { $(&quot;#txStatus&quot;).text(&quot;Eating a kitty. This may take a <a href="http://www.js-code.com/tag/while" title="浏览关于“while”的文章" target="_blank" class="tag_link">while</a>...&quot;); return CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;Ate a kitty and spawned a new Zombie!&quot;); getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { $(&quot;#txStatus&quot;).text(error); }); }</p> <p> // Start here function levelUp(zombieId) { $(&quot;#txStatus&quot;).text(&quot;正在升级您的僵尸...&quot;); return CryptoZombies.methods.levelUp(zombieId) .send({ from: userAccount, value: web3js.utils.toWei(&quot;0.001&quot;, &quot;ether&quot;) }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;不得了了!僵尸成功升级啦!&quot;); }) .on(&quot;error&quot;, function(error) { $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function getZombieDetails(id) { return cryptoZombies.methods.zombies(id).call() }</p> <p> function zombieToOwner(id) { return cryptoZombies.methods.zombieToOwner(id).call() }</p> <p> function getZombiesByOwner(owner) { return cryptoZombies.methods.getZombiesByOwner(owner).call() }</p> <p> <a href="http://www.js-code.com/tag/window" title="window" target="_blank">window</a>.addEventListener('load', function() {</p> <p> // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (<a href="http://www.js-code.com/tag/typeof" title="typeof" target="_blank">typeof</a> web3 !== '<a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a>') { // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } <a href="http://www.js-code.com/tag/else" title="else" target="_blank">else</a> { // Handle the <a href="http://www.js-code.com/tag/case" title="case" target="_blank">case</a> where the user doesn't have Metamask installed // Probably show them a message <a href="http://www.js-code.com/tag/prompt" title="prompt" target="_blank">prompt</a>ing them to install Metamask }</p> <p> // Now you can start your app &amp; access web3 freely: startApp()</p> <p> }) </script><br /> </body><br /> </html></p> <p>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-meta">&lt;!DOCTYPE html&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CryptoZombies front-end<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"javascript"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"javascript"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"web3.min.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">language</span>=<span class="hljs-string">"javascript"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"cryptozombies_abi.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"txStatus"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"zombies"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">var</span> cryptoZombies; <span class="hljs-keyword">var</span> userAccount; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startApp</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> cryptoZombiesAddress = <span class="hljs-string">"YOUR_CONTRACT_ADDRESS"</span>; cryptoZombies = <span class="hljs-keyword">new</span> web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); <span class="hljs-keyword">var</span> accountInterval = setInterval(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// Check if account has changed</span> <span class="hljs-keyword">if</span> (web3.eth.accounts[<span class="hljs-number">0</span>] !== userAccount) { userAccount = web3.eth.accounts[<span class="hljs-number">0</span>]; <span class="hljs-comment">// Call a function to update the UI with the new account</span> getZombiesByOwner(userAccount) .then(displayZombies); } }, <span class="hljs-number">100</span>); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayZombies</span>(<span class="hljs-params">ids</span>) </span>{ $(<span class="hljs-string">"#zombies"</span>).empty(); <span class="hljs-keyword">for</span> (id <span class="hljs-keyword">of</span> ids) { <span class="hljs-comment">// Look up zombie details from our contract. Returns a `zombie` object</span> getZombieDetails(id) .then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">zombie</span>) </span>{ <span class="hljs-comment">// Using ES6's "template literals" to inject variables into the HTML.</span> <span class="hljs-comment">// Append each one to our #zombies div</span> $(<span class="hljs-string">"#zombies"</span>).append(<span class="hljs-string">`&lt;div class="zombie"&gt; &lt;ul&gt; &lt;li&gt;Name: <span class="hljs-subst">${zombie.name}</span>&lt;/li&gt; &lt;li&gt;DNA: <span class="hljs-subst">${zombie.dna}</span>&lt;/li&gt; &lt;li&gt;Level: <span class="hljs-subst">${zombie.level}</span>&lt;/li&gt; &lt;li&gt;Wins: <span class="hljs-subst">${zombie.winCount}</span>&lt;/li&gt; &lt;li&gt;Losses: <span class="hljs-subst">${zombie.lossCount}</span>&lt;/li&gt; &lt;li&gt;Ready Time: <span class="hljs-subst">${zombie.readyTime}</span>&lt;/li&gt; &lt;/ul&gt; &lt;/div&gt;`</span>); }); } } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createRandomZombie</span>(<span class="hljs-params">name</span>) </span>{ <span class="hljs-comment">// This is going to take a while, so update the UI to <a href="http://www.js-code.com/tag/let" title="浏览关于“let”的文章" target="_blank" class="tag_link">let</a> the user know</span> <span class="hljs-comment">// the transaction has been sent</span> $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Creating new zombie on the blockchain. This may take a while..."</span>); <span class="hljs-comment">// Send the tx to our contract:</span> <span class="hljs-keyword">return</span> CryptoZombies.methods.createRandomZombie(name) .send({ <span class="hljs-attr">from</span>: userAccount }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Successfully created "</span> + name + <span class="hljs-string">"!"</span>); <span class="hljs-comment">// Transaction was accepted into the blockchain, let's redraw the UI</span> getZombiesByOwner(userAccount).then(displayZombies); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ <span class="hljs-comment">// Do something to <a href="http://www.js-code.com/tag/alert" title="浏览关于“alert”的文章" target="_blank" class="tag_link">alert</a> the user their transaction has failed</span> $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">feedOnKitty</span>(<span class="hljs-params">zombieId, kittyId</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Eating a kitty. This may take a while..."</span>); <span class="hljs-keyword">return</span> CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ <span class="hljs-attr">from</span>: userAccount }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Ate a kitty and spawned a new Zombie!"</span>); getZombiesByOwner(userAccount).then(displayZombies); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } <span class="hljs-comment">// Start here</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">levelUp</span>(<span class="hljs-params">zombieId</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"正在升级您的僵尸..."</span>); <span class="hljs-keyword">return</span> CryptoZombies.methods.levelUp(zombieId) .send({ <span class="hljs-attr">from</span>: userAccount, <span class="hljs-attr">value</span>: web3js.utils.toWei(<span class="hljs-string">"0.001"</span>, <span class="hljs-string">"ether"</span>) }) .on(<span class="hljs-string">"receipt"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">receipt</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"不得了了!僵尸成功升级啦!"</span>); }) .on(<span class="hljs-string">"error"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{ $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZombieDetails</span>(<span class="hljs-params">id</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.zombies(id).call() } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">zombieToOwner</span>(<span class="hljs-params">id</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.zombieToOwner(id).call() } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZombiesByOwner</span>(<span class="hljs-params">owner</span>) </span>{ <span class="hljs-keyword">return</span> cryptoZombies.methods.getZombiesByOwner(owner).call() } <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// Checking if Web3 has been injected by the browser (Mist/MetaMask)</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> web3 !== <span class="hljs-string">'undefined'</span>) { <span class="hljs-comment">// Use Mist/MetaMask's provider</span> web3js = <span class="hljs-keyword">new</span> Web3(web3.currentProvider); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// Handle the case where the user doesn't have Metamask installed</span> <span class="hljs-comment">// Probably show them a message prompting them to install Metamask</span> } <span class="hljs-comment">// Now you can start your app &amp; access web3 freely:</span> startApp() }) </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span> </code></pre> <h2 id="articleHeader5">三、订阅事件</h2> <p>如你所见,通过 Web3.js 和合约交互非常简单直接——一旦你的环境建立起来, <code>call</code> 函数和 <code>send</code> 事务和普通的网络<a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a>并没有多少不同。</p> <p>还有一点东西我们想要讲到——订阅合约事件</p> <h3 id="articleHeader6">监听新事件</h3> <p>如果你还记得 <code>zombiefactory.sol</code>,每次新建一个僵尸后,我们会触发一个 <code>NewZombie</code> 事件:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="event NewZombie(uint zombieId, string name, uint dna);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs cs"><code style="word-break: break-word; white-space: initial;"><span class="hljs-function"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/event" title="浏览关于“event”的文章" target="_blank" class="tag_link">event</a></span> <span class="hljs-title">NewZombie</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> zombieId, <span class="hljs-keyword">string</span> name, <span class="hljs-keyword">uint</span> dna</span>)</span>;</code></pre> <p>在 Web3.js里, 你可以 订阅 一个事件,这样你的 Web3 提供者可以在每次事件发生后触发你的一些代码逻辑:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="cryptoZombies.events.NewZombie() .on(&quot;data&quot;, function(event) { let zombie = event.returnValues; console.log(&quot;一个新僵尸诞生了!&quot;, zombie.zombieId, zombie.name, zombie.dna); }).on('error', console.error);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code>cryptoZombies.events.NewZombie() .on(<span class="hljs-string">"data"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">event</span>) </span>{ <span class="hljs-keyword">let</span> zombie = event.returnValues; <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"一个新僵尸诞生了!"</span>, zombie.zombieId, zombie.name, zombie.dna); }).on(<span class="hljs-string">'error'</span>, <span class="hljs-built_in">console</span>.error);</code></pre> <p>注意这段代码将在 任何 僵尸生成的时候激发一个警告信息——而不仅仅是当前用用户的僵尸。如果我们只想对当前用户发出提醒呢?</p> <h3 id="articleHeader7">使用indexed</h3> <p>为了筛选仅和当前用户相关的事件,我们的 Solidity 合约将必须使用 <code>indexed</code> 关键字,就像我们在 ERC721 实现中的Transfer 事件中那样:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lisp"><code style="word-break: break-word; white-space: initial;">event Transfer(<span class="hljs-name">address</span> indexed _from, address indexed _to, uint256 _tokenId)<span class="hljs-comment">;</span></code></pre> <p>在这种情况下, 因为<code>_from</code> 和 <code>_to</code> 都是 <code>indexed</code>,这就意味着我们可以在前端事件监听中过滤事件.</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="cryptoZombies.events.Transfer({ filter: { _to: userAccount } }) .on(&quot;data&quot;, function(event) { let data = event.returnValues; // 当前用户更新了一个僵尸!更新界面来显示 }).on('error', console.error);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code>cryptoZombies.events.Transfer({ <span class="hljs-attr">filter</span>: { <span class="hljs-attr">_to</span>: userAccount } }) .on(<span class="hljs-string">"data"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">event</span>) </span>{ <span class="hljs-keyword">let</span> data = event.returnValues; <span class="hljs-comment">// 当前用户更新了一个僵尸!更新界面来显示</span> }).on(<span class="hljs-string">'error'</span>, <span class="hljs-built_in">console</span>.error);</code></pre> <p>看到了吧, 使用 <code><a href="http://www.js-code.com/tag/event" title="event" target="_blank">event</a></code> 和 <code>indexed</code> 字段对于监听合约中的更改并将其反映到 DApp 的前端界面中是非常有用的做法。</p> <h3 id="articleHeader8">查询过去的事件</h3> <p>我们甚至可以用 <code>getPastEvents</code> 查询过去的事件,并用过滤器 <code>fromBlock</code> 和 <code>toBlock</code> 给 Solidity 一个事件日志的时间范围("block" 在这里代表以太坊区块编号):</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="cryptoZombies.getPastEvents(&quot;NewZombie&quot;, { fromBlock: 0, toBlock: 'latest' }) .then(function(events) { // events 是可以用来遍历的 `event` 对象 // 这段代码将返回给我们从开始以来创建的僵尸列表 });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs actionscript"><code>cryptoZombies.getPastEvents(<span class="hljs-string">"NewZombie"</span>, { fromBlock: <span class="hljs-number">0</span>, toBlock: <span class="hljs-string">'latest'</span> }) .then(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(events)</span> </span>{ <span class="hljs-comment">// events 是可以用来遍历的 `event` 对象 </span> <span class="hljs-comment">// 这段代码将返回给我们从开始以来创建的僵尸列表</span> });</code></pre> <p>因为你可以用这个方法来查询从最开始起的事件日志,这就有了一个非常有趣的用例: <strong>用事件来作为一种更便宜的存储</strong>。</p> <p><strong>若你还能记得,在区块链上保存数据是 Solidity 中最贵的操作之一。但是用事件就便宜太多太多了</strong>。</p> <p>这里的短板是,事件不能从智能合约本身读取。但是,如果你有一些数据需要永久性地记录在区块链中以便可以在应用的前端中读取,这将是一个很好的用例。这些数据不会影响智能合约向前的状态。</p> <p>举个栗子,我们可以用事件来作为僵尸战斗的历史纪录——我们可以在每次僵尸攻击别人以及有一方胜出的时候产生一个事件。智能合约不需要这些数据来计算任何接下来的事情,但是这对我们在前端向用户展示来说是非常有用的东西。</p> <h3 id="articleHeader9">Web3.js事件和MetaMask</h3> <p>上面的示例代码是针对 Web3.js 最新版1.0的,此版本使用了 WebSockets 来订阅事件。</p> <p>但是,MetaMask 尚且不支持最新的事件 <a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a> (尽管如此,他们已经在实现这部分功能了, 点击这里 查看进度)</p> <p>所以现在我们必须使用一个单独 Web3 提供者,它针对事件提供了WebSockets支持。 我们可以用 <code>Infura</code> 来像实例化第二份拷贝:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var web3Infura = new Web3(new Web3.providers.WebsocketProvider(&quot;wss://mainnet.infura.io/ws&quot;)); var czEvents = new web3Infura.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress);" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs scala"><code><span class="hljs-keyword">var</span> web3Infura = <span class="hljs-keyword">new</span> <span class="hljs-type">Web3</span>(<span class="hljs-keyword">new</span> <span class="hljs-type">Web3</span>.providers.<span class="hljs-type">WebsocketProvider</span>(<span class="hljs-string">"wss://mainnet.infura.io/ws"</span>)); <span class="hljs-keyword">var</span> czEvents = <span class="hljs-keyword">new</span> web3Infura.eth.<span class="hljs-type">Contract</span>(cryptoZombiesABI, cryptoZombiesAddress);</code></pre> <p>然后我们将使用 <code>czEvents.<a href="http://www.js-code.com/tag/event" title="event" target="_blank">event</a>s.Transfer</code> 来监听事件,而不再使用 <code>cryptoZombies.events.Transfer</code>。我们将继续在课程的其他部分使用 <code>cryptoZombies.methods</code>。</p> <p>将来,在 MetaMask 升级了 <a href="http://www.js-code.com/tag/api" title="浏览关于“API”的文章" target="_blank" class="tag_link">API</a> 支持 Web3.js 后,我们就不用这么做了。但是现在我们还是要这么做,以使用 Web3.js 更好的最新语法来监听事件。</p> <h3 id="articleHeader10">放在一起</h3> <p>来添加一些代码监听 <code>Transfer</code> 事件,并在当前用户获得一个新僵尸的时候为他更新界面。</p> <p>我们将需要在 <code>startApp</code> 底部添加代码,以保证在添加事件监听器之前 <code>cryptoZombies</code> 已经初始化了。</p> <ul> <li>1、在 <code>startApp()</code>底部,为 <code>cryptoZombies.events.Transfer</code> 复制粘贴上面的2行事件监听代码块</li> <li>2、复制监听 <code>Transfer</code> 事件的代码块,并用 <code>_to: userAccount</code> 过滤。要记得把 <code>cryptoZombies</code> 换成 czEvents 好在这 里使用 Infura 而不是 <code>MetaMask</code> 来作为提供者。</li> <li>3、用 <code>getZombiesByOwner(userAccount).then(displayZombies);</code> 来更新界面</li> </ul> <p><code>index.html</code></p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="浏览关于“button”的文章" target="_blank" class="tag_link">button</a>" class="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="浏览关于“top”的文章" target="_blank" class="tag_link">top</a>" data-clipboard-text="<!DOCTYPE html><br /> <html lang=&quot;en&quot;><br /> <head><br /> <meta charset=&quot;UTF-8&quot;><br /> <title>CryptoZombies front-end</title><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;web3.min.js&quot;></script><br /> <script language=&quot;javascript&quot; type=&quot;text/javascript&quot; src=&quot;cryptozombies_abi.js&quot;></script><br /> </head><br /> <body></p> <div id=&quot;txStatus&quot;></div> <div id=&quot;zombies&quot;></div> <p> <script> var cryptoZombies; var userAccount;</p> <p> function startApp() { var cryptoZombiesAddress = &quot;YOUR_CONTRACT_ADDRESS&quot;; cryptoZombies = new web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress);</p> <p> var accountInterval = setInterval(function() { // Check if account has changed if (web3.eth.accounts[0] !== userAccount) { userAccount = web3.eth.accounts[0]; // Call a function to update the UI with the new account getZombiesByOwner(userAccount) .then(displayZombies); } }, 100);</p> <p> // Start here var web3Infura = new Web3(new Web3.providers.WebsocketProvider(&quot;wss: var czEvents = new web3Infura.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); czEvents.events.Transfer({ filter: { _to: userAccount } }) .on(&quot;data&quot;, function(event) { <a href="http://www.js-code.com/tag/let" title="let" target="_blank">let</a> data = event.returnValues; getZombiesByOwner(userAccount).then(displayZombies); }).on('error', console.error);</p> <p> }</p> <p> function displayZombies(ids) { $(&quot;#zombies&quot;).empty(); for (id of ids) { // Look up zombie details from our contract. Returns a `zombie` object getZombieDetails(id) .then(function(zombie) { // Using ES6's &quot;template literals&quot; to inject variables into the HTML. // Append each one to our #zombies div $(&quot;#zombies&quot;).append(`</p> <div class=&quot;zombie&quot;> <ul> <li>Name: ${zombie.name}</li> <li>DNA: ${zombie.dna}</li> <li>Level: ${zombie.level}</li> <li>Wins: ${zombie.winCount}</li> <li>Losses: ${zombie.lossCount}</li> <li>Ready Time: ${zombie.readyTime}</li> </ul></div> <p>`); }); } }</p> <p> function createRandomZombie(name) { // This is going to take a while, so update the UI to <a href="http://www.js-code.com/tag/let" title="let" target="_blank">let</a> the user know // the transaction has been sent $(&quot;#txStatus&quot;).text(&quot;Creating new zombie on the blockchain. This may take a while...&quot;); // Send the tx to our contract: return CryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;Successfully created &quot; + name + &quot;!&quot;); // Transaction was accepted into the blockchain, let's redraw the UI getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { // Do something to <a href="http://www.js-code.com/tag/alert" title="alert" target="_blank">alert</a> the user their transaction has failed $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function feedOnKitty(zombieId, kittyId) { $(&quot;#txStatus&quot;).text(&quot;Eating a kitty. This may take a while...&quot;); return CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ from: userAccount }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;Ate a kitty and spawned a new Zombie!&quot;); getZombiesByOwner(userAccount).then(displayZombies); }) .on(&quot;error&quot;, function(error) { $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function levelUp(zombieId) { $(&quot;#txStatus&quot;).text(&quot;Leveling up your zombie...&quot;); return CryptoZombies.methods.levelUp(zombieId) .send({ from: userAccount, value: web3.utils.toWei(&quot;0.001&quot;, &quot;ether&quot;) }) .on(&quot;receipt&quot;, function(receipt) { $(&quot;#txStatus&quot;).text(&quot;Power overwhelming! Zombie successfully leveled up&quot;); }) .on(&quot;error&quot;, function(error) { $(&quot;#txStatus&quot;).text(error); }); }</p> <p> function getZombieDetails(id) { return cryptoZombies.methods.zombies(id).call() }</p> <p> function zombieToOwner(id) { return cryptoZombies.methods.zombieToOwner(id).call() }</p> <p> function getZombiesByOwner(owner) { return cryptoZombies.methods.getZombiesByOwner(owner).call() }</p> <p> window.addEventListener('load', function() {</p> <p> // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } else { // Handle the case where the user doesn't have Metamask installed // Probably show them a message prompting them to install Metamask }</p> <p> // Now you can start your app &amp; access web3 freely: startApp()</p> <p> }) </script><br /> </body><br /> </html><br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs coffeescript"><code>&lt;!DOCTYPE html&gt; &lt;html lang=<span class="hljs-string">"en"</span>&gt; &lt;head&gt; &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt; &lt;title&gt;CryptoZombies front-end&lt;/title&gt; &lt;script language=<span class="hljs-string">"javascript"</span> type=<span class="hljs-string">"text/javascript"</span> src=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"</span>&gt;&lt;/script&gt; &lt;script language=<span class="hljs-string">"javascript"</span> type=<span class="hljs-string">"text/javascript"</span> src=<span class="hljs-string">"web3.min.js"</span>&gt;&lt;/script&gt; &lt;script language=<span class="hljs-string">"javascript"</span> type=<span class="hljs-string">"text/javascript"</span> src=<span class="hljs-string">"cryptozombies_abi.js"</span>&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;div id=<span class="hljs-string">"txStatus"</span>&gt;&lt;/div&gt; &lt;div id=<span class="hljs-string">"zombies"</span>&gt;&lt;/div&gt; &lt;script&gt; var cryptoZombies; var userAccount; function startApp() { var cryptoZombiesAddress = <span class="hljs-string">"YOUR_CONTRACT_ADDRESS"</span>; cryptoZombies = <span class="hljs-keyword">new</span> web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); var accountInterval = setInterval(function() { <span class="hljs-regexp">//</span> Check <span class="hljs-keyword">if</span> account has changed <span class="hljs-keyword">if</span> (web3.eth.accounts[<span class="hljs-number">0</span>] !== userAccount) { userAccount = web3.eth.accounts[<span class="hljs-number">0</span>]; <span class="hljs-regexp">//</span> Call a function to update the UI with the <span class="hljs-keyword">new</span> account getZombiesByOwner(userAccount) .<span class="hljs-keyword">then</span>(displayZombies); } }, <span class="hljs-number">100</span>); <span class="hljs-regexp">//</span> Start here var web3Infura = <span class="hljs-keyword">new</span> Web3(<span class="hljs-keyword">new</span> Web3.providers.WebsocketProvider(<span class="hljs-string">"wss: var czEvents = new web3Infura.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); czEvents.events.Transfer({ filter: { _to: userAccount } }) .on("</span>data<span class="hljs-string">", function(event) { let data = event.returnValues; getZombiesByOwner(userAccount).then(displayZombies); }).on('error', console.error); } function displayZombies(ids) { $("</span><span class="hljs-comment">#zombies").empty();</span> <span class="hljs-keyword">for</span> (id <span class="hljs-keyword">of</span> ids) { <span class="hljs-regexp">//</span> Look up zombie details <span class="hljs-keyword">from</span> our contract. Returns a `<span class="javascript">zombie</span>` object getZombieDetails(id) .<span class="hljs-keyword">then</span>(function(zombie) { <span class="hljs-regexp">//</span> Using ES6<span class="hljs-string">'s "template literals" to inject variables into the HTML. // Append each one to our #zombies div $("#zombies").append(`&lt;div class="zombie"&gt; &lt;ul&gt; &lt;li&gt;Name: ${zombie.name}&lt;/li&gt; &lt;li&gt;DNA: ${zombie.dna}&lt;/li&gt; &lt;li&gt;Level: ${zombie.level}&lt;/li&gt; &lt;li&gt;Wins: ${zombie.winCount}&lt;/li&gt; &lt;li&gt;Losses: ${zombie.lossCount}&lt;/li&gt; &lt;li&gt;Ready Time: ${zombie.readyTime}&lt;/li&gt; &lt;/ul&gt; &lt;/div&gt;`); }); } } function createRandomZombie(name) { // This is going to take a while, so update the UI to let the user know // the transaction has been sent $("#txStatus").text("Creating new zombie on the blockchain. This may take a while..."); // Send the tx to our contract: return CryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on("receipt", function(receipt) { $("#txStatus").text("Successfully created " + name + "!"); // Transaction was accepted into the blockchain, let'</span>s redraw the UI getZombiesByOwner(userAccount).<span class="hljs-keyword">then</span>(displayZombies); }) .<span class="hljs-literal">on</span>(<span class="hljs-string">"error"</span>, function(error) { <span class="hljs-regexp">//</span> Do something to alert the user their transaction has failed $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } function feedOnKitty(zombieId, kittyId) { $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Eating a kitty. This may take a while..."</span>); <span class="hljs-keyword">return</span> CryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ from: userAccount }) .<span class="hljs-literal">on</span>(<span class="hljs-string">"receipt"</span>, function(receipt) { $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Ate a kitty and spawned a new Zombie!"</span>); getZombiesByOwner(userAccount).<span class="hljs-keyword">then</span>(displayZombies); }) .<span class="hljs-literal">on</span>(<span class="hljs-string">"error"</span>, function(error) { $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } function levelUp(zombieId) { $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Leveling up your zombie..."</span>); <span class="hljs-keyword">return</span> CryptoZombies.methods.levelUp(zombieId) .send({ from: userAccount, value: web3.utils.toWei(<span class="hljs-string">"0.001"</span>, <span class="hljs-string">"ether"</span>) }) .<span class="hljs-literal">on</span>(<span class="hljs-string">"receipt"</span>, function(receipt) { $(<span class="hljs-string">"#txStatus"</span>).text(<span class="hljs-string">"Power overwhelming! Zombie successfully leveled up"</span>); }) .<span class="hljs-literal">on</span>(<span class="hljs-string">"error"</span>, function(error) { $(<span class="hljs-string">"#txStatus"</span>).text(error); }); } function getZombieDetails(id) { <span class="hljs-keyword">return</span> cryptoZombies.methods.zombies(id).call() } function zombieToOwner(id) { <span class="hljs-keyword">return</span> cryptoZombies.methods.zombieToOwner(id).call() } function getZombiesByOwner(owner) { <span class="hljs-keyword">return</span> cryptoZombies.methods.getZombiesByOwner(owner).call() } <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, function() { <span class="hljs-regexp">//</span> Checking <span class="hljs-keyword">if</span> Web3 has been injected <span class="hljs-keyword">by</span> the browser (Mist/MetaMask) <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> web3 !== <span class="hljs-string">'undefined'</span>) { <span class="hljs-regexp">//</span> Use Mist/MetaMask<span class="hljs-string">'s provider web3js = new Web3(web3.currentProvider); } else { // Handle the case where the user doesn'</span>t have Metamask installed <span class="hljs-regexp">//</span> Probably show them a message prompting them to install Metamask } <span class="hljs-regexp">//</span> Now you can start your app &amp; access web3 freely: startApp() }) &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <hr></code></p>

总结

以上是脚本宝典为你收集整理的

以太坊开发实战学习-Web3.js(十)

全部内容,希望文章能够帮你解决

以太坊开发实战学习-Web3.js(十)

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过