(Part 17) Ethereum Solidity - ICO Contract, Basic Security And Token Interaction(PT 17)

Repository

https://github.com/igormuba/EthereumSolidityClasses/tree/master/class17

What Will I Learn?

  • Cross-contract interaction
  • Creating an ICO contract
  • Basic ICO security

Requirements

  • Internet connection
  • Code editor
  • Browser

Difficulty

  • Intermediate

Tutorial Contents

In this tutorial, I will teach you the basics of an ICO. I will add a few very basic security features on the contracts, but at this moment I won't cover any standard for security, crowd sales or token development because I want to focus on what are the core features an ICO should have. Though, if you want to learn more about design patterns, I have covered ERC20 and ERC721 and 165 compliance in previous tutorials, though, all of them did not cover crowd sales and ICO patterns.

Cross contract interaction

On a previous tutorial I have introduced how can contracts interact with each other, but in that case I was using that functionality to provide mutability for contract (Solidity contracts are inherently immutable, but that can be hacked!), but, in short, this is how it works

import "contractYouWantToImport.sol"; by importing a local contract you provide your contract with the signature of the contract it wants to fetch by the network

contractYouWantToImport externalContract = contractYouWantToImport(INSERT contractYouWantToImport ADDRESS HERE); this tells the contract what is the signature and the address of the contract you want it to communicate to in the Ethereum network

To call a function from the contractYouWantToImport contract, you can normally call it as if externalContract is an instantiated object

externalContract.externalFunction();

where externalFunction() is a function from contractYouWantToImport contract

The token contract

The token contract does not follow any standard and is made just to demonstrate how the ICO could work, you can, however, use previous tutorials to make an ERC20 token for example

pragma solidity ^0.5.0;

contract simpleToken{
    mapping(address => uint) public balance; //stores token balances of users
    address public icoAddress; //address of the ICO contract
}

I am creating a variable the ICO contract because that contract is the one that will manage the creation of tokens. We will, first, deploy the ICO contract, then, this token contract. When deploying the token we will pass the ICO contract by the constructor

constructor(address _icoAddress) public {
        icoAddress=_icoAddress; //sets the ICO address
        balance[_icoAddress]=1000; //gives all tokens to the ICO contract
    }

Token creation function on the token contract

Still talking about the token contract, we will now set a function that allows the ICO contract to send funds from its account to the buyer's account.

function createToken(address _receiver, uint _amount) public{
        require(msg.sender == icoAddress); //throws error if caller is not the ICO contract
    require(balance[icoAddress]>=0); //requires that ICO contract has the balance
    require(balance[icoAddress]-_amount>=0); //requires that after transfer ICO balance is not negative
        balance[icoAddress]-=_amount; //reduces balance of ICO contract
        balance[_receiver]+=_amount; //increases balance of buyer
    }

Notice that in the code above we have implemented 4 security features. The 3 first ones are explicit and obvious
require(msg.sender == icoAddress) ensures that only the ICO contract can "create" tokens (transfer from ICO balance to buyer balance)
require(balance[icoAddress]>=0); ensures that the ico contract has balance to proceed with the operation
require(balance[icoAddress]-_amount>=0); will cancel the call function if the balance after the withdrawal from the ICO token balance is less than zero (if someone tries to buy more than the remaining supply for example)
The last security feature is that the function reduces the balance of the sender before adding to the balance of the receiver. The DAO hack was done by using an exploit that can be prevented by doing transfers in this order!

Token transfers

This function will allow users to trade and send tokens to each other, though, for not complying with ERC20 yet, as this is not the focus of this tutorial, this token would probably have a hard time being accepted by exchanges

    function transfer(address _receiver, uint _amount) public {
        require(balance[msg.sender]>=_amount); //requires the sender to have at least the amount he wants to send
        require(balance[msg.sender]-_amount>=0); // requires that senders balance won't be negative after sending
        balance[msg.sender]-=_amount; //reduces sender balance
        balance[_receiver]+=_amount; //increases receiver balance
    }

Again, those 3 security measures are similar to the ones used on the previous function

Clearing ICO balance

We want that, when the ICO ends, the remaining tokens are burned, to avoid people buying the remaining tokens or for whatever economic reason ICOs like to burn tokens, it is not necessary, but it is a neat cool feature to have, also contributes to security, in my opinion.

