If you’ve been paying attention to the Blockchain universe lately, you know that the center of action today is in Ethereum.

Ethereum isn’t a store of value like Bitcoin; it’s a decentralized, distributed computational network, running on a set of public nodes. Frontend developers can think of it like a public, distributed database they can access using an API.

You can build fully functional frontend web applications with integrated signon, lambda functions, and storage, just by using the Ethereum blockchain as your backend! It’s like a public, distributed version of AWS or Google Cloud. The most popular API for working with Ethereum today is provided by Metamask, a browser extension.

At Crowdbotics, we help people build blockchain software, Dapps, and Smart Contracts — among other things — and we get to see firsthand all the interesting ways people are applying blockchain technology to real-world problems.

Our goal at Crowdbotics is to help all sorts of people build complex software applications better and faster. That’s why we’re providing this complete guide on building Ethereum DApps with MetaMask.

We will be covering the following topics:

  • What is MetaMask?
  • How to get MetaMask
  • Funding MetaMask with Ether
  • What is Blockchain?
  • What is the Ethereum blockchain?
  • Decentralized Applications (DApps)
  • Ethereum Ecosystem
  • Web3 — Ethereum Javascript API
  • Detecting MetaMask and handling possible error states
  • Avoiding Race Conditions with onLoad()
  • Event listeners vs polling the interface

What is MetaMask?

MetaMask is a browser extension that allows web applications to interact with the Ethereum blockchain. For users, it works as an Ethereum wallet, allowing them to store and send any standard Ethereum-compatible tokens (so-called ERC-20 tokens).

For developers, it allows you to design and run Ethereum DApps right in your browser without running a full Ethereum node (which is what developers had to do before Metamask was available). MetaMask talks to the Ethereum blockchain for your web application.

Metamask includes a secure sign-on process, providing a user interface to manage your identities on different sites and sign blockchain transactions. It is easy to use on almost every browser.

Figure 1. MetaMask on Chrome.

Getting MetaMask

To use MetaMask, you will need to install it in your browser. You can choose between Google Chrome, Mozilla Firefox, Opera or Brave. In our case, we will be using Google Chrome browser. As a first step we need to go to the Chrome extension web store, and download the MetaMask extension. Once you are at the Chrome web store, just click on “Add to Chrome ” to add the MetaMask extension into your browser. Then click on “Add Extension” and immediately you will see the icon of MetaMask on the right part of the navbar navigation of your Chrome browser.

Figure 2. MetaMask is added to Chrome.

When MetaMask is installed in your browser, you will see an icon at the same level of the address bar on your browser. You should select the icon and proceed with login:

Figure 3. MetaMask icon will appear on the right side of the address bar.

Before Logging in you should accept Terms of use, Privacy notice and Phishing Warning. Scroll inside the panel in order to have the accept button available. When you accept each one, MetaMask login will appear.

Figure 4. Accept Terms of use, Privacy notice and Phishing Warning.
Figure 5. Insert a password and save the 12 words in a safe place.

Funding MetaMask with Ether

Now, we will learn how we can get some test Ether for our MetaMask. Real Ether cost money and have to be purchased on a site like Coinbase, but test Ether are available for free. First, you need to log in to your MetaMask account and then you should change your Network by clicking on “Main Network” that is located on the left side of the panel, and finally select “Ropsten Test Network”.

Figure 6. On the top-left side of panel you will see a dropdown to change Network.

Be sure to Verify that you are on the correct Network. Next click on the “BUY” button. A panel will appear called “BUY ETH”, finally click on the “Ropsten Test Faucet” button.

Figure 7. Buying 1ETH. Click on “Buy” button, then you click on “Ropsten test Faucet” button.

When you click on “Ropsten Test Faucet”, you will be redirected to https://faucet.metamask.io/. There, you can click on the green button to “request 1 ether from faucet”, wait for a few seconds and you will receive an address transaction, which is actually a confirmation. Now click on the MetaMask icon and verify your 1ETH for testing purposes.

