TalentLayer’s Ether.js to Viem Migration

An Open Source How-To Guide

Gathin
TalentLayer
Published in
3 min readSep 19, 2023

--

Looking to get started with Viem……

Here is an open-source contribution that I have made to TalentLayer organization’s TalentLayer-Starter-Kit repository making a complete removal of ethers.js dependency and using viem instead through this Pull request.

I’m excited to share the changes I’ve made to ease your migration from ethers.js to Viem. I’ll do my best to cover all the modifications and provide relevant documentation links.

Introduction

Viem is a typeScript Interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum. An alternative to ethers.js and web3.js with a focus on reliability, efficiency, and excellent developer experience.

Version Details

"viem": "^1.10.9", 
"wagmi": "^1.4.1",

Chain Setup

Using defineChain we could set up custom chain configurations.

import { defineChain } from 'viem';
export const polygonMumbai = defineChain({
id: 80_001,
name: 'Polygon Mumbai',
network: 'maticmum',
nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
rpcUrls: {
alchemy: {
http: ['https://polygon-mumbai.g.alchemy.com/v2'],
webSocket: ['wss://polygon-mumbai.g.alchemy.com/v2'],
},
infura: {
http: ['https://polygon-mumbai.infura.io/v3'],
webSocket: ['wss://polygon-mumbai.infura.io/ws/v3'],
},
default: {
http: ['https://rpc-mumbai.maticvigil.com'],
},
public: {
http: ['https://rpc-mumbai.maticvigil.com'],
},
},
blockExplorers: {
etherscan: {
name: 'PolygonScan',
url: 'https://mumbai.polygonscan.com',
},
default: {
name: 'PolygonScan',
url: 'https://mumbai.polygonscan.com',
},
},
contracts: {
multicall3: {
address: '0xca11bde05977b3631167028862be2a173976ca11',
blockCreated: 25770160,
},
},
testnet: true,
});

To use existing chain configurations: Chains

Provider -> PublicClient

Provider in ethers.js is used as PublicCient in viem

  1. Initialize a Client with your desired Chain (e.g. mainnet) and Transport (e.g. HTTP).
 import { createPublicClient, http } from 'viem';
import { /*chainName*/ } from 'viem/chains';

const client = createPublicClient({
chain: /*chainName*/,
transport: http()
});

2. Use Wagmi’s hook for accessing viem Public Client.

 import { usePublicClient } from 'wagmi';
const publicClient = usePublicClient({ /*chainId*/ });

Signer -> WalletClient

Signer in ethers.js is used as WalletCient in viem

  1. Initialize a Client with your desired Chain (e.g. mainnet) and Transport (e.g. custom).
 import { createWalletClient, custom } from 'viem';
import { /*chainName*/ } from 'viem/chains';

const client = createWalletClient({
chain: /*chainName*/,
transport: custom(window.ethereum)
});

2. Use Wagmi’s hook for accessing viem Wallet Client.

 import { useWalletClient } from 'wagmi';
const { data: walletClient } = useWalletClient({ /*chainName*/ });

Contract

-> Read Contract

Here is how I implemented the function to read from the Contract.

// ETHER.JS
const ERC20Token = new Contract(rateToken, ERC20.abi, signer);
const balance = await ERC20Token.balanceOf(signer.getAddress());

// VIEM
const balance: any = await publicClient.readContract({
address: rateToken,
abi: ERC20.abi,
functionName: 'balanceOf',
args: [walletClient.getAddresses()]
});

Docs: readContract

-> Write Contract

Here is how I implemented the function to read from the Contract.

 //ETHERS.JS
const contract = new ethers.Contract(
config.contracts.talentLayerId,
TalentLayerID.abi,
signer,
);
const tx = await contract.updateProfileData(user.id, cid);

//VIEM
const tx = await walletClient.writeContract({
address: config.contracts.talentLayerId,
abi: TalentLayerID.abi,
functionName: 'updateProfileData',
args: [user.id, cid],
account: address,
});

Docs: writeContract

-> Simulate Contract

The simulateContract function simulates/ validates a contract interaction. This is useful for retrieving return data and revert reasons of contract write functions. It is almost identical to readContract, but also supports contract write functions.

The code pairs simulate contract and writeContract is better than using writeContract directly as it provides the option to validate the contract before writing.

const {request} = await publicClient.simulateContract({
address: config.contracts.talentLayerEscrow,
abi: TalentLayerEscrow.abi,
functionName: 'approve',
args: [config.contracts.talentLayerEscrow, value]
});
const tx1 = await walletClient.writeContract(request);

Docs: Simulate Contract

Utils

-> formatUnits

const formattedValue = ethers.utils.formatUnits(value, token.decimals); import { formatUnits } from 'viem'; const formattedValue = formatUnits(BigInt(value), token.decimals);

Docs: formatUnits

-> formatEther

//ETHERS.JS
const formattedValue = ethers.utils.formatUnits(value, token.decimals);

//VIEM
import { formatUnits } from 'viem';
const formattedValue = formatUnits(BigInt(value), token.decimals);

Docs: formatEther

-> parseUnits

//ETHERS.JS
const val = ethers.utils.parseUnits(value.toString(), 'ether');

//VIEM
import { parseUnits } from 'viem';
const fee = parseUnits(value.toString(),decimals);

Docs: parseUnits

-> parseEther

//ETHERS.JS
const fee = ethers.utils.parseUnits(value.toString(), 'ether').toBigInt()

//VIEM
import { parseEther } from 'viem';
const fee = parseEther(value.toString());

Docs: parseEther

Let’s Connect 👋

Final thoughts

I hope this article has been helpful to you. Please feel free to reach out if you have any questions. Your thoughts, suggestions, and corrections are more than welcome.

Special credits to Kirsten & Romain from TalentLayer Team for their constant guidance and support of my work. TalentLayer is an open protocol and developer toolkit for building better hiring platforms.

Originally published at https://gathin.hashnode.dev.

--

--

Gathin
TalentLayer

⚒️Opensource Blockchain Developer 🏆5x Hackathon winner 🗽Founding member/Developer (Web3 Startup) 💣Failed 2 micro saas startups