如何在5分钟内为ICO编写智能合约



大家好! 在本文中,我将告诉您如何在5分钟内在以太坊上启动ICO的智能收款合同,并在终端中执行几个命令。 本文将为您节省数万美元,因为任何程序员(而不是程序员)都可以启动经过审计且安全的智能合约(而不是支付15,000美元至75,000美元的开发费用)。 简而言之,您可以向该智能合约汇款,并为其接收ERC20令牌。 可以说,本文是我通过为项目启动ICO获得的所有经验的集合。

在Internet上,您的这些书中已经充斥着有关智能合约的文章,但是一旦您开始撰写有关智能合约的文章,就会发现一个事实,即信息无处不在,并且根本没有关于如何欺骗ERC20的教程,或者它们已经过时了。 顺便说一下,为了使本文保持相关性,我将尝试指出它可能已过时的潜在位置(以及解决方法)。 走吧

坚固性


这是开菲尔团队开发的用于启动智能合约的主要语言的名称。 如果您是一名程序员,那么只需遍历该语言文档 -这很简单。 顺便说一句,他们简化了工作,因此在编写智能合约时更容易出错。 因此, 绝对是任何程序员,至少是初级的程序员,都可以弄清楚这一点。 向知道稳定性的开发人员支付巨额资金绝对没有意义-培训现有开发人员会便宜一个数量级。

智能合约


...以及您需要了解的所有信息。 如果您不是程序员,请跳过本节。 智能合约是一段代码。 原则上,这是实体类(OOP,是),它具有两种类型的功能:状态更改和非状态更改。 好吧,为了仅通过向其发送开菲尔在智能合约中运行功能,就需要将此功能标记为payable功能。

国家是一个数据仓库,区块链,EPT。 合同可以更改区块链(状态,存储)-但是要更改区块链,您需要向开采矿者支付开菲尔。 在本文的框架中不会分析他们如何分享开菲尔。 向矿工支付运行状态更改代码的费用称为天然气。 如果有人从外部将开菲尔扔到智能合约的地址上,并且调用了一个标记为payable但未标记为ConstantViewPure的函数,那么将从发送的金额中扣除开菲尔支付给矿工的必要金额。 通常,在ERC20令牌中,这些功能要么发出开菲尔的令牌发送者,要么将令牌从一个令牌持有者转移到另一个令牌持有者。

而且,如果您在合同中用“ Constant或“ View (它们表示相同的内容,它们只允许您读取状态)或“ Pure (相同的内容,甚至不读取状态)字样标记功能,那么您甚至不需要在该功能上花费开菲尔! 我什至还要说更多的是这些功能不需要通过事务来调用-毕竟,任何酸奶客户理论上都可以在家执行它-而且没有人需要知道这一点(毕竟,什么都没有写到区块链上)。

稳固性有两个重要方面:多重继承和函数修饰符。 您还需要了解它们。