Figure 8. MetaMask Ether Faucet view (https://faucet.metamask.io/).
Figure 9. Click on MetaMask icon to see your balance.

What is Blockchain?

There are several definitions regarding “Blockchain”. We’ll share just one:

"Blockchain technology’ means distributed ledger technology that uses a distributed, decentralized, shared and replicated ledger, which may be public or private, permissioned or permissionless, or driven by tokenized crypto economics or tokenless. The data on the ledger is protected with cryptography, is immutable and auditable and provides an uncensored truth."

On a blockchain, the data is decentralized; it’s distributed across every device connected to the blockchain. It’s a peer for which anyone can set up a node that replicates the necessary data for all nodes to reach an agreement and be compensated by users and app developers. This allows for user data to remain private and apps to be decentralized.

Figure 10. Blockchains are implemented on a peer-to-peer network of nodes, from https://www.ethereum.org/ 

What are Decentralized Applications (DApps)?

  • Decentralized applications are similar to conventional web applications, but that run on blockchain. While frontend web applications use APIs to interact with servers and databases, Dapps use Smart Contract interfaces to interact with the blockchain.
  • The code of a Dapp is client-side code (usually Javascript), running in a browser.
  • The backend of a Dapp is one or more Smart Contracts deployed on a blockchain.
  • Typically, to use a Smart Contract , you pay with cryptographic tokens like ETH rather than (for example) AWS or Google Cloud Credits.

Ethereum Ecosystem

  • Decentralized platform that runs smart contracts.
  • Provides developers with a foundational layer: a blockchain with a built-in Turing-complete programming language.
  • Works on peer-to-peer network protocols where each blockchain database is maintained and managed by multiple nodes.

Web3 — Ethereum Javascript API

  • A collection of libraries which allow you to interact with a local or remote ethereum node, using a HTTP or IPC connection.
  • Use it to communicate with an Ethereum node or transact with a smart contract deployed on the blockchain from inside a JavaScript or web application.
  • The MetaMask extension exposes the web3 API by an injected web3 object which you can access via JavaScript and does not support most synchronous web3 API methods.

MetaMask and error state handling

We will use web3 JS library and conditionals to manage error states. We have four cases:

Figure 11. Error state handling diagram
  1. If MetaMask is not installed
  2. If MetaMask is installed but it is locked
  3. If MetaMask is installed and unlocked and it doesn’t have sufficient balance to carry out a transaction
  4. If you have a MetaMask transaction, but reject the transaction.

CASE 1: To verify if MetaMask is installed or not.

CASE 2: To verify if MetaMask is locked or not.

   function isInstalled() {
   if (typeof web3 !== 'undefined'){
      console.log('MetaMask is installed')
   } 
   else{
      console.log('MetaMask is not installed')
   }
    }
function isLocked() {web3.eth.getAccounts(function(err, accounts){if (err != null) {console.log(err)}else if (accounts.length === 0) {console.log('MetaMask is locked')}else {console.log('MetaMask is unlocked')}});}

CASE 3: To verify if MetaMask has balance or not

    function checkBalance() {
   tokenInst.balanceOf(
      web3.eth.accounts[0], 
      function (error, result) {
      if (!error && result) {
         var balance = result.c[0];
         if (balance < balanceNeeded * (100000000)) {
            console.log('MetaMask shows insufficient balance')
            return false;
         }
         console.log('MetaMask shows sufficient balance')
         // Include here your transaction function here
      }
      else {
         console.error(error);
      }
      return false;
   });
}

CASE 4: If you have a MetaMask transaction, but reject the transaction.

Figure 12. MetaMask transaction
tokenInst.approve(
   addrHOLD, 
   truePlanCost, 
   gasPrice: web3.toWei('50', 'gwei') }, 
   function (error, result) {
   if (!error && result) {
      var data;
      console.log('approval sent to network');
      
      var url = 'https://etherscan.io/tx/' + result;
      var link = '<a href=\"" + 
                  url + 
                  "\" target=\"_blank\">View Transaction</a>';
      console.log('Waiting for approval ...');
     
      data = {
         txhash: result,
         account_type: selectedPlanId,
         txtype: 1, // Approval
      };
      apiService(data, '/transaction/create/', 'POST')
      .done(function (response) {
         location.href = response.tx_url;
      });
   } 
   else {
      console.error(error);
      console.log('You reject the transaction');
   }
});

