📜 ⬆️ ⬇️

Ethereum Smart Contracts: writing a simple contract for ICO

Recently, I have received a huge number of requests for help in developing a smart contract for an ICO, and I don’t have enough time to help everyone. Therefore, I decided to write this small post (link to the video at the end of the post), in which I describe a very simple smart contract for a crowdsale, which you can use in your projects.



To save time, I wrote a contract in advance. Let's break it down into steps.

Smartcontract is a program written in a programming language. In our case in the language of Solidity. To develop simple contracts, I use the online editor and the Remix compiler.
')
Sign of a good tone is considered to start any program, incl. and smart contracts, with the indication of the license on which it is distributed. In our case, this is the GPL. You can also specify yourself as the author of the contract, of course, if you are not writing a contract for any scam project where you are embarrassed to specify yourself as an author.

/* This file is part of the EasyCrowdsale Contract. The EasyCrowdsale Contract is free software: you can redistribute it and/or modify it under the terms of the GNU lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The EasyCrowdsale Contract is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU lesser General Public License for more details. You should have received a copy of the GNU lesser General Public License along with the EasyCrowdsale Contract. If not, see <http://www.gnu.org/licenses/>. @author Ilya Svirin <i.svirin@prover.io> */ 

Immediately after comes the line that indicates which version of the compiler should be used. If this line is not, then the smart contract will not compile.

 pragma solidity ^0.4.0; 

Next comes the source code of the smart contract itself, which I structured as a hierarchy of contracts, each of which implements the complete functionality. This simplifies the understanding and subsequent use of the code in your contracts.

First of all, it should be understood that after downloading a smart contract to an Ethereum virtual machine, you will interact with it on a common basis, like all other users. It is logical that we, as a project team, would like to be in privileged conditions, which should at least be expressed in the fact that the contract should form precisely on command tokens and, of course, gave us the collected broadcast. For this, the contract must know its owner and the “owned” contract is responsible for this.

 contract owned { address public owner; function owned() payable { owner = msg.sender; } modifier onlyOwner { require(owner == msg.sender); _; } function changeOwner(address _owner) onlyOwner public { owner = _owner; } } 

The "owned" contract contains only one public field "owner", the value of which is initialized in the constructor by the value of the "sender" field of the global structure "msg", thus, initially the owner of the contract becomes the one who implemented it.

It is logical to foresee the possibility of changing the owner in case our private key is compromised; for this, the “changeOwner” function is provided, which receives the address of the new owner as a parameter. It should be paid to the modifier «onlyOwner», which is defined within the same smart contract. Modifiers are a very convenient design that allows you to group and assign a name to the conditions for calling functions of a smart contract. The “onlyOwner” modifier checks that the function is called from the address that is stored in the “owner” field.

The “owned” contract is fully operational and extremely simple, but it carries one hidden threat, because by calling the “changeOwner” function, we can mistakenly specify a non-existent address, which means we lose control over the contract. To correct this deficiency, it is enough to enter another field, call it “candidate”, and when calling the function “changeOwner” we will save the new value first to “candidate” and move it to “owner” as soon as the candidate confirms his entry into the rights by calling the "confirmOwner" function from your address.

The next contract in the hierarchy, Crowdsale, is directly responsible for collecting funds and issuing tokens, and inherits the previously owned owned contract.

 contract Crowdsale is owned { uint256 public totalSupply; mapping (address => uint256) public balanceOf; event Transfer(address indexed from, address indexed to, uint256 value); function Crowdsale() payable owned() { totalSupply = 21000000; balanceOf[this] = 20000000; balanceOf[owner] = totalSupply - balanceOf[this]; Transfer(this, owner, balanceOf[owner]); } function () payable { require(balanceOf[this] > 0); uint256 tokensPerOneEther = 5000; uint256 tokens = tokensPerOneEther * msg.value / 1000000000000000000; if (tokens > balanceOf[this]) { tokens = balanceOf[this]; uint valueWei = tokens * 1000000000000000000 / tokensPerOneEther; msg.sender.transfer(msg.value - valueWei); } require(tokens > 0); balanceOf[msg.sender] += tokens; balanceOf[this] -= tokens; Transfer(this, msg.sender, tokens); } } 

Special attention should be paid to the following elements of the contract:


All these three elements are one, they are a mandatory part of the ERC20 standard, which must be observed so that the information about our tokens is correctly displayed in the wallets of users and etherscan.io.