第一个合同可以同时从多个类(如TimedCrowdsaleCappedCrowdsaleMintedCrowdsaleOwnable继承,同时,构造函数的功能也会一个接一个地启动-但我将在后面举例说明。

第二个是创建功能的能力,然后将这些功能插入其他功能。 就像简单的封装一样,只是稍微灵活一点-它实际上是一个函数模板 。 创建修饰符时,请写特殊字符_ ,表示使用该修饰符的函数代码。 也就是说,修饰符不仅仅是返回值的封装功能。 当使用修饰符将字面意义上的修饰符代码插入函数时,这是一个函数模板。

让我们继续练习。

烹饪环境


如果您不知道终端机是什么,请在此处阅读本文 。 如果您在Windows上,请通过WLS设置终端。 如果您已经熟悉终端,让我们继续。 另外,立即将自己放到 Node.js中-接下来的步骤将是必需的。 最好安装LTS,但实际上,安装哪种现代版本没有什么区别。

我们立即安装并启动块同步过程的第一件事是geth 。 简而言之,这是一个用Go编写的实用程序,它将使我们能够在本地计算机上运行以太节点,并连接到测试和真实网络。 您可以通过安装程序进行安装 ,但我强烈建议您立即在Terminal中安装,如此处所述。 您可以geth在终端中运行以下命令来检查您的geth标准是否geth

 geth version 

如果您不喜欢geth版本-一切都在镂空中,请继续学习本教程。 如果不是-不好,请纠正; 看来您必须与终端机和操作系统做爱-但这不是您第一次了解它。 如何安装geth,在终端中运行命令:

 geth --testnet console 

这将启动将节点与测试服务器同步的过程,可以在此处查看其块。 您可以通过以下命令在geth控制台中检查是否与网络同步:

 eth.blockNumber #  0 —     eth.syncing #     false,     

同步过程使我花了1到4个小时-什么时候开始。 另外,除了块同步之外,您还必须等待状态同步-它通常比块同步长。 您还可以将geth--light标志一起使用-然后同步持续几秒钟到一分钟,您仍然可以部署合同。

好的,我们安装了第一个实用程序-放下一个。 我们需要模拟一个geth的模拟,只是一个非常本地的testrpc链模拟testrpc 。 是的,我们有3个区块链

  • testrpc本地testrpc链模拟; 快速,但是伪造的,仅存储在您的计算机上
  • geth --testnet已经是一个真正的geth --testnet链,但是您不会在这里亏损,可以免费获得开菲尔和测试geth --testnet
  • geth-主网,主,真实区块链,真实开菲尔; 都是以成人的方式,这里的错误是真正的开菲尔酒的损失

因此,我们将使用testrpc启动测试合同,然后将其安装在geth --testnet ,然后直接在geth下载它。

我们通过运行以下命令来testrpc

 npm install -g ethereumjs-testrpc 

好吧,或者它随松露一起上升,因为现在testrpc 在松露翼下 ,被称为ganache-cli 。 尽管魔鬼知道,但使用vanilla testrpc一切testrpc 。 而且如果它可行,请不要触摸它,就像我在银河系学院所教过的那样。 您也可以通过在控制台中注册truffle来运行它以验证安装,但是测试区块链已经与我们同步-让我们不要打扰它。

好了,找出了区块链吗? 现在有节点并且测试甚至是同步的? 我们使用以下命令在kefir- truffle上放置了一个方便的实用程序来处理智能合约:

 npm install -g truffle truffle version #  ,  ,   

松露是一种工具,可让您将智能合约保存在不同的文件中,导入其他文件,并将智能合约代码编译为一个大字节码(人无法读取),它会自动查找本地运行的geth (测试和真实) )或testrpc ,将智能合约部署到该网络。 此外,检查您的智能合约代码中是否有错误,并且最近完成的交易也有助于调试 。 简而言之,刊头。

在这一阶段,您应该已经安装: testrpcgethtestrpc -如果其中任何一个丢失或版本未根据要求吐出到控制台,则请更正此错误。 否则,您将不会成功。

另外,我抛出了一个简单的bash脚本 ,它将为您安装所有内容。 这样称呼:

 source <(curl -s https://raw.githubusercontent.com/backmeupplz/eth-installer/master/install.sh) 

-但我尚未对其进行测试,因此我不确定其性能。 不过,我很乐意提出要求。

菲加什合同


一切都已经发明出来,可以为您编写-很好。 一点点彩旗都是一样的-但我会尽力将其最小化。 我们将使用来自OpenZeppelin的现成的ERC20合同 -这已成为行业标准,它们已通过审核,并且确实都使用了其代码。 非常感谢您对开源的贡献。

使cd进入一些安全文件夹,然后输入:

 mkdir contract && cd contract 

在此文件夹中,我们将工作。 在此处为我们的智能合约创建存根:

 truffle init 

清楚地跌倒了。 现在,我们有两个非常重要的文件夹可供选择: contractsmigrations 。 第一个是我们合同的代码,第二个是松露的代码,以了解将合同部署到区块链时该怎么做。

接下来,我们需要从npm中获取当前的智能合约代码,并且实际上启动项目本身:

 npm init -y #     ( -y) npm install -E openzeppelin-solidity #       ( -E) 

好吧,来自OpenZeppelin的智能合约代码位于我们的口袋中的node_modules/openzeppelin-solidity/contracts文件夹中。 现在,我们转到主contracts文件夹,删除其中的所有文件,然后添加文件MyToken.solMyCrowdsale.sol自然,您将以不同的方式命名合同。 第一个将是我们的ERC20代币的合同,第二个将是我们的ICO的合同,它将接受开MyToken并将MyToken人们。 本文可能已过时,但是您始终可以查看OpenZeppelin如何建议您在其存储库中创建合同。 这就是MyToken.sol样子:

 pragma solidity ^0.4.23; // Imports import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol"; // Main token smart contract contract MyToken is MintableToken { string public constant name = "My Token"; string public constant symbol = "MTKN"; uint8 public constant decimals = 18; } 

不错-您拥有自己的令牌智能合约(只需更改常量中的名称)! 您可以看到MintableToken有什么MintableToken继承-但是那里的一切都尽可能简单。 这是可以发行的令牌(从英文“ Mint”到薄荷),并且只有所有者才有权发行,因为MintableToken也是从Ownable继承的。 另外, MintableToken还继承了OpenZeppelin编写的ERC20令牌类,其中实现了ERC20接口:

 contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } 