All cases together:

var transactionApproval = true;
function validate() {
  if (typeof web3 !== 'undefined'){
    console.log('MetaMask is installed')
    web3.eth.getAccounts(function(err, accounts){
      if (err != null) {
        console.log(err)
      }
      else if (accounts.length === 0) {
        console.log('MetaMask is locked')
      }
      else {
        console.log('MetaMask is unlocked')
      
        tokenInst.balanceOf(
          web3.eth.accounts[0], 
          function (error, result) {
     
          if (!error && result) {
            var balance = result.c[0];
            if (balance < dappCost * (100000000)) {
              console.log('MetaMask has insufficient balance')
              return false;
            }
            console.log('MetaMask has balance')
            if (transactionApproval == true ){
              requestApproval();
              transactionApproval = false;
            }
          }
          else {
            console.error(error);
          }
          return false;
        });
      }
    });
  } 
  else{
    console.log('MetaMask is not installed')
  }
}
// request approval from MetaMask user
function requestApproval() {
  tokenInst.approve(
    addrHOLD,
    truePlanCost,
    { gasPrice: web3.toWei('50', 'gwei') },
    function (error, result) {
      
    if (!error && result) {
      var data;
      console.log('approval sent to network.');
      var url = 'https://etherscan.io/tx/' + result;
      var link = '<a href=\"" + 
                  url + 
                  "\" target=\"_blank\">View Transaction</a>';
      console.log('waiting for approval ...');
      data = {
        txhash: result,
        account_type: selectedPlanId,
        txtype: 1, // Approval
      };
      apiService(data, '/transaction/create/', 'POST')
      .done(function (response) {
        location.href = response.tx_url;
      });
    }
    else {
      console.error(error);
      console.log('You rejected the transaction');
    }
  });
}

Avoiding Race Conditions with onLoad()

Race conditions arise in software when an application depends on the sequence or timing of processes or threads for it to operate properly.

Event listeners vs polling the interface

You should decide between setting a time that means polling the interface or use event listeners. See an example:

  • Polling the Interface using an interval to check for account changes. This is the way that the Metamask provider recommends for avoiding the refreshing of page to see UI changes. Click here to see more.
var account = web3.eth.accounts[0];
var accountInterval = setInterval(function() {
  if (web3.eth.accounts[0] !== account) {
    account = web3.eth.accounts[0];
    updateInterface();
  }
}, 100);
  • Using web3 version 1.0.0, the MetaMask provider exposes an “update” event listener.
web3.currentProvider.publicConfigStore.on('update', callback);

Your callback will be passed an object which contains {selectedAddress, networkVersion}. You can modify the interface according to those attributes change or update.

To select event listeners is a better option than polling because you will improve performance, “.on('update')” is triggered without needing to loop.

Conclusion

As more people are becoming familiar with the technology, the creative potential for DApps continues to snowball.

MetaMask is one tool making development of this technology more accessible, and they are updating with new features all the time.

MetaMask is a bridge that allows you to visit the distributed web of tomorrow in your browser today. It allows you to run Ethereum dApps right in your browser without running a full Ethereum node.

Among other things, MetaMask is developing new ways to prevent possible attacks. To stay up-to-date with all the features they are working on, subscribe to MetaMask’s newsletter here.

If you have questions about building DApps with Metamask, or have suggestions for additional topics, let me know in the comments!

Special thanks to those who helped review and edited drafts of this post: Aleksa Miladinovic, William Wickey, and Anand Kulkarni