Buillding Crypto Wallet with Ethers.js and Node.js

Introduction

Ethers.js is a toolkit in the field of Ethereum development. It simplifies the development process for developers. Let's explore the role that Ethers.js plays in Ethereum-related tasks and in enhancing accessibility to the development process by creating a crypto wallet.

Significance of Ethers.js

Ethers.js is like a helpful friend for developers diving into Ethereum, which is this cool decentralized platform with blockchains, smart contracts, and lots of interesting applications. Imagine Ethers.js as a superhero tool, written in JavaScript, that makes it way easier for developers to do stuff with Ethereum. Getting into Ethereum development might seem a bit tricky, especially with all its special features and complex stuff. That's where Ethers.js comes to the rescue! It's like your trusty sidekick, offering tools that are easy to use and efficient.

Key Features of Ethers.js

  • Wallet Management: Ethers.js makes creating and managing Ethereum wallets super easy. Developers can quickly create new wallets, bring in existing ones, and handle wallet tasks effortlessly.
  • Smart Contract Interactions: Ethers.js makes working with Ethereum smart contracts easy. It helps deploy contracts, use functions, and manage events smoothly, making things simple for developers.
  • Blockchain Interaction: Ethers.js makes talking to the Ethereum blockchain a breeze. Whether you're checking transactions, balances, or history, Ethers.js keeps things simple for developers.

Ethers.js is like a gateway to Ethereum for developers, making it easy to tap into its possibilities without getting stuck in complexities. As we explore more, you'll see it's not just a handy tool but a spark for innovation in Ethereum development.

Now we have the basic overview of the ethers.js and its capabilities. Let's create a crypto wallet application using ethers.js and node.js.

Creating a crypto wallet

Let's create a wallet step by step.

Prerequisites

We are going to create a wallet that will be able to create a new account, import the existing account, and show the available balance and transaction history. We will achieve this using Node.js, HTML, and CSS, so you should have a basic knowledge of these technologies and a basic knowledge of Blockchain. Your system should have Node.js installed on it, if not then download it from the official site of Node.js.

Setting Up the Project

Once the installation of Node.js is done, create a new folder with the name of your choice as I have created it with the "etherjs-demo" name. Now open this folder into the command prompt or terminal and enter the following command.

npm init -y

this command will initiate the node project in this directory and a new JSON file will be created named "package.json". If you do not get the same result try checking whether you have successfully installed the node or not. You can check that by running the following command in the command prompt.

node -v

It will show you the version of the installed node.

Install Required Libraries

In this application, we are going to use the following libraries.

  • express: It is a web application framework written in JavaScript and hosted on Node.js. We will use it to create our web application.
  • ejs: EJS stands for Embedded JavaScript used to handle templates.
  • body-parser: This package is used to parse the data of the body on the server side.
  • ethers: We will use this package to interact with the Ethereum or Polygon blockchain.

To install these libraries run the following command.

npm install express ejs body-parser ethers

Now we have installed all required libraries, let's move to the next step.

Create app file

Now create a JavaScript file named "app.js" file and require(import) the express framework in this file. And add get, post route, and port number for your web application.

const express = require('express'); 

const app = express(); 
const PORT = 3000; 

app.get('/', (req, res) => {
    res.send('Hello');
});

app.listen(PORT, (error) =>{ 
    if(!error) 
        console.log("Server is Successfully Running, and App is listening on port "+ PORT); 
    else 
        console.log("Error occurred, server can't start", error); 
    } 
); 

Now run the following command to start the server.

node app.js

Then visit the 3000 port of localhost by using any browser and you will see "Hello" on the screen. So our application is good to go so let's move to the next step.

Now require the "ejs" library to render the templates and create the ejs template files.

const express = require('express'); 
const ejs = require('ejs');

const app = express(); 
const PORT = 3000; 

app.use(express.static(path.join(__dirname, 'public')));
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');

app.get('/', (req, res) => {
    res.send('Hello');
});

app.listen(PORT, (error) =>{ 
    if(!error) 
        console.log("Server is Successfully Running, and App is listening on port "+ PORT); 
    else 
        console.log("Error occurred, server can't start", error); 
    } 
); 

Let's create our template file. First Create the "views" named folder in the root directory then inside the "views" directory create a subfolder named "partial" where we will put the code of header and footer files. Create a "header.ejs" file and write the following code into it.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
    <link rel="stylesheet" href="/css/style.css">
</head>

Create a "footer.ejs" file and write the following code into it.

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</html>

Now in the "views" directory create a file named "index.ejs" It will be the landing page of our application.

<%- include('partial/header') %>
<body>

    <div class="container">
        <header>
            <h1><%= pageTitle %></h1>
        </header>
    
        <section>
            <div class="wallet-info">
                    <div class="wallet-card">
                        <div class="w-img">
                                <image src="images/cw-bg.png"></image>
                        </div>
                        <div class="text-center mb-3">
                                <a href="/create-account"><button class="btn btn-primary">Create New Account</button></a>
                                <a href="/import-account"><button class="btn btn-primary" >Import Account</button></a>
                            </div>
                    </div>
                
                <!-- Add more wallet information here -->
            </div>
        </section>
    </div>

