Blockchain : Day 2 — EtherJS + VueJS

blockchain Jan 08, 2022

# Overview

In previous post, we discussed about creating and deploying smart contract using Hardhat on Ganache. We also tested the functionality of our simple smart contract using hardhat console . Console tools is good for testing purpose but sooner or later we need to build the real application which can interact with our created contract. There are some libraries that help us with this task, among of them I found those two famous

  • Web3JS: It is a collection of libraries that allow you to interact with a local or remote Ethereum node using HTTP, IPC or WebSocket.
  • Ethers : The ethers.js library aims to be a complete and compact library for interacting with the Ethereum Blockchain and its ecosystem.

From the description, it is hard to say which one is better but to my investigation, ethers seem to hava some advance features that web3js does not.

Announcing ethers.js — a web3 alternative

L4 Ventures and Richard Moore are proud to announce the most recent version of ethers.js, a feature-complete library…

medium.com

One major difference between ethers.js and web3 is how they handle key management and interaction with the ethereum blockchain. Web3 assumes that there is a local node connected to the application. That node is assumed to store keys, sign transactions, and interact with and read the ethereum blockchain. In reality, this is not often the case — most users are not running geth locally. Metamask effectively emulates that environment through a browser application, and so most web3 apps require Metamask to hold keys, sign transactions, and interact with the ethereum mainnet.( Cited L4V )

So I decided use etherjs in building our front-end app. I also decided to choose VueJS as the front-end framework. It is not because VueJS has some outstanding features that support etherjs but only because I used to working on VueJS.

  • Ethers
  • VueJS

# Front-end app setup

The first step is to create the front-end app which we has already done in previous post.

$vue create hello-blockchain 
$cd hello-blockchain

Then we need to install ethers :

$npm install --save ethers

According to ether’s manual it is very simple to import ethers and use it in our app:

import { ethers } from "ethers";

So I tried to import ethers in my main.js as below and it did not work.


import Vue from 'vue'
import router from './router'
import { ethers } from "ethers";
import App from './App.vue'

Vue.config.productionTip = false
Vue.use(ethers);
new Vue({   
	router,   
	render: h => h(App),
}).$mount('#app')

I could not use ethers in my Vue component using neitherthis.ethers nor Vue.ethers. I realized that the problem could ethers is not in the shape of Vue plugin. So I decided to create my own ethers plugin.

  • Create the plugins folder
$mkdir plugins
$cd plugins
  • Create an ethers plugin called ethers.js
$touch ethers.js
  • I did a simple trick to wrap ethers library and install it as a Vue Plugin:
"use strict";
import { ethers } from 'ethers';
Plugin.install = function(Vue) {
   Vue.prototype.ethers = ethers;
   Object.defineProperties(Vue.prototype, {
     $ethers: {
        get() {
         return ethers;
        }
     },
  });
};
export default Plugin;
  • Make use of newly created ethers plugin instead of importing ethers library in main.js:
import Vue from 'vue'
import router from './router'
import ethers from "./plugins/ethers";
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ethers);
new Vue({
   router,
   render: h => h(App),
}).$mount('#app')

From now on I could use this.$ethers in my components.

# Connection setup

Now it is time to do some basic steps to connect our app to ganache and interact with our contract using code. Let use the existing component HelloWorld.vue for now.

  • Define component datas structures :
data() {
   return {
   currentAccount: null,
   currentContract : null,
   contractAddress: "<Your deployed contract Address>"
   };
},
  • We want to check if our app is connected to MetaMask every time component is mounted so we did like below :
mounted(){
    this.checkConnectedWalletExist();
},
  • checkConnectedWalletExists() is defined in component’smethods part. This function return true if we have already connected to MetaMask and false if we haven’t.
methods:{
   checkConnectedWalletExist: async function(){
     try {
      const { ethereum } = window;
      if (!ethereum) {
        alert("Make sure you have metamask!");
        return false;
      } else {
        console.log("We have the ethereum object", ethereum);
     }
     const accounts = await ethereum.request({ method: "eth_accounts" });
     if (accounts.length !== 0) {
         const account = accounts[0];
         console.log("Found an authorized account:", account);
         this.currentAccount = account;
         return true;
     } else {
         console.log("No authorized account found");
         return false;
      }
   } catch (error) {
      console.log(error);
      return false;
   }
},
  • In case we have not connected to MetaMask, we asked user to do so by clicking on Connect Wallet button
<h3>Connect Wallet</h3>
<div v-if="!currentAccount">
     <button class="primaryButton" @click="connectWallet">Connect Wallet</button>
</div>
  • Clicking on Connect Wallet button will in turn trigger the method connectWallet() which is defined as below
connectWallet: async function (){
 try {
   const { ethereum } = window;
   if (!ethereum) {
       alert("Get MetaMask!");
      return;
   }
   const accounts = await ethereum.request({
        method: "eth_requestAccounts",
   });
   console.log("Connected", accounts[0]);
   this.currentAccount = accounts[0];
 } catch (error) {
   console.log(error);
 }
},
  • Now as we have already connected to wallet, it is time to refer to our deployed contracts :
<div v-if="!currentContract">
    <button class="primaryButton" @click="attachContract">Attach Contract</button>
</div>
  • Contract reference :
attachContract: async function() {
	const provider = new 
    this.$ethers.providers.JsonRpcProvider("http://127.0.0.1:7545");
	const signer = provider.getSigner()
	//const network = await provider.getNetwork();
	//console.log(network);
	const abi = Greeter.abi;
	// The Contract object
	this.currentContract = new this.$ethers.Contract(this.contractAddress, abi, signer);
	console.log(await this.currentContract.symbol());
}

Please noted that http://127.0.0.1:7545 is the RCP address of Ganache. Of course it is not convenient to create providers here and we gonna put it in store later but it is ok for now. The reason I put blockchain folder under Vue folder project is for easily reference to combined ABI

import Greeter from '../../blockchain/artifacts/contracts/Greeter/Greeter.json'

# End

So we finished step 2 in configuring EtherJS to work with our VueJS project. See you in Day 3.

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.