Integrating MetaMask with NestJS and Web3.js: A Detailed Guide

Cláudio Rapôso
4 min readJun 28, 2023

In this tutorial, we’ll step-by-step understand how to integrate MetaMask with NestJS using the Web3.js library. We will be creating a NestJS application that will interact with the Ethereum blockchain.

Prerequisites

Before we start, you need to:

  1. Create an account on Infura. It provides an API URL that we’ll use to connect to the Ethereum network.
  2. Set up a MetaMask account with an Ethereum wallet and its respective private key.

Configuring the Web3 Module

In NestJS, a module is a component that bundles related providers. Here, we’ll create a Web3 module, which will initialize the Web3 instance and configure the wallet and private key. This module will be responsible for providing the necessary configuration for our application to communicate with the Ethereum blockchain.

import { Module } from '@nestjs/common';
import Web3 from 'web3';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Web3Adapter } from './web3.adapter';

@Module({
imports: [ConfigModule],
providers: [
{
provide: 'Web3',
useFactory: (configService: ConfigService) => {
return new Web3(configService.get('INFURA_URL'));
},
inject: [ConfigService],
},
{
provide: 'Config',
useFactory: (configService: ConfigService) => {
return {
wallet: configService.get('WALLET'),
privateKey: configService.get('PRIVATE_KEY'),
};
},
inject: [ConfigService],
},
Web3Adapter,
],
exports: [Web3Adapter],
})
export class Web3Module {}

In this code:

  1. We’re creating a new module named Web3Module.
  2. We import Web3Adapter and Web3 along with ConfigModule and ConfigService from @nestjs/config to handle the application configuration.
  3. In the providers section, we are providing the Web3 instance and the wallet and private key configurations.
  4. The Web3 instance is created using the Infura URL (obtained from the environment variables), and the wallet and private key configurations are also obtained from the environment variables.
  5. Finally, we export Web3Adapter so it can be used in other modules.

Configuring the Web3 Adapter

Next, let’s set up the Web3Adapter service, which will be responsible for interacting with the Ethereum blockchain. It will have two functions: balance to check the wallet balance and transfer to transfer Ether to another wallet.

import { Inject, Injectable } from '@nestjs/common';
import Web3 from 'web3';

@Injectable()
export class Web3Adapter {
constructor(
@Inject('Web3')
private readonly web3: Web3,
@Inject('Config')
private readonly config: { wallet: string; privateKey: string },
) {}

async balance() {
const balance = await this.web3.eth.getBalance(this.config.wallet);
return this.web3.utils.fromWei(balance, 'ether');
}

async transfer(toWallet: string, value: number) {
const nonce = await this.web3.eth.getTransactionCount(
this.config.wallet,
'latest',
);

const transaction = {
to: toWallet,
value,
gas: 21000,
nonce,
};

const signedTx = await this.web3.eth.accounts.signTransaction(
transaction,
this.config.privateKey,
);

const tx = await this.web3.eth.sendSignedTransaction(
signedTx.rawTransaction,
);

return tx.transactionHash;
}
}

In this code:

  1. The balance function uses the web3 instance to get the wallet balance and converts the balance from Wei to Ether using web3.utils.fromWei.
  2. The transfer function first gets the nonce, which is the number of the next transaction to be processed from the wallet.
  3. It then creates a transaction containing the destination wallet, the value to be transferred, the gas for the transaction, and the nonce.
  4. The transaction is then signed using the private key of the wallet.
  5. Finally, the signed transaction is sent, and the transaction hash is returned.

Setting Up the Wallet Service, Controller, and Module

Now, let’s create the wallet service, controller, and module. The WalletService will utilize the Web3Adapter to implement its functions, the WalletController will provide endpoints to check the balance and transfer Ether, and the WalletModule will group everything together.

Service:

import { Injectable } from '@nestjs/common';
import { Web3Adapter } from '../adapters/web3/web3.adapter';

@Injectable()
export class WalletService {
constructor(private readonly web3Adapter: Web3Adapter) {}

async getBalance() {
return this.web3Adapter.balance();
}

async setTransfer(toWallet: string, value: number) {
return this.web3Adapter.transfer(toWallet, value);
}
}

In the WalletService service, we're simply calling the functions from the Web3Adapter.

Controller:

import { Body, Controller, Get, Post } from '@nestjs/common';
import { WalletService } from './wallet.service';

@Controller('wallet')
export class WalletController {
constructor(private readonly walletService: WalletService) {}

@Get()
getBalance() {
return this.walletService.getBalance();
}

@Post()
setTransfer(
@Body('toWallet') toWallet: string,
@Body('value') value: number,
) {
return this.walletService.setTransfer(toWallet, value);
}
}

In the WalletController, we're providing two endpoints. A GET to /wallet that returns the wallet balance, and a POST to /wallet that transfers Ether to another wallet.

Module:

import { Module } from '@nestjs/common';
import { WalletController } from './wallet.controller';
import { WalletService } from './wallet.service';
import { Web3Module } from 'src/utils/web3/web3.module';

@Module({
imports: [Web3Module],
controllers: [WalletController],
providers: [WalletService],
})
export class WalletModule {}

Finally, in the WalletModule module, we're importing the Web3Module we created earlier, the WalletController, and the WalletService.

Now you have an API that interacts with the Ethereum blockchain using MetaMask and Web3.js. Remember to properly set up your environment variables in the .env file.

INFURA_URL=<infura url>
WALLET=<user wallet>
PRIVATE_KEY=<metamask private key>

I hope this tutorial was helpful and informative. Integrating MetaMask with NestJS using Web3.js is a great way to interact with the Ethereum blockchain in an easy and secure way.

If you want to see the complete code, follow the link:

engcfraposo/nestjs-web3 (github.com)

If you want to listen in portuguese, follow the link too:

Integração do MetaMask com NestJS e Web3.js: Um Guia Detalhado | by Cláudio Rapôso | Jun, 2023 | Medium

--

--

Cláudio Rapôso
Cláudio Rapôso

Written by Cláudio Rapôso

Microsoft MVP | Software Architect | Teacher | Book Author | MCT | 12x Microsoft Certified Connect with me in https://www.linkedin.com/in/cfraposo