是的,这里您拥有整个ERC20界面。 有困难吗? 我不这么认为。 它使您有机会查看发出的令牌数量,检查地址余额并通过为网络上的轻质开菲尔客户吐出转移事件来将令牌转移到另一个地址。 由于MyToken.sol的工作,您可以在MyToken.sol免费获得所有这些功能-它们很棒。

现在让我们继续进行ICO的主要部分-我们需要接受开MyToken并发出MyToken ! 这是您的MyCrowdsale.sol样子:

 pragma solidity ^0.4.23; // Imports import "../node_modules/openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/crowdsale/distribution/RefundableCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol"; contract MyCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale { constructor( uint256 _openingTime, uint256 _closingTime, uint256 _rate, address _wallet, uint256 _cap, MintableToken _token, uint256 _goal ) public Crowdsale(_rate, _wallet, _token) CappedCrowdsale(_cap) TimedCrowdsale(_openingTime, _closingTime) RefundableCrowdsale(_goal) { //   ,  ,    // ,     require(_goal <= _cap); } } 

一般般,我们怎么了? 什么,男孩,智能合约? 我们的代币公开销售继承了三个最受欢迎的属性:它具有硬上限,无法再收集; 软顶,不收集返回的酯类; 代币销售开始和结束的时间。 事实上,幸福还需要什么?

程序员请注意,如何将多个继承类的构造函数排成一行,并从MyCrowdsale的主要构造函数获取参数。 另外,我们检查硬键是否高于软键-Ales Gut! 同样,不要被MyCrowdsale构造函数中MyCrowdsale参数所MyCrowdsale -我们将在松露中的合同部署阶段传递它们。

仅此而已-您拥有自己的ERC20代币的现成合同,甚至还有ICO智能合约,该智能合约均根据您的需求进行配置,并为开菲尔提供代币。 而且,所有ERC20钱包都支持它-一个大错! 让我们继续进行手动测试和部署。

移居


正如我之前所说,我们将在三个区块链网络上进行顺序测试,但是使用笔进行测试的过程将始终相同。 让我们从testrpc开始,然后进入geth --testnet并继续geth 。 搜大灯,我们只是编写了代码,让我们尝试对其进行编译。 在项目文件夹中,输入:

 truffle compile 

