在本系列关于使用以太坊构建DApps教程的第7部分中,我们展示了如何构建应用程序的前端,为我们一直在研究的这个Story故事设置和部署UI。是时候进行一些部署并编写一些最终功能了。
这是使用以太坊区块链构建去中心化应用程序系列的第八部分。我们正在建设的项目名为The Neverending Story
。完整的项目可以在storydao.bitfalls.com
找到。它的完整代码在GitHub上 。
以下是整个系列的概述:
- 在第1部分中,我们引导大家做了两个版本的本地区块链进行开发:Ganache版本和完整的私有PoA版本。
- 在第2部分中,我们构建并部署了TNS代币。
- 在第3部分,我们将介绍如何编译,部署,测试和验证我们的自定义TNS代币,该代币与所有交易所兼容,可用作常规ERC20代币。
- 在第4部分中,我们迈出了开发Story DAO的第一步,包括白名单和测试。
- 在第5部分中,我们处理向故事Story添加内容,查看如何添加参与者从DAO购买代币的能力以及向故事中添加提交内容。
- 在第6部分中,我们将DAO置于最终形式,添加投票,黑名单/取消黑名单,股息分配和撤销,同时投入一些额外的辅助函数以获得良好的评价标准。
- 在第7部分中,我们将展示如何构建应用程序的前端,为我们一直在研究的这个故事story设置和部署UI。
- 在最后一部分中,我们将介绍部署应用程序和编写一些最终功能的最后步骤。
自毁程序
有些东西可能会非常非常错误,并且使得整个DAO会以某种方式被破坏——无论是通过糟糕的编写代码,还是由于参与者太多而无法完成循环。(提案上的选民太多也可能破坏系统;我们实际上没有采取任何预防措施!)为了防止发生这种情况,拥有相当于“红色大按钮”可能会很有用。首先,让我们升级我们的StoryDao
:
function bigRedButton() onlyOwner external {
active = false;
withdrawToOwner();
token.unlockForAll();
}
然后,让我们可以在代币合约中立即解锁所有代币:
/**
@dev unlocks the tokens of every user who ever had any tokens locked for them
*/
function unlockForAll() public onlyOwner {
uint256 len = touchedByLock.length;
for (uint256 i = 0; i < len; i++) {
locked[touchedByLock[i]] = 0;
}
}
当然,我们需要在合约中添加这个新的地址列表:
address[] touchedByLock;
我们需要升级我们的increaseLockedAmount
函数以向此列表添加地址:
/**
@dev _owner will be prevented from sending _amount of tokens. Anything
beyond this amount will be spendable.
*/
function increaseLockedAmount(address _owner, uint256 _amount) public onlyOwner returns (uint256) {
uint256 lockingAmount = locked[_owner].add(_amount);
require(balanceOf(_owner) >= lockingAmount, "Locking amount must not exceed balance");
locked[_owner] = lockingAmount;
touchedByLock.push(_owner);
emit Locked(_owner, lockingAmount);
return lockingAmount;
}
我们还应该更新StoryDao
合约中代币所需的接口,以包含这个新函数的签名:
// ...
function getUnlockedAmount(address _owner) view public returns (uint256);
function unlockForAll() public;
}
使用我们之前添加的活动故事块(除非故事的active
标志为真,否则无法运行某些功能),这应该可以解决问题。没有人需要在发送合约时浪费钱,每个人的代币都会被解锁。
所有者没有得到人们提交的以太。取而代之的是退出功能变得可用,因此人们可以收回他们的以太,并且每个人都会得到照顾。
现在我们的合约终于可以部署了。
销毁程序是什么样的?
有一个名为selfdestruct
的函数可以销毁合约。它看起来像这样:
selfdestruct(address);
调用它将禁用有问题的合约,从区块链的状态中删除其代码并禁用所有功能,同时将该地址中的以太网发送到提供的地址。在我们的案例中,这不是一个好主意:我们仍然希望人们能够撤回他们的以太;我们不想从他们那里拿走它。此外,直接发送到自杀合约地址的任何以太币将永远丢失(烧毁),因为没有办法将其取回。
部署合约
要完全部署智能合约,我们需要执行以下操作:
- 部署到主网
- 将代币发送到StoryDAO地址
- 将Token合约的所有权转让给StoryDao。
我们走吧。
主网部署
要部署到mainnet
,我们需要在truffle.js
文件中添加一个新网络:
mainnet: {
provider: function() {
return new WalletProvider(
Wallet.fromPrivateKey(
Buffer.from(PRIVKEY, "hex")), "https://mainnet.infura.io/"+INFURAKEY
);
},
gasPrice: w3.utils.toWei("20", "gwei"),
network_id: "1",
},
幸运的是,这非常简单。它与Rinkeby部署几乎相同;我们只需要移除gas量(让它自己计算)并改变gas价格。我们还应该将网络ID更改为1,因为这是主网ID。
我们这样使用:
truffle migrate --network mainnet
这里有一点需要注意。如果你在先前部署的网络上进行部署(即使你刚刚将代币部署到主网上并希望稍后部署StoryDao),你可能会收到此错误:
Attempting to run transaction which calls a contract function, but recipient address XXX is not a contract address
之所以发生这种情况,是因为Truffle会记住部署已经部署的合约的位置,以便它可以在后续迁移中重复使用它们,从而避免重新部署。但是如果你的网络重新启动(即Ganache)或者你进行了一些不兼容的更改,可能会发生它保存的地址实际上不再包含此代码,因此会报错。你可以通过重置迁移来解决此问题:
truffle migrate --network mainnet --reset
将代币发送到StoryDao地址
从部署过程中获取代币的地址和StoryDao的地址。
然后只需使用前面描述的MEW来发送代币。
如果出现gas缺失,只需增加gas限制即可。请记住:剩余的未使用的gas总是会退回来,所以不用担心会损失比交易成本更多的钱(发送代币应该低于40000gas)。
将代币的所有权转让给StoryDao要转移所有权,我们需要在代币上调用transferOwnership
函数。让我们将代币加载到MEW中。在Contracts
屏幕中,我们输入地址和合约的ABI(从/build文件夹中获取)。然后单击Access
将允许我们在菜单中访问该合约中的功能,我们从中选择transferOwnership
。
提示:仅包含你要调用的函数的ABI就足够了,它不必是代币的整个ABI!你可以只包括transferOwnership
函数的ABI,它就没事了!
然后我们选择新的所有者(已部署的StoryDao的地址)并解锁当前所有者的钱包(我们之前发送的钱包相同的钱包)。
写完此更改后,我们可以检查代币合约中的只读功能owner
(与transferOwnership
相同的菜单)。它应该现在显示新的所有者。
为了确保StoryDao地址实际上有代币,我们可以选择balanceOf
函数并在_owner
字段中输入StoryDao的地址,然后单击Read
:
事实上,StoryDao地址中有1亿个代币。
提示:我们也可以在部署步骤中完成代币发送和所有权转移。尝试弄清楚如何在测试环境中。
验证
根据本系列的第3部分,验证DAO和Etherscan上代币的合约将对我们有很大帮助。绿色的复选标记是一条很长的路。
按照该部分中的说明验证你的合约。请注意,在验证步骤中,你现在必须将优化器标记为活动,因为我们正在优化代码以实现更便宜的部署!
部署到Web
要部署StoryDao的Web UI,请按照“常规”Web开发世界中的说明进行操作。因为,在这种情况下,所有的都是静态代码,你甚至可以在GitHub页面或类似的东西上托管它。
页面启动后,配置UI以使用我们从迁移步骤获得的合约地址。或者,注册代币和StoryDao的ENS名称,你可以保持Web UI静态和固定,硬编码地址,然后只更改ENS名称所指向的以太坊地址。
结论
DAO教程到此结束。我们希望它能帮助你认识到Solidity开发的复杂性,但我们也希望它能让事情更加清晰,让你更加好奇。
一如既往,最好的学习方式就是做。实验,犯错,重启和重建。这种类型的区块链开发需求量很大,而且它越来越受欢迎,所以你有机会接触到底层。
祝好运!
======================================================================
分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:
- java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
- python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
- php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
- 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
- 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
- C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
- EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
- java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
- php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
- tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。
汇智网原创翻译,转载请标明出处。这里是原文以太坊构建DApps系列教程(八):启动StoryDAO