The designer of the smart contract "Crowdsale" is extremely simple. First of all, the value of the “totalSupply” field is initialized. Our contract issues 21 million tokens, of which 20 million will be immediately transferred to the smart contract balance. We assume that the tokens from the address of the smart contract are available for sale. The remaining tokens, in our case 1 million, will be written to the address of the owner of the contract. Well, at the end of the constructor, the “Transfer” event is emitted, which is placed on the blockchain and informs contract users that a corresponding number of tokens have been transferred from the balance of the contract to the balance of the contract holder. It is the emission of this event that allows etherscan.io to correctly display tokens holders and their balances.

Well, the most important function of the smart contract is “Crowdsale”, the so-called fallback function, which is called every time the air arrives at the address of our smart contract. At the very beginning, a check is made that there is at least some number of tokens for sale on the smart contract balance. Next, set a fixed price of tokens - 5000 pieces for 1 air. Then we calculate how many tokens must be sent to the sender. The number of funds transferred in the transaction is recorded in the “value” field of the global structure “msg” and it is indicated in “wei”, therefore, when determining the number of tokens, we translate “wei” into “ether”.

Then a check is made that there is a sufficient number of tokens on the balance of the smart contract. If more tokens are requested than the smartcontract has, then we will transfer all the remaining tokens. We determine the cost in “wei” of the remaining tokens and return to the sender the over-translated air. We make sure that the number of purchased tokens is non-zero, after which we record this number of tokens on the balance of the buyer and deduct them from the balance of the smart contract. At the end, don't forget to emit the Transfer event.

This is where the actual implementation of the fundraising functionality is completed, but now we need to make our token operable and implement some more features of the ERC20 standard. This is done in the “EasyToken” contract, which is inherited from the previously reviewed “Crowdsale” contract.

 contract EasyToken is Crowdsale { string public standard = 'Token 0.1'; string public name = 'EasyTokens'; string public symbol = "ETN"; uint8 public decimals = 0; function EasyToken() payable Crowdsale() {} function transfer(address _to, uint256 _value) public { require(balanceOf[msg.sender] >= _value); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; Transfer(msg.sender, _to, _value); } } 

First of all, we will define 4 public fields, which are now practically not used by any wallets, but for the order we will nevertheless define them. Here we indicate the full and abbreviated name of the token, as well as the number of fractional characters. In our case, the token is indivisible, because the value of the decimals field is set to 0.

And finally, the only smart contract function “EasyToken” for which we created this contract is “transfer”, which is also part of the ERC20 standard and will allow users' wallets to transfer tokens to each other, transfer them to the stock exchange and withdraw them. The implementation of the function is extremely simple, the sufficiency of the number of tokens on the balance of the sender is checked, after which the balance of the sender decreases, and the balance of the recipient increases by the requested number of tokens. At the end, the “Transfer” event is emitted. Now our token is operable and it remains to do the most important thing - to give the contract holder the opportunity to withdraw the collected airs. We will do this in the “EasyCrowdsale” contract.

 contract EasyCrowdsale is EasyToken { function EasyCrowdsale() payable EasyToken() {} function withdraw() public onlyOwner { owner.transfer(this.balance); } } 

The “withdraw” function has an “onlyOwner” modifier, i.e. can only be called by the owner of a smart contract. The only thing she does is transfer the entire balance of the smart contract to the address of the owner of the smart contract.

Despite the fact that the considered smart contract is fully functional and workable, I would not recommend using it in a real project. Excessive simplification of the contract logic has led to the fact that such a contract does not adequately protect the interests of investors, namely, it does not set the deadline for crowdsale, does not set the minimum collection limit, does not return funds to investors in case the minimum limit is not reached, and also contains a number of known Vulnerabilities at the level of the compiler language Solidity, for example, is subject to the so-called short address attack.

Many of these shortcomings are eliminated in the smart contract of our PROVER project. The PROOF contract is uploaded to Ethereum at this address along with the source code, which can be found. You can even check how the contract works, by sending a real broadcast to it, right now we are having Pre-ICO :). In fact, we will be happy if you join the presale of our PROVER project, which will last until the end of September. PROVER is a unique technology for verifying the authenticity of video materials based on blockchain and video analytics.

Useful links:

Source: https://habr.com/ru/post/338084/


All Articles