function clearIcoBalance() public {
        require(msg.sender == icoAddress); //requires that caller is the ICO contract
        balance[msg.sender]=0; //cleans the balance of the sender
    }

Notice that we implement 2 security measures, only the ICO contract can call this function, but if someone manages to (I think it is impossible) overcome this requirement, the function cleans the balance of the caller of the function, not the ICO function, in case the caller is the contract, well, then the ICO balance will be clean as expected.

Get user balance

This last feature is useful for debugging and for users to keep track of their balances, the implementation is very simple

    function getMyBalance() public view returns (uint){
        return balance[msg.sender]; //returns balance of caller
    }

The ICO contract

The ICO contract is very simple and does not follow any development standard, though, on future tutorials I will cover standards, as they are important.

pragma solidity ^0.5.0;

import "browser/simpleToken.sol"; //imports the token

contract ico{
    simpleToken public token; //we will use this to call the tokens functions
    bool public tokenSet = false; //tells if the token contract is set
    address public tokenCreator; //address of token creator, for security
    bool public icoOver = false; //if ICO has ended or not
}

The ICO constructor

On the constructor of the ICO, we will set the creator of the ICO, for future security measures

    constructor() public{
        tokenCreator=msg.sender; //token creator is the creator of ICO contract
    }

Setting the token

This function will store on the ICO contract what is the address of the token we are selling

    function setToken(address _tokenAddress) public{ //receives as argument the address  of deployed token
        require(!tokenSet); //throws error if token is already set
        require(msg.sender==tokenCreator); //throws error if caller is not token creator
        token=simpleToken(_tokenAddress); //sets the address of the token
    }

Notice a few security measures:
require(!tokenSet); ensures that we can only set the token if the token is not yet set (in case someone tries to change the token address for some reason or by accident)
require(msg.sender==tokenCreator) ensures us that only the deployer of the ICO contract can tell the contract what token (address) are we talking about

Selling the token

This is the function that is responsible for receiving Ethereum payments and sending the tokens to the buyer

    function() payable external{
        require(!icoOver); //throes error if ICO is over
        uint amount = msg.value / 1 ether; //the paid value divided by 1Ether
        token.createToken(msg.sender, amount);//tells the token contract to send tokens from contract to buyer
    }

On our ICO the price of 1 token is 1 Ether, to keep things simple

Ending the ICO

At the moment we are implementing a very simple method to end the ICO, you could make it automatic, based on amount sold or based on a set time, but I think that the following function is the basic you need to know for any of those methods mentioned.

    function endIco() public{
        require(msg.sender==tokenCreator); //requires caller is token creator
        icoOver=true; //changes ICO status to over
        token.clearIcoBalance; //tells the token to clean the ICO contract token balance
    }

Now you can see that this function connects perfectly with the function from the token when the owner of the token tells the contract to end the ICO, the contract will tell the token to clean its balance, and everything just works! Very cool!

Deploying

According to how we have designed the Token and the ICO, it is mandatory that the ICO contract is deployed first, and just then we deploy the token contract, telling the token contract what is the ICO contract

I am using Remix browser IDE on a local JavaScript VM to do the following tests

Using the address 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c (the owner), I deployed the ICO contract, which has the address of 0xdd1f635dfb144068f91d430c76f4219088af9e64

To deploy the simpleToken I need to pass to its constructor the address of the ICO
image.png

By checking the balance of the ICO contract, we can confirm that indeed the balance was created and assigned correctly to the right address
image.png

Using the owner address, set the token address on the ICO, else the crowdsale contract won't be able to find what token contract are we talking about
image.png

Testing

Now I have switched to the secondary address 0xca35b7d915458ef540ade6068dfe2f44e8fa733c
I have sent 10 Ether to the ICO contract, which activated the fallback (seller) function

image.png

The balance of the buyer account is now 10 tokens
image.png

The balance of the ICO contract is 10 tokens smaller
image.png

I want now to send 5 tokens from the buyer 0xca35b7d915458ef540ade6068dfe2f44e8fa733c to a third address 0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db

I can see that after I have sent indeed my balance is lower
image.png

And the receiver balance is equal to the number of tokens I sent him
image.png

Curriculum

Beneficiaries

This post has as beneficiaries
@utopian.pay with 5%
using the SteemPeak beneficiary tool
image.png

H2
H3
H4
Upload from PC
Video gallery
3 columns
2 columns
1 column
6 Comments