Do you have an excellent idea for an app? Maybe you want to establish a new, groundbreaking startup? Probably the first problem on your way to success will be to collect enough amount of money.
Okey but it’s not only your problem and a lot of people managed to do it before. So you can ask ‘Uncle Google’ for help. For sure one of the first results will be to organize an ICO. But what is it?
What is more I want to cover more technical part to show how it works, which could be interesting for people who want to learn the Ethereum technology.
ICO
ICO (Initial Coin Offering) is a mechanism which allows you to collect cryptocurrency like BitCoin or Ether in exchange for your cryptocurrency or crypto-tokens. Simply speaking, it’s just an easy, based on popularity of cryptocurrencies, way to collect money from investors. You receive cryptocurrency and offer your token which maybe will have a real value in the future or will be just a souvenir for investors.
I want to show you what is behind most of ICOs now.
Bitcoin, cryptocurrencies, blockchain, Ethereum, …
You must have heard about Bitcoin and cryptocurrencies. And it’s not only the lines on the graph that make you lose when it goes down or earn when it raises. Behind it there is an interesting algorithm which goal is to make it trustworthy and secure. It turns out that using the same approach we can do more than only transferring coins. And as always in IT world, when there is a need, there is a group of people that prepare a framework for it.
Probably in this way Ethereum was born. Ethereum uses similar technologies to BitCoin, it simplifies exchanging everything in a way that BitCoin does it with coins. Of course it’s not the only tool to do it, but nowadays it is the most popular one.
Behind Ethereum (and BitCoin)
Personally, I hate using technology not knowing what is behind it. So this is a really brief description how it is realized. You can skip it if you already know, for example, how BitCoin/Ethereum works.
Blockchain
Really catchy word now. But it is just a way of holding information using, not surprisingly, a chain of blocks. The main idea is to decentralize everything to eliminate a person or an institution which we have to trust in (for example in the traditional banking we have to trust a bank). In this concept everybody has a copy of a database so everything is transparent and there isn’t a single person who can manipulate records in this database. If somebody did it, other users would reject his change. How is it realized? Using a simple one-directional list and a handful of cryptographic algorithms. Changes are added as the next block.
Mining
But how it is added? If we want to change something (make a transaction) we have to broadcast it to all other nodes in the Ethereum network. Then there are some special nodes called miners. Their task is to verify transaction and use some computational power to find an answer for a puzzle to confirm block of transactions. The first miner, that solves this, will receive a prize. And it makes it really hard to add manipulated block, because the potential attacker would have to have more computational power than the rest of the network, what is really expensive.
Keys
To confirm that you are you there is used pair of keys – private and public one. You sign transactions using the private key and then everybody can check that is was you using your public key. Nothing more than typical cryptographic algorithm, but it ensures than nobody can make transaction on your behalf.
Smart contracts (not in BitCoin)
It is a thing which differs Ethereum from BitCoin. Smart contracts are just a piece of code which determines the behavior of a program. Because of it (and because of the blockchain) we can be sure that it always executes in the way that a developer has written it. We know its code (like in real-world contract) so nobody can manipulate and change conditions of the agreement. It enables us to make transactions even with people that we doesn’t know.
JSON RPC
Code must be executed on every node. RPC stands for “Remote Procedure Call” and JSON RPC is just a way of transferring information through the nodes. It uses JSON as a format of data and HTTP as a protocol for communication between nodes. Because of it we can make transactions from every programming language. Of course there is a plenty of libraries which simplify doing it.
When we sum it up we receive the framework for decentralized applications in which everything is obvious and which promotes itself as a possibility to create stoppable and trustless apps (or code-trust to be precise).
How to create it?
Let’s make two most typical things in Ethereum – a token and an ICO. Ethereum uses a language called Solidity to write smart contracts. I won’t go into details of the syntax, I believe that it is pretty self-explanatory, even for a non-technical person.
Token
It is so popular and widely-used that there are even standards ‘how to create token’. But let’s start from the simplest implementation:
contract Token { mapping(address => uint) private balances; function balanceOf(address owner) public view returns (uint) { return balances[owner]; } function transfer(address to, uint amount) public returns (bool) { require(balances[msg.sender] >= amount); balances[msg.sender] -= amount; balances[to] += amount; return true; } }
I believe that this is really clear. We have a book (map technically speaking) called ‘balances’, where we keep current amount of coins for every account. We can check the current balance using the balanceOf() function. And the transfer() function in which we can give somebody some coins just by removing from our account and adding to theirs. Simple and insecure.
Problems
Coins from the air?
We can now exchange coins but we have to pose a question: ‘What was at the beginning?’. We have to setup an initial balance. There are two common approaches to do it: setup an initial balance which is immutable or add a mint function which only the owner of the token can invoke. Below there is the first way.
contract Token { uint private totalSupply; constructor(uint _initialAmount) public { totalSupply =_initialAmount; balances[msg.sender] = totalSuppply; } ... }
Long-time problem – overflows
The type uint in Solidity have 256 bits so it can hold really big numbers. But not infinite ones. There were a lot of attack based on integer overflow. To prevent it we can use SafeMath library which checks overflows for us. Typically zeppelin’s one.
contract Token { using SafeMath for uint; ... function transfer() public return (bool){ require(balances[msg.sender] >= amount); balances[msg.sender] = balances[msg.sender].add(amount); balances[to] = balances[to].sub(amount); return true; } }
Sending to contracts
One more problem occurs when we send tokens to contracts. There is a big possibility that they won’t be able to handle them. Then our coins will be stuck in this contract forever. And that leads us to tokens’ standards.
Token standards
The Ethereum community have established a lot of standards which determine functions that coins implementations should have.
ERC20
This is the basic token standard which can be recognized by other apps. Besides the basic functionality it also supports functions like approve() and transferFrom() which enable us to delegate an address that will be able to manage part of our wealth for us. It is a little bit deprecated because of the problem with sending tokens to contract. Here is the interface which contract should implement to follow this standard:
interface ERC20 { function totalSupply() external view returns (uint256); function balanceOf(address _who) external view returns (uint256); function allowance(address _owner, address _spender) external view returns (uint256); function transfer(address _to, uint256 _value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 _value) external returns (bool); }
ERC223
This standard comes as extensions to ERC20 that resolves problem with sending coins to contracts. Additionally, it is fully compatible with the previous standard. It blocks sending coins to contracts by previous transfer() and transferFrom() functions and adds a transfer function that allows to send coins only to contracts which have a tokenFallback() function and are able to handle this request.
interface ERC223 is ERC20 { function transfer(address _to, uint256 _value, bytes32 _data) public returns (bool); }
interface ERC223Receiver{ function tokenFallback(address _from, uint256 _amount, bytes32 _data) public; }
ERC827
It is also a fully-compatible extension for ERC20 but it allows user, who makes a transfer, to call any function of receiving contract, not only tokenFallback() one. It sounds great but it could be hard to implement all receiving contracts securely. It is realized through the _data argument which can be the name and arguments for a next function.
interface ERC827 is ERC20 { function approveAndCall(address _spender, uint256 _value, bytes _data) public payable returns (bool); function transferAndCall(address _to, uint256 _value, bytes _data) public payable returns (bool); function transferFromAndCall(address _from, address _to, uint256 _value, bytes _data) public payable returns (bool); }
ERC721
This standard is a little bit different from the previous. Tokens followed it are non-fungible. It means that one token cannot be just replaced by another. For example if you collect stamps, one from Warsaw will be different than one from Cracow, even though both are just ‘one stamp’.
Full implementation
Let’s connect everything now. In my opinion the best standard for typical token is ERC223, but it can depend on what you want. There is a lot of token templates you can just use to implement your token in a few lines of code. I decided to use the openzeppelin’s implementation of the ERC20 token and extend it for functionality of the ERC223 standard.
The full implementation is here.
At the beginning we can see 3 parameters: name, symbol and decimals. First two are self-explanatory, the last one is an information how your token is divisible, and how many numbers should be shown after comma in wallet apps.
ICO
With this very basic knowledge we can start implementing an ICO.
Basic implementation
This time let’s begin with a bunch of basic parameters:
contract ICO{ using SafeMath for uint; Token token; address owner; uint startBlock; uint endBlock; uint price = 0.001 * 10 ** 18; constructor(address _token, address _owner, uint _startBlock, uint _endBlock) public { token = Token(_token); owner = _owner; startBlock = _startBlock; endBlock = _endBlock; } }
Our ICO needs to have an access to instance of our Token to be able to transfer coins. After deploying the contract we will receive address of it and then we will be able to enter it here. What is more our campaign should be time-limited. To achieve it we add variables startBlock and endBlock, because, as I wrote earlier, changes are passed when miner broadcast a block and all blocks have the next number. Approximately new block is mined every 15 seconds so basing on this we are able to determine a duration of the ICO. One more parameters is the price which determines how many tokens user receives for his ether, one thing to note is that in contracts amount of ether is in wei (1 ether = 10^18 wei) so with selected price investor will receive 1000 coins for 1 ether. Now we can switch to the most important function – buyCoins().
function buyCoins() public payable{ //check if user sent ether require(msg.value > 0); //check time limit require(block.number >= startBlock && block.number < endBlock); //count tokens to send uint amountRemaining = token.balanceOf(this); uint amountToBuy = msg.value.div(price).mul(10 ** 18); if(amountToBuy > amountRemaining){ amountToBuy = amountRemaining; } assert(amountToBuy > 0); //send tokens token.transfer(msg.sender, amountToBuy); //return tokens to sender if too much uint remainingEther = msg.value.sub(receivedEther); msg.sender.transfer(remainingEther); }
Very self-explanatory. We have to check if the ICO is in progress, count number of coins which an investor will receive and send them to him, additionally if he sends too much Ether we will give him the excess back. Now we probably want to get the Ether that our campaign has collected.
function finalize() public { //only owner should be able to get the ether require(msg.sender == owner); //check if ICO is finished require(endBlock <= block.number); //send collected ether owner.transfer(this.balance); //send remaining coins to owner token.transfer(owner, token.balanceOf(this)); }
And a basic version is finished. After we get collected Ether we can exchange it to real money and thank investors. But of course it can be improved and extended.
Problems and extensions
From where this contract have obtained coins?
ICO is a smart contract, it has different address than our so we have to transfer initial amount of coins to this contract before we can sell them. I have paid attention that ERC223 standard allows us to send only to contract which can handle it. So we have to add tokenFallback() function:
contract ICO is ERC223Receiver{ ... function tokenFallback(address _from, uint _value, bytes _data){ //receive coins and probably emit an event } ... }
Another popular way to do it is to deploy an ICO contract first, then a Token contract with the ICO address in constructor and there initialize this account to an initial value. But it could be problematic if we want to start more than one ICO with the same tokens.
Ether collected in contract
In current implementation all Ether is collected in a contract and send to owner after the campaign. Better solution is to send Ether just after transaction to the owner to avoid possible attacks.
function buyCoins() public payable { ... assert(amountToBuy > 0); //count and transfer ether received for coins uint receivedEther = amountToBuy.div(10 ** 18).mul(price); owner.transfer(receivedEther); //send tokens token.transfer(msg.sender, amountToBuy); ... }
Block number as time tracker
We aren’t able to know exact time between blocks. It is approximately 15 second but we can’t be sure. Summing a lot of miscalculations we could receive start or end time much different than expected. Currently recommended solution is to use block.timestamp, it also isn’t a perfect solution, because miners can manipulate this value, but mistake could be only about 30 seconds. It is much more precise than the first solution. To implement it we have to change the startBlock/endBlock to the startTime/endTime and use block.timestamp in exchange of the block.number.
License agreement
Sometimes owner wants users to accept an agreement before participating in the ICO and before accepting it users shouldn’t be able to buy tokens. To achieve it we can add book (map) of approved participants, create a website account which will be able to approve users and prepare some UI for it.
contract ICO is ERC223Receiver{ ... address websiteAddress; ... mapping(address => bool) approvedParticipants; constructor(..., address _websiteAddress, ...) public { ... websiteAddress = _websiteAddress; } ... function approveParticipant(address participant) public { require(msg.sender == websiteAddress); approvedParticipants[participant] = true; } function buyCoins() public payable { ... //check participant require(approvedParticipants[msg.sender]); ... } }
There is one more question. How to connect it for example with a prepared website? Community have prepared a lot of libraries, like for example web3.js, which enables us to make transactions directly from app written in different language.
Pause opportunity
Everybody wants to be errors-proof. Sometimes it is really hard and some bugs will become public. Then it is worth having possibility to block core functions of the app. It is possible by adding a pause functionality. The easiest option to do it is to use zeppelin’s implementation in which owner of the contract is able to pause every function:
contract ICO is ERC223Receiver, Pausable { function buyCoins() public payable whenNotPaused { ... } }
Changing price
Sometimes we want to give a bonus for users who buy coins at the beginning. It’s not a problem. We have to just plan this ranges and add them:
function getPrice() private view returns (uint256) { uint256 diff = block.number.sub(startBlock); if(diff < 57600){ // 57600 = 10 * 24 * 60 * 4 - approximately 10 days return 0.000769230769 * 10**18; //bonus 30% } else if (diff < 115200) { // 115200 = 20 * 24 * 60 * 4 - approximately 20 days return 0.000833333333 * 10**18; //bonus 20% } else if (diff < 172800) { // 115200 = 30 * 24 * 60 * 4 - approximately 20 days return 0.000909090909 * 10**18; //bonus 10% } return 0.001 * 10**18; }
View functions
It’s nice to have more functions that enable potential investors to see remaining coins, the end time or to count how much coins they can buy:
function howMuchCoinsCanIBuy(uint256 amountOfEther) public view returns (uint) { return amountOfEther.mul(10 ** 18).div(getPrice()); } function getRemainingCoins() public view returns (uint) { return futurumCoin.balanceOf(this); } function getEndBlock() public view returns (uint) { return endBlock; }
Full implementation
When we sum everything up we will receive a finished ICO. The full code is here and even more improved version of a Futurum’s ICO, which I wrote, here. All ICOs are similar but of course every one can have different designs and functionalities. It is really common thing so you can prepare it in just a few lines of code using already created implementations like this from zeppelin.
Security
Everything is transparent, decentralized and unstoppable, but the most important thing when we want to collect money is security. Nobody starts a campaign until he is sure that he will receive all collected money. It is a young technology so it could be susceptible to errors and until today there were many attacks based on vulnerabilities of tools and contracts. But most of them was caused by people, not by framework so it is important not to make the same mistake. Many of them probably won’t have a chance to be present in the ICO, but still it’s good to know about them. I think that currently Ethereum as a base could be considered as safe to use.
Summary
There are many very successful ICOs using the Ethereum ecosystem. Personally, I think that it is a worth to consider and relatively safe option for collecting donations based on popularity of cryptocurrencies. What is more it isn’t hard and long to create it. After learning this technology and looking on some ICOs you can see that most of them are very similar and there are a lot of already created and tested libraries. Additionally, for me as a developer it was something new and interesting to learn. I covered only very basics in this article but I hope that I encouraged you to consider ICO as a fund-raising mechanism or to learn more about this technology.
Besides examples from this article I was responsible for creating ICO for Futurum (here and here). So if you have found any errors or bugs in presented contracts, please leave me a comment!