How to Connect to Somnia Network via Viem Library.

Somnia empowers developers to build applications for mass adoption. Smart Contracts deployed on Somnia will require front-end user interfaces to interact with them. These front-end user interfaces will require middleware libraries to establish a connection to the Somnia Network and enable interaction with Smart Contracts. In this Guide, you will learn how to use the Viem Library to establish a connection between your deployed Smart Contracts on Somnia Network and your Front-end User application. You will also learn how to perform READ and WRITE operations using Viem. Viem is a TypeScript interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum.

How does Viem enable UI interaction?

When a Smart Contract is programmed using any development tool such as RemixIDE, Hardhat or Foundry, the Smart Contract undergoes a “compilation” stage. Compiling a Smart Contract, among other things will convert the Solidity code into machine-readable bytecode. An ABI file is also produced when a Smart Contrac is compiled. ABI stand for Application Binary Interface. You can think of an ABI like the Interface that make it possible for a User Interface to connect with the Smart Contract functions in a way similar to how an API makes it possible to to connect a UI and Backend server in web2.

Example Smart Contract

Here is an example `Greeter.sol` Smart Contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

contract Greeter {
    string public name;
    address public owner;

    event NameChanged(string oldName, string newName);

    modifier onlyOwner() {
        require(msg.sender == owner, "Only the owner can perform this action");
        _;
    }

    constructor(string memory _initialName) {
     name = _initialName;
        owner = msg.sender;
    }

    function changeName(string memory _newName) external onlyOwner {
        string memory oldName = name;
        name = _newName;
        emit NameChanged(oldName, _newName);
    }

    function greet() external view returns (string memory) {
        return string(abi.encodePacked("Hello, ", name, "!"));
    }
}

Example ABI

When the Greeter Smart Contract is compiled, below is its ABI:

ABI

The ABI is an array of JSON objects containing the constructor, event, and four functions in the Smart Contract. Using a Library such as Viem, you can perform READ and WRITE operations, for each of the ABI objects. You can READ the events, and other “view” only methods. You can perform WRITE operations on the “changeName” function. A cursory look at each ABI method will help you understand the function and what can be accomplished by interacting with the method. For example:

{
"inputs": [  --->specifies it is an input, i.e. a WRITE function
{
"internalType": "string", ---> the data type
"name": "_newName", ---> params name
"type": "string" ---> data type
}
],
"name": "changeName", ---> function name
"outputs": [], ---> it does not have a return property
"stateMutability": "nonpayable", ---> It changes the Blockchain State without Token exchange, it simply stores information.
"type": "function" ---> It is a function.
},

How to use Viem.

To use Viem, it has to be installed in the project directory where you want to perform READ and WRITE operations. First, create a directory and initialize a new project using npm.

mkdir viem-example && cd viem-example

Initialize a project in the directory by running the command:

npm init -y

Install Viem by running the following command.

npm i viem

Set Up Viem

To connect to the deployed Example Greeter Smart Contract using Viem, it is necessary to have access to the Smart Contract’s ABI and its Contract Address. Viem sets up a “transport” infrastructure to connect with a node in the EVM Network and the deployed Smart Contracts. We will use some Viem methods to connect to your Smart Contract deployed on the Somnia Network. Viem has a `createPublicClient` and a `createWalletClient` method. The PublicClient is used to perform READ operations, while the WalletClient is used to perform WRITE operations. Create a new file index.js Import the method classes from the Library:

import { createPublicClient, createWalletClient, http, defineChain } from "viem";

The http is the transport protocol for interacting with the Node of the Somnia Blockchain via RPC. It uses the default Somnia RPC URL: https://dream-rpc.somnia.network. In the future developers can use RPC providers to avoid rate limiting.

To connect to Somnia, we will use the defineChain method. Add the following chain definition variable:

const SOMNIA = defineChain({
  id: 50311,
  name: "Somnia",
  nativeCurrency: {
    decimals: 18,
    name: "Ether",
    symbol: "STT",
  },
  rpcUrls: {
    default: {
      http: ["https://dream-rpc.somnia.network"],
    },
  },
  blockExplorers: {
    default: { name: "Explorer", url: "https://somnia-devnet.socialscan.io" },
  },
});

Set up PublicClient

We will start with setting up the publicClient to read view only methods. Set up a publicClient where the default Transport is http and chain is SOMNIA network created using the defineChain method.

const publicClient = createPublicClient({ 
  chain: SOMNIA, 
  transport: http(), 
}) 

Consume Actions

Now that you have a Client set up, you can interact with Somnia Blockchain and consume Actions! An example will be to call the greet method on the deployed Smart Contract. To do this, we have to create a file name abi.js and add the exported ABI in the file.

export const ABI = [//...ABI here]

In the index.js we can import the ABI file and start calling methods on the deployed Smart Contract. Import the ABI:

import { ABI } from "./abi.js";

Set Contract Address

const CONTRACT_ADDRESS = "0x2e7f682863a9dcb32dd298ccf8724603728d0edd";

This is an example Greeter Smart Contract deployed on Somnia DevNet

Write a Function `interactWithContract`:

const interactWithContract = async () => {
  try {
    console.log("Reading message from the contract...");


    // Read the "greet" function
    const greeting = await publicClient.readContract({
      address: CONTRACT_ADDRESS,
      abi: ABI,
      functionName: "greet",
    });
    console.log("Current greeting:", greeting);
 } catch (error) {
    console.error("Error interacting with the contract:", error);
  }
};


interactWithContract();

Open your terminal and run the following:

node index.js

You will see the response from the Smart Contract logged into the Console!

Congratulations, you have successfully performed a READ operation on your Smart Contract deployed on Somnia.

Set up Wallet Client

To perform a write operation, we will parse the `createWalletClient` method to a `walletClient` variable. It is important to understand that carrying out WRITE operations changes the state of the Blockchain, unlike READ operations, where you read the state of the Blockchain. So, to perform WRITE operations, a user will have to spend Gas, and to be able to spend Gas, a user will have to parse his Private Key from an EOA to give the Library masked permission to carry out transactions on behalf of the user. To read the Private Key from an EOA, we will use a Viem method:

import { privateKeyToAccount } from "viem/accounts";

Then, create a variable walletClient

const walletClient = createWalletClient({
  account: privateKeyToAccount($YOUR_PRIVATE_KEY),
  chain: SOMNIA,
  transport: http(),
});

The variable `$YOUR_PRIVATE_KEY` variable can be parsed using a dotenv file.

After sending a WRITE operation, we also have to be able to read the transaction to see the state changes. We will rely on a READ method to read a transaction, `waitForTransactionReceipt`. Update the `interactWithContract` function with the code below:

   // Write to the "changeName" function
    const txHash = await walletClient.writeContract({
      address: CONTRACT_ADDRESS,
      abi: ABI,
      functionName: "changeName",
      args: ["Saksham!"],
    });
    console.log("Transaction sent. Hash:", txHash);
    console.log("Waiting for transaction confirmation...");

    // Wait for the transaction to be confirmed
    const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
    console.log("Transaction confirmed. Receipt:", receipt);

    // Read the updated "greet" function
    const updatedGreeting = await publicClient.readContract({
      address: CONTRACT_ADDRESS,
      abi: ABI,
      functionName: "greet",
    });
    console.log("Updated greeting:", updatedGreeting);

Save the file and run the node command to see your responses logged into the console.

node index.js

Congratulations, you have successfully performed a WRITE operation on your Smart Contract deployed on Somnia. 🎉

Last updated