Today I’m going to show you how to develop and sell your own cryptocurrency on the Ethereum blockchain! I’ll show you how to use Ethereum smart contracts to gradually create your own ERC-20 tokens and crowdfund sales, how to test smart contracts, how to deploy smart contracts to the Ethereum blockchain, and how to build ICO sites to deploy to the network. I’ll also explain what erC-20 tokens are, how Ethereum tokens work, and how initial coin offerings (ICOs) work.

What is the ERC-20 token?

The Ethereum blockchain allows you to create your own cryptocurrency or token, which can be purchased via Ethereum, the ethereum blockchain’s local cryptocurrency. Erc-20 is just a standard that specifies how these tokens should behave, so they are compatible with other platforms such as cryptocurrency exchanges.

So how do you do that? Let’s take a look at how the Ethereum blockchain works.

Ethereum is a blockchain like Bitcoin. Like Bitcoin, Ethereum tracks the balance of users who have Ether, the native cryptocurrency of Ethereum. Unlike Bitcoin, Ethereum is also a platform that allows you to create your own tokens without creating a new blockchain.

You can create Ethereum tokens using smart contracts. Erc-20 is a standard that specifies how this token smart contract should work.

Let’s use an example to understand how the ERC-20 token smart contract works. Suppose we want to create a Token called “My Token” with the symbol “MTK”, and there are 100,000,000 such tokens.

First, token smart contracts track some basic token properties. For example, it records the name “My Token,” the symbols you see in cryptocurrency exchanges, and how many total tokens exist.

It also tracks who owns “My tokens” and how much.

Erc-20 tokens can be transferred from one account to another as payment, just like any other cryptocurrency.

They can also be purchased in crowdfunded sales, such as ICOs, which we’ll discuss in the next section.

They can also be bought and sold on cryptocurrency exchanges.

How icOs work

Erc-20 tokens can be distributed in a number of ways. One popular approach is to hold targeted promotions or initial coin offerings (ICOs). Crowdfunding sales are a way for companies to raise money for their business by creating their own ERC-20 token, which can be purchased by Ethereum investors.

Each time a crowdfunding sale occurs, the company receives working capital in the form of Ether paid by investors and holds ERC-20 tokens of the amount reserved for sale in the crowdfunding sale.

In order to participate in the crowdfunding sale, investors must connect to the Etherum blockchain using an account. The account has a wallet address for storing Ether, as well as ERC-20 tokens purchased in a crowdfunding sale.

Investors must visit crowdfunding sales sites that talk to smart contracts. Smart contracts govern all the rules of how crowdfunding sales work.

Each time an investor buys a token on a crowdfunding sales site, they send Ether from their wallet to a smart contract, which immediately distributes the purchased token to their wallet.

Smart contracts set the price of tokens in crowdfunded sales and control how crowdfunded sales behave.

Crowdfunded sales can come in all shapes and sizes. They can have multiple levels or stages, such as the Pre ICO, ICO, and ICO Bonus stages. Each of these layers can occur at different points in time and can behave differently.

They can also use a whitelist to limit which investors can buy tokens.

They can also own a predetermined number of tokens that won’t be sold in crowdfunding sales. These reserves are usually reserved for specific members of each company, such as founders and advisers. These reserves can be a fixed number of tokens or percentages.

At the end of each public sale, it can be finalized by the administrator. Whenever this happens, all reserved tokens will be distributed to the appropriate account and the crowdfunding sale will officially end.

How the ERC-20 token works

As I explained earlier, erC-20 tokens are created using Ethereum smart contracts. What is a smart contract?

Ethereum allows developers to write applications that run on the blockchain using smart contracts that encapsulate all of their business logic. They enable us to read and write data on the blockchain, as well as execute code. Smart contracts are written in a programming language called Solidity that looks a lot like Javascript. It’s a complete programming language that allows us to do many of the same kinds of things that Javascript can provide, but behaves a little differently because of its use cases, as we’ll see in this tutorial.

For ERC-20 tokens, the smart contract manages all actions regarding how the token works and tracks token ownership and account balances.

Erc-20 is an API specification for how to build Ethereum tokens. It is a community-adopted standard that allows tokens to be supported in a variety of use cases. We want to build a token that meets this standard so that it can be widely accepted. If we didn’t have such a standard, we could have endless ways to create tokens that might not be compatible with each other!

Using the ERC-20 standard ensures that tokens comply with the following use cases (and more) :

  • E-wallet Transfer – Sending tokens from one account to another
  • Buy and sell on cryptocurrency exchanges
  • Buy tokens in a crowdfunded sale (ICO), as we will demonstrate in this tutorial