</body>

<%- include('partial/footer') %>

On this page, we have imported the header and footer by using include.

Let's style this page and add the images. Create a public folder in the root directory, then inside the public folder create a new folder named css and in css folder create a new css file named "style.css" and write the following code in it.


    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: #f5f5f5;
    }

    header {
        background-color: #333;
        color: #fff;
        padding: 10px;
        text-align: center;
    }

    section {
        margin: 20px;
    }

    .wallet-info {
        background-color: #fff;
        padding: 20px;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }

    .transaction-history {
        background-color: #fff;
        margin-top: 20px;
        padding: 20px;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }
    .wallet-card{
        height: 45%;
        width: 45%;
        margin-left: 25%;
        border: solid 1px #e3d2d2;
        border-radius: 5px;
    }
    .pass textarea{
    height: 100px;
    width: 500px;
    border-radius: 5px;
    margin-left: 30%;
    }

In the public folder create a new folder to store the image files named "images" and provide the path of your image in the image tag in an index.ejs file.

Then update the app.js file as follows.

const express = require('express'); 
const ejs = require('ejs');

const app = express(); 
const PORT = 3000; 

app.use(express.static(path.join(__dirname, 'public')));
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');

app.get('/', (req, res) => {
    res.render('index', {
        pageTitle: 'Crypto Wallet'
    });
});

app.listen(PORT, (error) =>{ 
    if(!error) 
        console.log("Server is Successfully Running, and App is listening on port "+ PORT); 
    else 
        console.log("Error occurred, server can't start", error); 
    } 
); 

Now run the following command.

node app.js

Navigate to the locahost:3000 and the output will be as follows.

etherjs-home-output

We will add more pages for create and import functionality. I am adding the code of the whole application in this article, you can download it and check out the code of all pages. For now, we will discuss the code that will interact with the blockchain. Let's go to the app.js file import the ethers library and add the route and method for creating a new account functionality.


const ethers = require('ethers');

app.get('/create-account', (req, res) => {

    try {
        const wallet = ethers.Wallet.createRandom();
        let newWallet = {
            "message": "Success",
            "Mnemonic": wallet.mnemonic.phrase.toString(),
            "Address": wallet.address.toString(),
            "PrivateKey": wallet.privateKey.toString()
        }
        res.render('create', {
            newWallet: newWallet
        });
    }
    catch {
        result = {
            "message": "error"
        }
        res.send(result)
    }
    
}); 

In this code, we are using the "createRandom" library function of the wallet to create a new account. Now add the route and method for importing existing account functionality.

app.get('/import-account', (req, res) => {
    res.render('import', {
        pageTitle: 'Import Account'
    });
});

app.post('/import', async (req, res) => {
    try {
        let mnemonic = req.body.mnemonic;
        let result = await generateAccountFromMnemonic(mnemonic);
        var balance = await provider.getBalance(result.Address);
        balanceInEthers = await ethers.utils.formatEther(balance);
        var history = await etherscanProvider.getHistory(result.Address);       
        res.render('home', {
            result: result,
            balance: balanceInEthers,
            history:history
        });
    }
    catch(error) {
        let result = {
            "message": error
        }
        res.send(result)
    }
});

function generateAccountFromMnemonic(mnemonic) {
    try {
       const wallet = ethers.Wallet.fromMnemonic(mnemonic);
        //const wallet = ethers.Wallet.
        const address = wallet.address;
        const privateKey = wallet.privateKey;

        result = {
            "message": "Success",
            "Mnemonic": mnemonic,
            "Address": address,
            "PrivateKey": privateKey
        }

        return result;
    }
    catch(Error) {
        result = {
            "message": Error.message 
        }
        return result;
    }

}

In this code, we have added a get endpoint for the import account that will render a form where users can provide their passphrase and submit. The post endpoint is to handle that submitted data and provide the response interacting with the chain based on that data.

Now run the application by the command "node app.js" and click on the "Create New Account" button. The output will be as follows.

create-account-output

The account is created in the testnet network of the Ethereum blockchain and it provides the Pass Phrase, Address, and Private Key. Let's move to the next functionality of our application. Go to the Homepage and click on the "Import Account" button. The output will be as follows.

import-account-output

Enter your passphrase and click on "Import".

imported-account-output

We have successfully imported our account into our wallet.

Conclusion

The journey into Ethereum development with Ethers.js doesn't end here. This project serves as a foundation for further exploration, innovation, and the creation of more sophisticated decentralized applications. As you delve deeper into the Ethereum ecosystem, Ethers.js remains a steadfast companion, empowering you to unlock the full potential of blockchain technology. Happy coding!


Similar Articles