diff --git a/zh/10/00-overview.md b/zh/10/00-overview.md index 045c45dd91..6d6fd4287c 100644 --- a/zh/10/00-overview.md +++ b/zh/10/00-overview.md @@ -16,10 +16,10 @@ position: 2 为什么要部署到 **Loom**?毕竟,**_以太坊_** 才是最安全的网络。 -是的,我们完全同意。但在以太坊上每个事务都要耗费 _gas_, 因此你的用户就必须为每个事务付费。而且,每个事务确认还得等上至少10秒。 +是的,我们完全同意。但在以太坊上每个交易都要耗费 _gas_, 因此你的用户就必须为每个交易付费。而且,每个交易确认还得等上至少10秒。 -简而言之,**_在以太坊上,所有事务都受益于相同的安全保障_**。对于面向用户的 dapp 或游戏等,往往并不一定需要这种级别的安全性。事实上,它只会破坏用户体验。 +简而言之,**_在以太坊上,所有交易都受益于相同的安全保障_**。对于面向用户的 dapp 或游戏等,往往并不一定需要这种级别的安全性。事实上,它只会破坏用户体验。 -在 **Loom** 上, 用户可以有更快速且零 gas 的事务。这使得 **Loom** 更适合游戏或面向用户的 dapp。 +在 **Loom** 上, 用户可以有更快速且零 gas 的交易。这使得 **Loom** 更适合游戏或面向用户的 dapp。 好了,废话少说!现在就开始吧 😉 \ No newline at end of file diff --git a/zh/10/02.md b/zh/10/02.md index 60faae63a5..d6bd36b094 100644 --- a/zh/10/02.md +++ b/zh/10/02.md @@ -67,7 +67,7 @@ truffle.js ## truffle-hdwallet-provider -在本课中,我们将使用 _Infura_ 来把代码部署到 **_以太坊_**。这样,我们的用户便可以直接运行该应用程序,他们无需设置自己的 **_以太坊_** 节点或钱包。然而,为了保证安全,_Infura_ 不管理私钥,这也意味着它不能代表我们签署事务易。由于部署智能合约需要 **Truffle** 签署事务,所以我们将需要一个叫做 `truffle-hdwallet-provider` 的工具。它惟一的目的就是处理事务签名。 +在本课中,我们将使用 _Infura_ 来把代码部署到 **_以太坊_**。这样,我们的用户便可以直接运行该应用程序,他们无需设置自己的 **_以太坊_** 节点或钱包。然而,为了保证安全,_Infura_ 不管理私钥,这也意味着它不能代表我们签署交易易。由于部署智能合约需要 **Truffle** 签署交易,所以我们将需要一个叫做 `truffle-hdwallet-provider` 的工具。它惟一的目的就是处理交易签名。 >注意: 也许你会问,为什么我们不在上一章安装 `truffle-hdwallet-provider`, 使用像下面这样的命令: diff --git a/zh/10/05.md b/zh/10/05.md index 2800c0e2ca..cacf5280b1 100644 --- a/zh/10/05.md +++ b/zh/10/05.md @@ -92,7 +92,7 @@ $ cat truffle.js 还记得第二章吗? -我们让你装了一个叫做 `truffle-hdwallet-provider` 的附加包,好帮助 **Truffle** 签署事务。 +我们让你装了一个叫做 `truffle-hdwallet-provider` 的附加包,好帮助 **Truffle** 签署交易。 现在,我们想要编辑配置文件以使用 `HDWalletProvider`。先得在文件顶部添加一行: diff --git a/zh/10/07.md b/zh/10/07.md index 8ccc777f69..93229519bd 100644 --- a/zh/10/07.md +++ b/zh/10/07.md @@ -21,9 +21,9 @@ material: ## Loom Basechain -现在,如果你想在 `以太坊` 上构建 DApp,有一点你应该清楚 —— 在主网上,用户需要 `为每笔事务支付 gas 费`。这对于面向用户的 DApp 或游戏来说并不理想。它很容易破坏用户体验。 +现在,如果你想在 `以太坊` 上构建 DApp,有一点你应该清楚 —— 在主网上,用户需要 `为每笔交易支付 gas 费`。这对于面向用户的 DApp 或游戏来说并不理想。它很容易破坏用户体验。 -相反,在 `Loom` 上,你的用户可以有更快速且无 gas 的事务,这使得它更适合游戏和其他非金融类应用。 +相反,在 `Loom` 上,你的用户可以有更快速且无 gas 的交易,这使得它更适合游戏和其他非金融类应用。 这意味着你的 `Loom` 僵尸将是快僵尸! diff --git a/zh/10/lessoncomplete.md b/zh/10/lessoncomplete.md index d3fbb18e98..a0a6ce668b 100644 --- a/zh/10/lessoncomplete.md +++ b/zh/10/lessoncomplete.md @@ -9,7 +9,7 @@ material: 你已经掌握了使用 **Truffle** 部署智能合约的技能! -请记住,在 **_Loom_** 上构建将为你带来更快速、无 gas 的事务,是你创建区块链游戏和面向用户型 dapp 的完美选择。与此同时,你的用户也将享受到以太坊提供的安全保障! +请记住,在 **_Loom_** 上构建将为你带来更快速、无 gas 的交易,是你创建区块链游戏和面向用户型 dapp 的完美选择。与此同时,你的用户也将享受到以太坊提供的安全保障! 另一点也请记住,部署到 **_Loom_** 与部署到以太网差不多。你已经知道具体怎么实现,下一个项目就请选择使用最适合你的吧 😉。 diff --git a/zh/11/05.md b/zh/11/05.md index 2dfcf56966..5452637795 100644 --- a/zh/11/05.md +++ b/zh/11/05.md @@ -55,9 +55,9 @@ const result = await contractInstance.createRandomZombie(zombieNames[0], {from: 在使用 `artifacts.require` 指定了我们要测试的合约后,_Truffle_ 就会自动提供我们智能合约产生的日志。这意味着我们现在可以这样来检索 Alice 的新僵尸名字:`result.logs[0].args.name`。用类似的方式,我们还可以获得其 `id` 和`_dna`。 -除了这些信息外,`result` 还将为我们提供关于事务的其他一些有用细节: -- `result.tx`: 事务哈希 -- `result.receipt`: 包含事务收据的对象。如果 `result.receipt.status` 的值是 `true`, 表示事务成功。否则,就意味着事务失败。 +除了这些信息外,`result` 还将为我们提供关于交易的其他一些有用细节: +- `result.tx`: 交易哈希 +- `result.receipt`: 包含交易收据的对象。如果 `result.receipt.status` 的值是 `true`, 表示交易成功。否则,就意味着交易失败。 >注意:还可以选择日志来存储数据。优点是很低廉,缺点是无法从智能合约内部对其进行访问。 diff --git a/zh/11/12.md b/zh/11/12.md index fead458c5c..8437188ab4 100644 --- a/zh/11/12.md +++ b/zh/11/12.md @@ -268,7 +268,7 @@ function _createZombie(string _name, uint _dna) internal { 让我来解释下这些函数是如何运行的: -- 每次挖一个新区块时,矿工都会向它添加一个时间戳。假设在第5个区块中挖到了生成僵尸的事务。 +- 每次挖一个新区块时,矿工都会向它添加一个时间戳。假设在第5个区块中挖到了生成僵尸的交易。 - 接下来,我们调用 `evm_increaseTime`,但由于区块链是不可变的,所以不可能修改现有区块。所以,当合约检查时间时,它不会增加。 diff --git a/zh/11/13.md b/zh/11/13.md index 1b240399ef..90cd8ee27d 100644 --- a/zh/11/13.md +++ b/zh/11/13.md @@ -248,7 +248,7 @@ expect(zombieName).to.equal('My Awesome Zombie'); 1. 将 `expect` 移植到我们的项目中。 -2. 用 `zombieName` 继续上面的例子,我们可以使用 `expect` 来为一个成功的事务测试,如下所示: +2. 用 `zombieName` 继续上面的例子,我们可以使用 `expect` 来为一个成功的交易测试,如下所示: ```javascript expect(result.receipt.status).to.equal(true); diff --git a/zh/11/14.md b/zh/11/14.md index 9f5c3ccc9b..0ea6980538 100644 --- a/zh/11/14.md +++ b/zh/11/14.md @@ -109,7 +109,7 @@ material: 现在,如果不向你展示如何在 **_Loom_** 测试网上进行测试,本教程就不完整啦。 -回想一下我们之前的课程,在 **_Loom_** 上,用户可以比在**以太坊**上有更快、更且无 gas 的事务。这使得 DAppChain 更适合游戏或面向用户的 DApp。 +回想一下我们之前的课程,在 **_Loom_** 上,用户可以比在**以太坊**上有更快、更且无 gas 的交易。这使得 DAppChain 更适合游戏或面向用户的 DApp。 而且,你知道吗?在 **Loom** 上部署和测试没有任何不同。我们已经为你总结了在 **_Loom_** 上测试所需要做的,快来看下吧。 diff --git a/zh/3/10-savinggasview.md b/zh/3/10-savinggasview.md index 6770412472..b7eeb0a1e6 100644 --- a/zh/3/10-savinggasview.md +++ b/zh/3/10-savinggasview.md @@ -202,11 +202,11 @@ material: 当玩家从外部调用一个`view`函数,是不需要支付一分 gas 的。 -这是因为 `view` 函数不会真正改变区块链上的任何数据 - 它们只是读取。因此用 `view` 标记一个函数,意味着告诉 `web3.js`,运行这个函数只需要查询你的本地以太坊节点,而不需要在区块链上创建一个事务(事务需要运行在每个节点上,因此花费 gas)。 +这是因为 `view` 函数不会真正改变区块链上的任何数据 - 它们只是读取。因此用 `view` 标记一个函数,意味着告诉 `web3.js`,运行这个函数只需要查询你的本地以太坊节点,而不需要在区块链上创建一个交易(交易需要运行在每个节点上,因此花费 gas)。 稍后我们将介绍如何在自己的节点上设置 web3.js。但现在,你关键是要记住,在所能只读的函数上标记上表示“只读”的“`external view` 声明,就能为你的玩家减少在 DApp 中 gas 用量。 ->注意:如果一个 `view` 函数在另一个函数的内部被调用,而调用函数与 `view` 函数的不属于同一个合约,也会产生调用成本。这是因为如果主调函数在以太坊创建了一个事务,它仍然需要逐个节点去验证。所以标记为 `view` 的函数只有在外部调用时才是免费的。 +>注意:如果一个 `view` 函数在另一个函数的内部被调用,而调用函数与 `view` 函数的不属于同一个合约,也会产生调用成本。这是因为如果主调函数在以太坊创建了一个交易,它仍然需要逐个节点去验证。所以标记为 `view` 的函数只有在外部调用时才是免费的。 ## 实战演习 diff --git a/zh/4/battle-02.md b/zh/4/battle-02.md index 242e265c54..1b0c0bc613 100644 --- a/zh/4/battle-02.md +++ b/zh/4/battle-02.md @@ -249,15 +249,15 @@ uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100; ### 这个方法很容易被不诚实的节点攻击 -在以太坊上, 当你在和一个合约上调用函数的时候, 你会把它广播给一个节点或者在网络上的 **_transaction_** 节点们。 网络上的节点将收集很多事务, 试着成为第一个解决计算密集型数学问题的人,作为“工作证明”,然后将“工作证明”(Proof of Work, PoW)和事务一起作为一个 **_block_** 发布在网络上。 +在以太坊上, 当你在和一个合约上调用函数的时候, 你会把它广播给一个节点或者在网络上的 **_transaction_** 节点们。 网络上的节点将收集很多交易, 试着成为第一个解决计算密集型数学问题的人,作为“工作证明”,然后将“工作证明”(Proof of Work, PoW)和交易一起作为一个 **_block_** 发布在网络上。 -一旦一个节点解决了一个PoW, 其他节点就会停止尝试解决这个 PoW, 并验证其他节点的事务列表是有效的,然后接受这个节点转而尝试解决下一个节点。 +一旦一个节点解决了一个PoW, 其他节点就会停止尝试解决这个 PoW, 并验证其他节点的交易列表是有效的,然后接受这个节点转而尝试解决下一个节点。 **这就让我们的随机数函数变得可利用了** 我们假设我们有一个硬币翻转合约——正面你赢双倍钱,反面你输掉所有的钱。假如它使用上面的方法来决定是正面还是反面 (`random >= 50` 算正面, `random < 50` 算反面)。 -如果我正运行一个节点,我可以 **只对我自己的节点** 发布一个事务,且不分享它。 我可以运行硬币翻转方法来偷窥我的输赢 — 如果我输了,我就不把这个事务包含进我要解决的下一个区块中去。我可以一直运行这个方法,直到我赢得了硬币翻转并解决了下一个区块,然后获利。 +如果我正运行一个节点,我可以 **只对我自己的节点** 发布一个交易,且不分享它。 我可以运行硬币翻转方法来偷窥我的输赢 — 如果我输了,我就不把这个交易包含进我要解决的下一个区块中去。我可以一直运行这个方法,直到我赢得了硬币翻转并解决了下一个区块,然后获利。 ## 所以我们该如何在以太坊上安全地生成随机数呢 diff --git a/zh/4/payable.md b/zh/4/payable.md index d1a4bb77ec..156be7e5a2 100644 --- a/zh/4/payable.md +++ b/zh/4/payable.md @@ -251,7 +251,7 @@ function test() external view onlyOwner anotherModifier { /* ... */ } 先放一下。当你在调用一个普通网站服务器上的API函数的时候,你无法用你的函数传送美元——你也不能传送比特币。 -但是在以太坊中, 因为钱 (_以太_), 数据 (*事务负载*), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 **并**付钱给另外一个合约。 +但是在以太坊中, 因为钱 (_以太_), 数据 (*交易负载*), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 **并**付钱给另外一个合约。 这就允许出现很多有趣的逻辑, 比如向一个合约要求支付一定的钱来运行一个函数。 @@ -276,9 +276,9 @@ contract OnlineStore { OnlineStore.buySomething().send(from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)) ``` -注意这个 `value` 字段, JavaScript 调用来指定发送多少(0.001)`以太`。如果把事务想象成一个信封,你发送到函数的参数就是信的内容。 添加一个 `value` 很像在信封里面放钱 —— 信件内容和钱同时发送给了接收者。 +注意这个 `value` 字段, JavaScript 调用来指定发送多少(0.001)`以太`。如果把交易想象成一个信封,你发送到函数的参数就是信的内容。 添加一个 `value` 很像在信封里面放钱 —— 信件内容和钱同时发送给了接收者。 ->注意: 如果一个函数没标记为`payable`, 而你尝试利用上面的方法发送以太,函数将拒绝你的事务。 +>注意: 如果一个函数没标记为`payable`, 而你尝试利用上面的方法发送以太,函数将拒绝你的交易。 ## 实战演习 diff --git a/zh/6/02.md b/zh/6/02.md index 71ac2c7005..d0f54d51b8 100644 --- a/zh/6/02.md +++ b/zh/6/02.md @@ -402,9 +402,9 @@ material: var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws")); ``` -不过,因为我们的 DApp 将被很多人使用,这些用户不单会从区块链读取信息,还会向区块链 **_写_** 入信息,我们需要用一个方法让用户可以用他们的私钥给事务签名。 +不过,因为我们的 DApp 将被很多人使用,这些用户不单会从区块链读取信息,还会向区块链 **_写_** 入信息,我们需要用一个方法让用户可以用他们的私钥给交易签名。 -> 注意: 以太坊 (以及通常意义上的 blockchains )使用一个公钥/私钥对来对给事务做数字签名。把它想成一个数字签名的异常安全的密码。这样当我修改区块链上的数据的时候,我可以用我的公钥来 **证明** 我就是签名的那个。但是因为没人知道我的私钥,所以没人能伪造我的事务。 +> 注意: 以太坊 (以及通常意义上的 blockchains )使用一个公钥/私钥对来对给交易做数字签名。把它想成一个数字签名的异常安全的密码。这样当我修改区块链上的数据的时候,我可以用我的公钥来 **证明** 我就是签名的那个。但是因为没人知道我的私钥,所以没人能伪造我的交易。 加密学非常复杂,所以除非你是个专家并且的确知道自己在做什么,你最好不要在你应用的前端中管理你用户的私钥。 diff --git a/zh/6/04.md b/zh/6/04.md index f44065a8db..733069ada0 100644 --- a/zh/6/04.md +++ b/zh/6/04.md @@ -892,9 +892,9 @@ Web3.js 有两个方法来调用我们合约的函数: `call` and `send`. ### Call -`call` 用来调用 `view` 和 `pure` 函数。它只运行在本地节点,不会在区块链上创建事务。 +`call` 用来调用 `view` 和 `pure` 函数。它只运行在本地节点,不会在区块链上创建交易。 -> **复习:** `view` 和 `pure` 函数是只读的并不会改变区块链的状态。它们也不会消耗任何gas。用户也不会被要求用MetaMask对事务签名。 +> **复习:** `view` 和 `pure` 函数是只读的并不会改变区块链的状态。它们也不会消耗任何gas。用户也不会被要求用MetaMask对交易签名。 使用 Web3.js,你可以如下 `call` 一个名为`myMethod`的方法并传入一个 `123` 作为参数: @@ -904,11 +904,11 @@ myContract.methods.myMethod(123).call() ### Send -`send` 将创建一个事务并改变区块链上的数据。你需要用 `send` 来调用任何非 `view` 或者 `pure` 的函数。 +`send` 将创建一个交易并改变区块链上的数据。你需要用 `send` 来调用任何非 `view` 或者 `pure` 的函数。 -> **注意:** `send` 一个事务将要求用户支付gas,并会要求弹出对话框请求用户使用 Metamask 对事务签名。在我们使用 Metamask 作为我们的 web3 提供者的时候,所有这一切都会在我们调用 `send()` 的时候自动发生。而我们自己无需在代码中操心这一切,挺爽的吧。 +> **注意:** `send` 一个交易将要求用户支付gas,并会要求弹出对话框请求用户使用 Metamask 对交易签名。在我们使用 Metamask 作为我们的 web3 提供者的时候,所有这一切都会在我们调用 `send()` 的时候自动发生。而我们自己无需在代码中操心这一切,挺爽的吧。 -使用 Web3.js, 你可以像这样 `send` 一个事务调用`myMethod` 并传入 `123` 作为参数: +使用 Web3.js, 你可以像这样 `send` 一个交易调用`myMethod` 并传入 `123` 作为参数: ``` myContract.methods.myMethod(123).send() diff --git a/zh/6/07.md b/zh/6/07.md index bbc23dde93..cd0bfe62e8 100644 --- a/zh/6/07.md +++ b/zh/6/07.md @@ -1,5 +1,5 @@ --- -title: 发送事务 +title: 发送交易 actions: ['checkAnswer', 'hints'] requireLogin: true material: @@ -1004,11 +1004,11 @@ material: 相对 `call` 函数,`send` 函数有如下主要区别: -1. `send` 一个事务需要一个 `from` 地址来表明谁在调用这个函数(也就是你 Solidity 代码里的 `msg.sender` )。 我们需要这是我们 DApp 的用户,这样一来 MetaMask 才会弹出提示让他们对事务签名。 +1. `send` 一个交易需要一个 `from` 地址来表明谁在调用这个函数(也就是你 Solidity 代码里的 `msg.sender` )。 我们需要这是我们 DApp 的用户,这样一来 MetaMask 才会弹出提示让他们对交易签名。 -2. `send` 一个事务将花费 gas +2. `send` 一个交易将花费 gas -3. 在用户 `send` 一个事务到该事务对区块链产生实际影响之间有一个不可忽略的延迟。这是因为我们必须等待事务被包含进一个区块里,以太坊上一个区块的时间平均下来是15秒左右。如果当前在以太坊上有大量挂起事务或者用户发送了过低的 gas 价格,我们的事务可能需要等待数个区块才能被包含进去,往往可能花费数分钟。 +3. 在用户 `send` 一个交易到该交易对区块链产生实际影响之间有一个不可忽略的延迟。这是因为我们必须等待交易被包含进一个区块里,以太坊上一个区块的时间平均下来是15秒左右。如果当前在以太坊上有大量挂起交易或者用户发送了过低的 gas 价格,我们的交易可能需要等待数个区块才能被包含进去,往往可能花费数分钟。 所以在我们的代码中我们需要编写逻辑来处理这部分异步特性。 @@ -1032,14 +1032,14 @@ function createRandomZombie(string _name) public { ``` function createRandomZombie(name) { // 这将需要一段时间,所以在界面中告诉用户这一点 - // 事务被发送出去了 + // 交易被发送出去了 $("#txStatus").text("正在区块链上创建僵尸,这将需要一会儿..."); - // 把事务发送到我们的合约: + // 把交易发送到我们的合约: return cryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on("receipt", function(receipt) { $("#txStatus").text("成功生成了 " + name + "!"); - // 事务被区块链接受了,重新渲染界面 + // 交易被区块链接受了,重新渲染界面 getZombiesByOwner(userAccount).then(displayZombies); }) .on("error", function(error) { @@ -1049,22 +1049,22 @@ function createRandomZombie(name) { } ``` -我们的函数 `send` 一个事务到我们的 Web3 提供者,然后链式添加一些事件监听: +我们的函数 `send` 一个交易到我们的 Web3 提供者,然后链式添加一些事件监听: - `receipt` 将在合约被包含进以太坊区块上以后被触发,这意味着僵尸被创建并保存进我们的合约了。 -- `error` 将在事务未被成功包含进区块后触发,比如用户未支付足够的 gas。我们需要在界面中通知用户事务失败以便他们可以再次尝试。 +- `error` 将在交易未被成功包含进区块后触发,比如用户未支付足够的 gas。我们需要在界面中通知用户交易失败以便他们可以再次尝试。 > 注意:你可以在调用 `send` 时选择指定 `gas` 和 `gasPrice`, 例如: `.send({ from: userAccount, gas: 3000000 })`。如果你不指定,MetaMask 将让用户自己选择数值。 ## 实战演习 -我们添加了一个`div`, 指定 ID 为 `txStatus` — 这样我们可以通过更新这个 div 来通知用户事务的状态。 +我们添加了一个`div`, 指定 ID 为 `txStatus` — 这样我们可以通过更新这个 div 来通知用户交易的状态。 1. 在 `displayZombies`下面, 复制粘贴上面 `createRandomZombie` 的代码。 2. 我们来实现另外一个函数 `feedOnKitty`: - 调用 `feedOnKitty` 的逻辑几乎一样 — 我们将发送一个事务来调用这个函数,并且成功的事务会为我们创建一个僵尸,所以我们希望在成功后重新绘制界面。 + 调用 `feedOnKitty` 的逻辑几乎一样 — 我们将发送一个交易来调用这个函数,并且成功的交易会为我们创建一个僵尸,所以我们希望在成功后重新绘制界面。 在 `createRandomZombie` 下面复制粘贴它的代码,改动这些地方: diff --git a/zh/6/08.md b/zh/6/08.md index 01aab624e4..885f532a37 100644 --- a/zh/6/08.md +++ b/zh/6/08.md @@ -1079,7 +1079,7 @@ cryptoZombies.methods.levelUp(zombieId) 1. 函数将接收一个参数, `zombieId` -2. 在发送事务之前,`txStatus` 的文本应该是 `"正在升级您的僵尸..."` +2. 在发送交易之前,`txStatus` 的文本应该是 `"正在升级您的僵尸..."` 3. 当它调用合约里的`levelUp`时,它应该发送`"0.001"` ETH,并用 `toWei` 转换,如同上面例子里那样。 diff --git a/zh/6/09.md b/zh/6/09.md index 7c7ec541ca..8cf5368ca2 100644 --- a/zh/6/09.md +++ b/zh/6/09.md @@ -1057,7 +1057,7 @@ material: --- -如你所见,通过 Web3.js 和合约交互非常简单直接——一旦你的环境建立起来, `call` 函数和 `send` 事务和普通的网络API并没有多少不同。 +如你所见,通过 Web3.js 和合约交互非常简单直接——一旦你的环境建立起来, `call` 函数和 `send` 交易和普通的网络API并没有多少不同。 还有一点东西我们想要讲到——订阅合约事件 diff --git a/zh/6/10-wrappingitup.md b/zh/6/10-wrappingitup.md index 7345ab075e..93887e06c0 100644 --- a/zh/6/10-wrappingitup.md +++ b/zh/6/10-wrappingitup.md @@ -19,7 +19,7 @@ material: 所以我们把一些实现略去了。这里是你要完整实现所需要完成的基本事项列表: -1. 为 `attack`, `changeName`, `changeDna` 以及 ERC721 函数 `transfer`, `ownerOf`, `balanceOf` 等实现前端函数。这些函数的实现将和我们讲过的 `send`事务的函数非常相似。 +1. 为 `attack`, `changeName`, `changeDna` 以及 ERC721 函数 `transfer`, `ownerOf`, `balanceOf` 等实现前端函数。这些函数的实现将和我们讲过的 `send`交易的函数非常相似。 2. 实现一个“管理界面”,在那里你可以调用 `setKittyContractAddress`, `setLevelUpFee`, 以及 `withdraw`。再次,在前端这块没有什么特别的代码——这些实现之间将非常相似。你应该保证从部署合同时候相同的以太坊地址调用这些函数,因为他们都有`onlyOwner` 修饰符。