如果一切编译都没有问题,那么您将看到build ,其中将包含松露的krakozyab,以便它将智能合约的字节码嵌入到区块链中。 在部署智能合约之前,我们需要告诉松露该做什么。 智能合约的松露部署称为迁移-好吧,让我们坚持这个术语。 转到migrations/1_initial_migration.js并按以下方式进行更改:

 const token = artifacts.require("../contracts/MyToken.sol"); const crowdsale = artifacts.require("../contracts/MyCrowdsale.sol"); module.exports = function(deployer, network, accounts) { const openingTime = 1514764800; // 15  2018 const closingTime = 1561939200; // 1  2019 const rate = new web3.BigNumber(1); // 1   1  const wallet = '0x281055afc982d96fab65b3a49cac8b878184cb16'; // - const cap = 200 * 1000000; //  const goal = 100 * 1000000; //  return deployer .then(() => { return deployer.deploy(token); }) .then(() => { return deployer.deploy( crowdsale, openingTime, closingTime, rate, wallet, cap, token.address, goal ); }) .then(() => { // Crowdsale    var tokenContract = web3.eth.contract(token.abi).at(token.address); web3.eth.defaultAccount = web3.eth.accounts[0]; tokenContract.transferOwnership(crowdsale.address); }); }; 

松露将使用该文件来部署合同。 那我们在这里做什么? 首先,我们要求编译MyTokenMyCrowdsale 。 之后,我们使用ICO的所有参数设置常量-设置开始和结束时间; 人们将获得1千开菲尔的代币数量(0.000000000000000001 eth = 1 wei;设置decimals表示获得1个新制作的代币需要多少wei); 从销售中获得的开菲尔的钱包; 硬顶和软顶。 请注意, openingTime应该始终在区块链中当前块的时间之后–否则,由于检查TimedCrowdsale的条件,您的智能合约将不会被阻止。 我踩了一把耙子,失败的交易根本无法扣账。 根据需要更改这些常数。

下一步就是部署智能合约。 这里没什么有趣的:我们有一个deployer对象,该对象部署智能合约工件并在此处传递参数。 请注意,首先MyToken MyToken,然后才MyToken MyCrowdsale-第一个的地址在第二个作为参数传递。

然后,最有趣的是他们在文档或书籍中没有写的内容。 当您从钱包创建MyToken ,此钱包将成为Ownable超类中MyToken的所有者MyToken Ownable发生相同的情况。 如果深入研究MintableToken ,您会看到只有Owner才能铸造硬币! 谁是MyToken的所有者? 是的:让他不高兴的地址。 谁将发送铸造硬币的请求? 正确: MyCrowdsale智能合约。 让我提醒您,创建MyTokenMyCrowdsale的地址是两个不同的地址。

因此,我们将添加非正统的第三部署步骤,在该步骤中,已web3.eth.accounts[0]的地址( web3.eth.accounts[0] )调用MyToken合同上的transferOwnership函数, MyToken MyCrowdsale拥有MyToken并可以铸造硬币。 而且MyCrowdsale仍然是web3.eth.accounts[0]的所有者-因此,所有内容都捆绑在一起。

关于web3.eth.accounts[0]注意事项:部署智能合约时,请确保geth或testrpc在web3.eth.accounts[0]具有正确的钱包-不要丢失私钥,尽管这不会以任何方式伤害您,但是突然,所有者将需要稍后再做一些事情,但是钥匙不再在那里了?
testrpc ,在testrpc ,帐户在启动时立即创建并立即解锁。 但是,在测试和真实的区块链上,值得通过personal.newAccount()创建一个帐户-然后通过测试区块链上的Faucet或真实区块链上的真实开菲尔来补充该地址。 不要丢失密码和私钥。
另外,您可以通过调用web3.personal.importRawKey('pvt_key', 'password')将现有的钱包添加到您的帐户,但是为此,您需要使用附加参数--rpcapi="db,eth,net,web3,personal,web3" 。 我想您会发现的。

测试与部署


是的,合同已准备就绪,已编写迁移,仅保留以进行部署和检查。 geth (test和real)和testrpc通过truffle console以相同的方式testrpc管理-因此,我将介绍testrpc的验证方法,只告诉您之后如何启用geth 。 因此,我们启动了测试本地开菲尔区块链:

 testrpc 

嗯...仅此而已。 您在本地模拟开菲尔区块链。

为了将其部署到测试以太区块链,而不是此命令,您将得到geth --testnet --rpc 。 为了部署到以太geth --rpc的真实geth --rpc链中,您只需geth --rpc 。 需要--rpc标志,以便松露可以连接。 对于所有三种类型的区块链,以下部署和测试步骤大致相同。 唯一的事情是,通过geth运行测试或真实的区块链之后,它将开始同步块-在良好的Internet连接上,这可能需要多达4-5个小时。 关于此的评论是在本文的开头。 部署智能合约之前,建议您等待完全同步。 此外,区块链的重量约为60-100 GB,因此请为此准备磁盘空间。
同样,请确保web3.eth.accounts[0]解锁。 通常,您可以在立即打开的控制台中或通过geth console打开的控制台中的单独终端窗口中注册testrpceth.unlockAccount(eth.accounts[0], ", ", 24*3600) -这将解锁您的帐户,这应该创建一个智能合约

现在打开一个新的终端窗口( testrpc不关闭testrpc它应该可以工作)并将其写入项目文件夹中:

 truffle migrate --reset 

这个魔术命令将编译一个智能合约(也就是说,您不需要每次都编写truffle compile )并将其部署到本地开放的区块链微服务器上。 值得注意的是,如果testrpc立即执行此操作,则测试和实际区块链将在更长的下一个区块中包含交易。 之后,您应该在控制台中吐出以下内容:

 Using network 'development'. Running migration: 1_initial_migration.js Running step... Replacing MyToken... ... 0x86a7090b0a279f8befc95b38fa8bee6918df30928dda0a3c48416454e2082b65 MyToken: 0x2dc35f255e56f06bd2935f5a49a0033548d85477 Replacing MyCrowdsale... ... 0xf0aab5d550f363478ac426dc2aff570302a576282c6c2c4e91205a7a3dea5d72 MyCrowdsale: 0xaac611907f12d5ebe89648d6459c1c81eca78151 ... 0x459303aa0b79be2dc2c8041dd48493f2d0e109fac19588f50c0ac664f34c7e30 Saving artifacts... 

我认为您已经意识到控制台已为您提供了智能合约MyTokenMyCrowdsale的地址。 仅此而已! 智能合约嵌入在您已打开微服务器的区块链中。 仅需验证令牌是否已真正分发给将开MyCrowdsale发送给MyCrowdsale智能合约的用户。 我们在终端中输入以下内容以进入松露控制台:

 truffle console 

我们在现在的松露中写下以下内容(仅无评论):

 //   - t="0x2dc35f255e56f06bd2935f5a49a0033548d85477" //     MyToken ="0xaac611907f12d5ebe89648d6459c1c81eca78151" //     MyCrowdsale //   - token=MyToken.at(t) crowdsale=MyCrowdsale.at(c) //       account=web3.eth.accounts[0] // ,      token.balanceOf(account) //   0 //    - web3.eth.sendTransaction({from: account, to:c, value: web3.toWei(0.1, 'ether'), gas: 900000}) 

在这种情况下,testrpc您可以立即再次检查我们钱包的余额,但是在测试和真实区块链的情况下,您需要等待直到我们的交易被包含在区块中-通常在这种情况发生时,松露为您提供交易号。你等了吗再次检查我们的余额MyToken

 // ,      token.balanceOf(account) //     

仅此而已!首先在上测试您的合同testrpc,然后在上进行测试,然后在上geth --testnet进行部署geth。因此,您启动了自己的ICO!而且,您不必花费数十万美元来进行审核和发布。搞砸OpenZeppelin的家伙为我们提供的东西实际上是非常困难的。而且,当您使用它时truffle,这就是团结发展通常变成童话故事的方式。好吧,除了在智能合约执行过程中交易发生逆转的情况外,请首次亮相。但是,智能合约的调试确实值得单独写一篇文章。

结论


非常感谢您阅读本文结尾!如果我设法节省您的时间或金钱,或者您从本文中学到了新的知识,那么我将对此感到非常高兴。如果您与想进行ICO的朋友或熟人分享这篇文章,我也将不胜感激-为那些从寄生虫等领域从加密货币市场吸取金钱,复制粘贴相同25行代码的编程人员节省75,000美元。

开发智能合约的好运!还有问题吗?我想在评论中问您-我很乐意回答所有问题,并尝试解决问题。

红利


但是,如果您想改变考虑代币购买价格的逻辑怎么办?当然,您可以正确地更改它,也可以rate使用OpenZeppelin的其中一类合同,但是如果您想要更变态的东西怎么办?在智能合约中,您可以getTokenAmount按以下方式覆盖该功能

 function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) { if (block.timestamp < 1533081600) { // August 1st, 2018 rate = rate * 4; } else if (block.timestamp < 1546300800) { // January 1st, 2019 rate = rate * 2; } return _weiAmount.mul(rate); } 

通常,这会使令牌的价格取决于购买时间-进入森林越远,令牌就越昂贵。不要害怕尝试并重写智能合约的某些功能-这很有趣!

Source: https://habr.com/ru/post/zh-CN414493/


All Articles