
How to do an ICO in 10 minutes
Thats right, 10 minutes. In fact, I’m so confident about this, I’d encourage you to time yourself from start to end.
Backstory — an Initial Coin Offering is a strategy used by ‘new’ companies to raise funds, the modern age equivalent on an IPO without giving up an equity in the company but rather giving people a ‘token’ i.e an opportunity to transact with a product that is already built, or most likely to be built.
Now the ICO we’re launching is a token, not a cryptocurrency but a token. Whats the difference ? Technically — a token usually represents a utility in a product some entity is offering, and this ethos has been made abundant due to Ethereum’s app based infrastructure (kinda like android/ios as platforms and smart contracts act as mini apps)
Essentially we’ll be building an ERC20 Token, While ERC20 sounds like a robot straight out of the Star Wars universe, it’s nothing more than an ‘standard’ to follow. Because so many of these ICOs were coming out, the “community” agreed to follow a standard pattern / protocol to follow as a base requirement. Theres more standards out there, including interesting ones like the ERC721 standard (cryptokitties). Nonetheless, the ERC20 Standard can be simply jotted down as a contract that has, at minimum, this following interface:
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
Think of an interface as a guide to what a contract can do without sharing the core logic behind all these functions. Its a way of helping us interact with contracts, much like — a menu (which lists all the available options)
Don’t worry we’ll go ahead and build out an ERC20 contract with the logic filled up again. I’ve made this tutorial to be very minimalistic (reminder: we’re launching in less than 10 minutes )
Here’s the tooling you’ll need:
- Text editor (VSCode, Atom or Sublime)
- Access to remix.ethereum.org
- Some fake ether in a test network called Rinkeby
- An Ethereum wallet with Rinkeby ether in it
Now please note that this code is NOT tested, you NEED to test your code, using tools like truffle, you can simply copy paste the exact contract in, truffle gives you very simple instructions on testing — you will need ganache-cli set up but other than that, for testing purposes you should do local testing on a testrpc network and then test your contract, under a pseudo name on Rinkeby / Robsten.
Now for a little more on what Rinkeby actually is, Rinkeby is for all purpose needs a public test environment where you can test your smart contract code, with ‘fake’ ether, Yes the ether you get here does not hold any fiat equivalent value to it — https://www.rinkeby.io speaking of which you can easily get rinkeby ether from this link -> https://faucet.rinkeby.io/
I use Google plus, because no one really uses that platform(or I’m just trying to make the people who created it feel a little better), simply take your wallet address, create a Google post with just that wallet address, copy the link to that post and place it in the input box


And you should have ether in your account.
(You’re basically Satoshi Nakamoto)
Just kidding, you still need to create a token. Super simple. Head over to remix.ethereum.org
This is an online Ethereum IDE where we can build, compile and test our Ethereum solidity code.

