以太坊构建DApps系列教程(八):启动StoryDAO

在本系列关于使用以太坊构建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

1
2
3
4
5
function bigRedButton() onlyOwner external {
active = false;
withdrawToOwner();
token.unlockForAll();
}

然后,让我们可以在代币合约中立即解锁所有代币:

1
2
3
4
5
6
7
8
9
/**
@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;
}
}

当然,我们需要在合约中添加这个新的地址列表:

1
address[] touchedByLock;

我们需要升级我们的increaseLockedAmount函数以向此列表添加地址:

1
2
3
4
5
6
7
8
9
10
11
12
/**
@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合约中代币所需的接口,以包含这个新函数的签名:

1
2
3
4
// ...
function getUnlockedAmount(address _owner) view public returns (uint256);
function unlockForAll() public;
}

使用我们之前添加的活动故事块(除非故事的active标志为真,否则无法运行某些功能),这应该可以解决问题。没有人需要在发送合约时浪费钱,每个人的代币都会被解锁。

所有者没有得到人们提交的以太。取而代之的是退出功能变得可用,因此人们可以收回他们的以太,并且每个人都会得到照顾。

现在我们的合约终于可以部署了。

销毁程序是什么样的?

有一个名为selfdestruct的函数可以销毁合约。它看起来像这样:

1
selfdestruct(address);

调用它将禁用有问题的合约,从区块链的状态中删除其代码并禁用所有功能,同时将该地址中的以太网发送到提供的地址。在我们的案例中,这不是一个好主意:我们仍然希望人们能够撤回他们的以太;我们不想从他们那里拿走它。此外,直接发送到自杀合约地址的任何以太币将永远丢失(烧毁),因为没有办法将其取回。

部署合约

要完全部署智能合约,我们需要执行以下操作:

  • 部署到主网
  • 将代币发送到StoryDAO地址
  • 将Token合约的所有权转让给StoryDao。

我们走吧。

主网部署

要部署到mainnet,我们需要在truffle.js文件中添加一个新网络:

1
2
3
4
5
6
7
8
9
10
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。

我们这样使用:

1
truffle migrate --network mainnet

这里有一点需要注意。如果你在先前部署的网络上进行部署(即使你刚刚将代币部署到主网上并希望稍后部署StoryDao),你可能会收到此错误:

1
Attempting to run transaction which calls a contract function, but recipient address XXX is not a contract address

之所以发生这种情况,是因为Truffle会记住部署已经部署的合约的位置,以便它可以在后续迁移中重复使用它们,从而避免重新部署。但是如果你的网络重新启动(即Ganache)或者你进行了一些不兼容的更改,可能会发生它保存的地址实际上不再包含此代码,因此会报错。你可以通过重置迁移来解决此问题:

1
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