The ERC-20 specification basically specifies the interfaces that smart contracts must respond to. It defines the structure of a smart contract and the types of functions that a smart contract must have. It also offers some nice suggestion features, but is ultimately optional. It specifies certain events that our tokens must have, such as transfer events. Note that smart contracts can emit events that consumers can subscribe to, and using this standard we can subscribe to events that tell us when to sell tokens.

The following is an example implementation of the Transfer function specified by the ERC-20 standard. It is required by smart contracts and manages how someone sends erC-20 tokens from a wallet to another wallet.

contract ERC20Token { // ... function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value);  balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; Transfer(msg.sender, _to, _value); return true; } / /... }Copy the code

This function implements the ERC-20 standard by:

  • This feature exists.
  • It accepts the correct arguments.
  • If the user does not have enough tokens to pay, i.e., insufficient balance, it fails.
  • It transfers the balance from the sender’s account to the receiver’s account.
  • It will triggersellEvents.
  • It returns the correct value, for exampletrue.

If all this doesn’t make complete sense, don’t worry. You can read more about the ERC-20 token standard directly in the Ethereum Improvement Proposal Github repository. This is where all the community discussion around the Ethereum standard takes place. I highly recommend bookmarking the repository and reading submissions because this is where you can watch Ethereum technology grow and change in real time!

I also recommend this Wikipedia article.

We are going to build the website

We will build an ICO site to talk to crowdfunded sales of smart contracts on the blockchain. The client site will have a form where users can purchase tokens in crowdfunded sales. It will show the progress of the crowdfunding sale, such as how many tokens the user has purchased, how many tokens all users have purchased, and the total number of tokens available in the crowdfunding sale. It will also display our accounts associated with the blockchain under your Account.

Install dependencies

To build our ERC-20 token and sell, we first need some dependencies.

Node Package Manager (NPM)

The first dependency we need is the Node package manager, or NPM, which comes with Node.js. You can check if you have a node installed by entering the following from your terminal:

$ node -v
Copy the code

Truffle framework

The next dependency is the Truffle Framework, which allows us to build decentralized applications on the Ethereum blockchain. It provides a set of tools that allow us to write smart contracts using the Solidity programming language. It also enables us to test our smart contracts and deploy them to the blockchain. It also gives us a place to develop client applications.

You can install Truffle from the command line using NPM, as follows:

$ npm install -g truffle
Copy the code

Ganache

The next dependency is Ganache, a local memory blockchain. You can install Ganache by downloading it from the Truffle Framework website. It will give us 10 external accounts that contain our local Ethereum blockchain address. Each account comes preloaded with 100 test Ether.

Metamask

The next dependency is the Metamask extension for Google Chrome. In order to use a blockchain, we have to connect it (remember, I said a blockchain is a network). We had to install a special browser extension to use the Ethereum blockchain. This is where Metamask comes in. We will be able to connect to our local Ethereum blockchain through our personal accounts and interact with our smart contracts.

We’ll be using the Metamask Chrome extension in this tutorial, so you’ll need to install Google Chrome if you don’t already have it. To install Metamask, search for the Metamask Chrome plugin in the Google Chrome Web app store. After the installation is complete, make sure it is selected in the extension list. Once installed, you’ll see the fox icon in the top right corner of your Chrome browser.

Syntax is highlighted

Dependencies are optional, but recommended. I recommend installing syntax highlighting for the Solidity programming language. Most text editors and ides don’t have Solidity syntax highlighting out of the box, so you’ll have to install a package to support this feature. I am using Sublime Text and I have downloaded the “Ethereum” package which provides great syntax highlighting for Solidity.

Erc-20 token smart contract

Now that we have the dependencies installed, let’s start building our ERC-20 token! Here is the full Solidity code for ERC-20 token smart contracts:

Pragma solidity ^ 0.4.2; contract DappToken { string public name = "DApp Token"; string public symbol = "DAPP"; String public standard = "DApp Token v1.0"; uint256 public totalSupply; event Transfer( address indexed _from, address indexed _to, uint256 _value ); event Approval( address indexed _owner, address indexed _spender, uint256 _value ); mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; function DappToken (uint256 _initialSupply) public { balanceOf[msg.sender] = _initialSupply; totalSupply = _initialSupply; } function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; Transfer(msg.sender, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(_value <= balanceOf[_from]); require(_value <= allowance[_from][msg.sender]); balanceOf[_from] -= _value; balanceOf[_to] += _value; allowance[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; }}Copy the code

Let’s take a look at what this smart contract does and how it implements the ERC-20 standard:

  • It stores the token nameString public Name = "DApp Token".
  • It stores tokens used in cryptocurrency exchangesString public symbol = "DAPP".
  • It stores theuint256 public totalSupplyTotal supply of public tokens.
  • It uses the Solidity map to store the owning token mapmapping(address => uint256) public balanceOfThe balance of each account.
  • It implements onetransferFunction that allows the user to send tokens to another account.
  • It implements a token that allows other accounts to use tokensapproveFunctions, such as cryptocurrency exchanges. This will updateallowanceMap to see how much an account can spend.
  • It implementstransferFromTo allow other accounts to transfer tokens.

You can also read this smart contract test to learn more about how it works. These tests ensure that the smart contract behaves as expected. Here’s a complete suite of tests to check all the behavior of smart contracts:

var DappToken = artifacts.require("./DappToken.sol");

contract('DappToken', function(accounts) {
  var tokenInstance;

  it('initializes the contract with the correct values', function() {
    return DappToken.deployed().then(function(instance) {
      tokenInstance = instance;
      return tokenInstance.name();
    }).then(function(name) {
      assert.equal(name, 'DApp Token', 'has the correct name');
      return tokenInstance.symbol();
    }).then(function(symbol) {
      assert.equal(symbol, 'DAPP', 'has the correct symbol');
      return tokenInstance.standard();
    }).then(function(standard) {
      assert.equal(standard, 'DApp Token v1.0', 'has the correct standard');
    });
  })

  it('allocates the initial supply upon deployment', function() {
    return DappToken.deployed().then(function(instance) {
      tokenInstance = instance;
      return tokenInstance.totalSupply();
    }).then(function(totalSupply) {
      assert.equal(totalSupply.toNumber(), 1000000, 'sets the total supply to 1,000,000');
      return tokenInstance.balanceOf(accounts[0]);
    }).then(function(adminBalance) {
      assert.equal(adminBalance.toNumber(), 1000000, 'it allocates the initial supply to the admin account');
    });
  });

  it('transfers token ownership', function() {
    return DappToken.deployed().then(function(instance) {
      tokenInstance = instance;
      // Test `require` statement first by transferring something larger than the sender's balance
      return tokenInstance.transfer.call(accounts[1], 99999999999999999999999);
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, 'error message must contain revert');
      return tokenInstance.transfer.call(accounts[1], 250000, { from: accounts[0] });
    }).then(function(success) {
      assert.equal(success, true, 'it returns true');
      return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] });
    }).then(function(receipt) {
      assert.equal(receipt.logs.length, 1, 'triggers one event');
      assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event');
      assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from');
      assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to');
      assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount');
      return tokenInstance.balanceOf(accounts[1]);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 250000, 'adds the amount to the receiving account');
      return tokenInstance.balanceOf(accounts[0]);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 750000, 'deducts the amount from the sending account');
    });
  });

  it('approves tokens for delegated transfer', function() {
    return DappToken.deployed().then(function(instance) {
      tokenInstance = instance;
      return tokenInstance.approve.call(accounts[1], 100);
    }).then(function(success) {
      assert.equal(success, true, 'it returns true');
      return tokenInstance.approve(accounts[1], 100, { from: accounts[0] });
    }).then(function(receipt) {
      assert.equal(receipt.logs.length, 1, 'triggers one event');
      assert.equal(receipt.logs[0].event, 'Approval', 'should be the "Approval" event');
      assert.equal(receipt.logs[0].args._owner, accounts[0], 'logs the account the tokens are authorized by');
      assert.equal(receipt.logs[0].args._spender, accounts[1], 'logs the account the tokens are authorized to');
      assert.equal(receipt.logs[0].args._value, 100, 'logs the transfer amount');
      return tokenInstance.allowance(accounts[0], accounts[1]);
    }).then(function(allowance) {
      assert.equal(allowance.toNumber(), 100, 'stores the allowance for delegated trasnfer');
    });
  });

  it('handles delegated token transfers', function() {
    return DappToken.deployed().then(function(instance) {
      tokenInstance = instance;
      fromAccount = accounts[2];
      toAccount = accounts[3];
      spendingAccount = accounts[4];
      // Transfer some tokens to fromAccount
      return tokenInstance.transfer(fromAccount, 100, { from: accounts[0] });
    }).then(function(receipt) {
      // Approve spendingAccount to spend 10 tokens form fromAccount
      return tokenInstance.approve(spendingAccount, 10, { from: fromAccount });
    }).then(function(receipt) {
      // Try transferring something larger than the sender's balance
      return tokenInstance.transferFrom(fromAccount, toAccount, 9999, { from: spendingAccount });
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, 'cannot transfer value larger than balance');
      // Try transferring something larger than the approved amount
      return tokenInstance.transferFrom(fromAccount, toAccount, 20, { from: spendingAccount });
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, 'cannot transfer value larger than approved amount');
      return tokenInstance.transferFrom.call(fromAccount, toAccount, 10, { from: spendingAccount });
    }).then(function(success) {
      assert.equal(success, true);
      return tokenInstance.transferFrom(fromAccount, toAccount, 10, { from: spendingAccount });
    }).then(function(receipt) {
      assert.equal(receipt.logs.length, 1, 'triggers one event');
      assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event');
      assert.equal(receipt.logs[0].args._from, fromAccount, 'logs the account the tokens are transferred from');
      assert.equal(receipt.logs[0].args._to, toAccount, 'logs the account the tokens are transferred to');
      assert.equal(receipt.logs[0].args._value, 10, 'logs the transfer amount');
      return tokenInstance.balanceOf(fromAccount);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 90, 'deducts the amount from the sending account');
      return tokenInstance.balanceOf(toAccount);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 10, 'adds the amount from the receiving account');
      return tokenInstance.allowance(fromAccount, spendingAccount);
    }).then(function(allowance) {
      assert.equal(allowance.toNumber(), 0, 'deducts the amount from the allowance');
    });
  });
});
Copy the code