What we’re going to create is a standard ERC-20 with base ERC20 compliant standards. What this standards, means is that you’ll need to have ATLEAST these basic functionalities for it to match this standard
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
So this snippet basically shows something called an ‘Interface’ which is a ‘high-level abstract’ representation of the contract, i.e these are the things available and these are the function and event definitions.
Alright enough talk, here’s the code for the a standard contract that covers the functions mentioned above as well as. Just copy paste it into the remix IDE.
pragma solidity ^0.4.23;
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}contract BaseToken {
using SafeMath for uint256;
mapping(address => uint256) balances;
mapping (address => mapping (address => uint256)) internal allowed;address public owner;
uint256 totalSupply_;function totalSupply() public view returns (uint256) {
return totalSupply_;
}function transfer(address _to, uint256 _value) public returns (bool) {
emit Logger(msg.sender);
require(_to != address(0));
require(_value <= balances[msg.sender]);// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
emit Logger(_from);
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
event Logger(address sender);
}
Because who doesn’t love chunks of code, I’ve gone ahead an included a SafeMath library that does safety checks for all your mathematical calculations as well as an Ownable contract, that lets you define the owner of the contract. Think of the owner as the admin in traditional systems.
Let me quickly explain some of the thinks so you’re not copy and pasta-ing.
We have a SafeMath Library, a library, much like in traditional programming is a ‘module’ that adds additional functionality to our code base. The Ownable contract when inherited from basically lets us set the owner of the contract to the person/wallet that deployed the contract, it also gives us access to the onlyOwner modifier which we can add to any function we want to restrict to only the owner. Lastly it lets us transfer ownership between wallets.
Now is the BaseToken this is just something i’ve created which makes use of the SafeMath Library (the isOwnable is for another part i’ll share soon)
The base token has all the standard ERC20 functions as well as a mapping for the balances and allowances. A mapping is not too different (in theory) to a hashmap or a dictionary.
At the very bottom we have Events, whenever a transfer is made sometimes we want external actors to know transactions have occurred, an example of such an actor would be an exchange that will want to keep track of all the transfers that have happened or even etherscan.io, if you don’t add transfer events the initial transfer of tokens to the ‘supplyWallet’ wont be showcased and it would ‘error*’ out.
Lastly we add the contract itself:
contract PotatoCoin is BaseToken {
// Publicly listed name
string public name = "PotatoCoin";
// Symbol under which token will be trading
string public symbol = "U";
// 1 ETH consists of 10^18 Wei, which is the smallest ETH unit
uint8 public decimals = 18;
// Defining the value of a million for easy calculations - order of declaration matters (hoisting)
uint256 million = 1000000 * (uint256(10) ** decimals);
// We are offering a total of 100 Million PotatoCoin Tokens to distribute
uint256 public totalSupply = 40000 * million;
// Address where all the tokens are held, as tokens aren't held within the Smart Contract
address public masterWallet;// constructor function
constructor()
public
{
// The wallet from which the contract is deployed, also the owner of the contract
owner = msg.sender;
masterWallet = owner;// Assign total supply to master wallet
// https://github.com/OpenZeppelin/zeppelin-solidity/issues/494
// A token contract which creates new tokens SHOULD trigger a Transfer event with the _from address set to 0x0 when tokens are created.
balances[masterWallet] = totalSupply;
emit Transfer(0x0, masterWallet, totalSupply);
}function () public payable{
buyTokens();
}
function buyTokens() payable public {
// 10 is the exchange rate i've set 1ETH = 10 potato coinsuint256 tokenAmount = msg.value.mul(10);
// Ensure that the tokenAmount is greater than masterWallet amount
require(balances[masterWallet] >= tokenAmount);
// Subtract the tokens bought from the masterWallet
balances[masterWallet] = balances[masterWallet].sub(tokenAmount);
// Add these tokens to the person who bought
balances[msg.sender] =balances[msg.sender].add(tokenAmount);
// send the masterWallet the actual ETHER
masterWallet.transfer(msg.value);
// Manually Emit the Transfer Events
emit Transfer(masterWallet, msg.sender, tokenAmount);
}function burn(uint256 _value) onlyOwner public {
require(_value <= balances[msg.sender]);
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failureaddress burner = msg.sender;
balances[burner] = balances[burner].sub(_value);
totalSupply_ = totalSupply_.sub(_value);
emit Burn(burner, _value);
emit Transfer(burner, address(0), _value);
}// Events
event Burn(address indexed burner, uint256 value);
}
So this is PotatoCoin and as you can see, PotatoCoin is BaseToken, thats the solidity way of saying it is inheriting. We also have the nameless function, which is the default function that is called when a transaction is sent to the smart contract without a dedicated function call, i.e when we send ETHER. As you can see it also has the key payable attached to it, we MUST have this if we want this function to receive real ETHER or else the function will reject all the ETHER it receives — http://solidity.readthedocs.io/en/develop/contracts.html#function-modifiers (search for payable).
Cool — so we’ve done all this, we’ve added the code in remix, and now what ?

Look at this section on the right hand side, make sure Auto compile is ticked, and then ensure that from the dropdown you have selected PotatoCoin and then click Details.

You’ll get this popup and you can see there’ll be a heap of data here, for the purpose of the 10 minute process we won’t go too much into this, but primarily the metadata contains all information describing the data, but what we care about is the compiled bytecode. All you’ll have to do is copy the code represented by the ‘object’ key, in the image above this is the huge alphanumeric string “608060….”
Copy this, and now go to myetherwallet.com where we will select the Rinkeby test network to basically test the tokens, this is the same test network we spoke of in the beginning. Go through the set up process if you’d like, or if you have a metamask account already set up with the Rinkeby ether as above then click on the Contracts tab. Make sure at this point you’re in the Rinkeby ether scan, the image below top right you can see it says Network ETH, the next image shows Network Rinkeby.

Then click on Deploy contract, paste the bytecode in and set the gas limit to 4700000.

Unlock the wallet using metamask (preferred) or any hard wallet (more preferred) and then simply sign the transaction and click deploy.


Provided if you used metamask, you’ll get a popup, make sure you’re connected to the Rinkeby Test Net

I just bumped up the gas to fasten it up but that depends upon you.
You should get a green popup at the bottom like that.

This details your contract address as well as the link to view your transaction (don’t worry if it disappears, simply click on your metamask and you’ll see a transaction under your account saying ‘account creation’)
Once thats done, go to the transaction link it provides (BE QUICK, MEW is sneaky and the popup just disappears)

Now pat yourself on the backgive your self some claps, and if you’re feeling super generous share some claps on this post as well.
That being said, I HOLD NO RESPONSIBILITY FOR YOUR UNTESTED CODE, this is demo code and it has not been thoroughly tested, you SHOULD TEST ALL YOUR CODE (heaps of tools out there) AND ONLY WHEN YOU ARE 1100% SURE, THEN LAUNCH IT. TEST TEST TEST
And voila as you can see , i’ve launched Potato coin, and its been deployed from my Rinkeby wallet and you can click on the https://rinkeby.etherscan.io/address/0xf47964c385e4e0aa5c3320f0a4e4d7ea68ab2a9f link here to see all the fake ether I would raise.
Thats it people.
PS I will soon update this to talk about the Ownable contract part :)
I would LOVE to hear your feedback below.