You can run tests from the command line using truffle, as follows:

$ truffle test
Copy the code

Crowdfunding sells smart contracts

Now we can set up a crowdfunded sales smart contract that allows investors to buy tokens in initial coin offerings (ICOs). Here’s the full Solidity code for crowdfunded selling smart contracts:

Pragma solidity ^ 0.4.2; import "./DappToken.sol"; contract DappTokenSale { address admin; DappToken public tokenContract; uint256 public tokenPrice; uint256 public tokensSold; event Sell(address _buyer, uint256 _amount); function DappTokenSale(DappToken _tokenContract, uint256 _tokenPrice) public { admin = msg.sender; tokenContract = _tokenContract; tokenPrice = _tokenPrice; } function multiply(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function buyTokens(uint256 _numberOfTokens) public payable { require(msg.value == multiply(_numberOfTokens, tokenPrice)); require(tokenContract.balanceOf(this) >= _numberOfTokens); require(tokenContract.transfer(msg.sender, _numberOfTokens)); tokensSold += _numberOfTokens; Sell(msg.sender, _numberOfTokens); } function endSale() public { require(msg.sender == admin); require(tokenContract.transfer(admin, tokenContract.balanceOf(this))); // Just transfer the balance to the admin admin.transfer(address(this).balance); }}Copy the code

Let’s take a look at what this smart contract does and how it’s crowdfunded to sell:

  • It stores crowdfunded salesaddress adminAddress administrator account.
  • It references erC-20 token smart contractsDappToken public tokenContract.
  • It stores the price of the tokenuint256 public tokenPrice.
  • It stores the number of tokens solduint256 public tokensSold.
  • It implements onesellEvent so that consumers can be notified when tokens are sold.
  • It implementsbuyTokensFunction that allows users to buy tokens in crowdfunded sales.
  • It implements oneendSaleFunction that allows the administrator to end a crowdfunding sale and collect ether raised during the sale.
var DappToken = artifacts.require('./DappToken.sol'); var DappTokenSale = artifacts.require('./DappTokenSale.sol'); contract('DappTokenSale', function(accounts) { var tokenInstance; var tokenSaleInstance; var admin = accounts[0]; var buyer = accounts[1]; var tokenPrice = 1000000000000000; // in wei var tokensAvailable = 750000; var numberOfTokens; it('initializes the contract with the correct values', function() { return DappTokenSale.deployed().then(function(instance) { tokenSaleInstance = instance; return tokenSaleInstance.address }).then(function(address) { assert.notEqual(address, 0x0, 'has contract address'); return tokenSaleInstance.tokenContract(); }).then(function(address) { assert.notEqual(address, 0x0, 'has token contract address'); return tokenSaleInstance.tokenPrice(); }).then(function(price) { assert.equal(price, tokenPrice, 'token price is correct'); }); }); it('facilitates token buying', function() { return DappToken.deployed().then(function(instance) { // Grab token instance first tokenInstance = instance; return DappTokenSale.deployed(); }).then(function(instance) { // Then grab token sale instance tokenSaleInstance = instance; // Provision 75% of all tokens to the token sale return tokenInstance.transfer(tokenSaleInstance.address, tokensAvailable, { from: admin }) }).then(function(receipt) { numberOfTokens = 10; return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: numberOfTokens * tokenPrice }) }).then(function(receipt) { assert.equal(receipt.logs.length, 1, 'triggers one event'); assert.equal(receipt.logs[0].event, 'Sell', 'should be the "Sell" event'); assert.equal(receipt.logs[0].args._buyer, buyer, 'logs the account that purchased the tokens'); assert.equal(receipt.logs[0].args._amount, numberOfTokens, 'logs the number of tokens purchased'); return tokenSaleInstance.tokensSold(); }).then(function(amount) { assert.equal(amount.toNumber(), numberOfTokens, 'increments the number of tokens sold'); return tokenInstance.balanceOf(buyer); }).then(function(balance) { assert.equal(balance.toNumber(), numberOfTokens); return tokenInstance.balanceOf(tokenSaleInstance.address); }).then(function(balance) { assert.equal(balance.toNumber(), tokensAvailable - numberOfTokens); // Try to buy tokens different from the ether value return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: 1 }); }).then(assert.fail).catch(function(error) { assert(error.message.indexOf('revert') >= 0, 'msg.value must equal number of tokens in wei'); return tokenSaleInstance.buyTokens(800000, { from: buyer, value: numberOfTokens * tokenPrice }) }).then(assert.fail).catch(function(error) { assert(error.message.indexOf('revert') >= 0,  'cannot purchase more tokens than available'); }); }); it('ends token sale', function() { return DappToken.deployed().then(function(instance) { // Grab token instance first tokenInstance = instance; return DappTokenSale.deployed(); }).then(function(instance) { // Then grab token sale instance tokenSaleInstance = instance; // Try to end sale from account other than the admin return tokenSaleInstance.endSale({ from: buyer }); }).then(assert.fail).catch(function(error) { assert(error.message.indexOf('revert' >= 0, 'must be admin to end sale')); // End sale as admin return tokenSaleInstance.endSale({ from: admin }); }).then(function(receipt) { return tokenInstance.balanceOf(admin); }).then(function(balance) { assert.equal(balance.toNumber(), 999990, 'returns all unsold dapp tokens to admin'); // Check that the contract has no balance balance = web3.eth.getBalance(tokenSaleInstance.address) assert.equal(balance.toNumber(), 0); }); }); });Copy the code

A: congratulations! You’ve successfully learned how to build ERC-20 tokens and crowdfund sales smart contracts on Ethereum!

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

Share some interactive online programming tutorials related to blockchain such as Ethereum, EOS and Bitcoin:

  • Java Ethereum development tutorial, mainly for Java and Android programmers for blockchain Ethereum development web3J details.
  • Python Ethereum is a detailed explanation of blockchain ethereum development by Python engineers using Web3.py.
  • PHP Ethereum, mainly introduces the use of PHP for smart contract development interaction, account creation, transactions, transfers, token development, filters and transactions and other content.
  • Ethereum introductory course, mainly introduces smart contract and DAPP application development, suitable for entry.
  • Ethereum development advanced tutorial, mainly introduces the use of Node.js, mongodb, blockchain, IPFS to achieve decentralized e-commerce DApp combat, suitable for advanced.
  • C# ethereum, mainly explains how to use C# based development. Net ethereum applications, including account management, status and transactions, smart contract development and interaction, filters and transactions, etc.
  • This course will help you get a quick start on the development of EOS blockchain decentralized applications. It covers core knowledge points such as EOS tool chain, account and wallet, issuing tokens, development and deployment of smart contracts, and interaction between codes and smart contracts. Finally, the development of a notepad DApp will be completed using all knowledge points comprehensively.
  • Java development tutorial COINS, this course for beginners, content covers the core concepts of COINS, such as block mechanism, key chain store, decentralized consensus and script, trading and UTXO etc, also explained how to integrate the currency support functions in Java code, such as creating address wallet, tectonic naked trading, management, Is a rare bitcoin development course for Java engineers.
  • PHP currency development tutorial, this course for beginners, content covers the core concepts of COINS, such as block mechanism, key chain store, decentralized consensus and script, trading and UTXO etc, also explained how to integrated the currency support functions in PHP code, such as creating address wallet, tectonic naked trading, management, This is a rare bitcoin development course for Php engineers.
  • Tendermint blockchain development in detail, this course is suitable for engineers who want to use Tendermint blockchain development, the course content includes the core concepts of tendermint application development model, such as ABCI interface, Merkle tree, multi-version state library, etc., also includes the rich practical code such as token issuance. It is the best choice for go language engineers to quickly start blockchain development.

Huizhi net original translation, reprint please indicate the source. Develop your own cryptocurrency in Ethereum