Skip to main content

Viem

Overview

Viem is a high-performance, TypeScript-first Ethereum development library, providing robust tools for interacting with blockchains, smart contracts, and accounts. It offers first-class support for chains implemented on the OP Stack, including Soneium Minato.

Install

To install Viem, run the following command:

$ pnpm i viem

Setting Up the Client & Transport

To begin using Viem, set up your client and transport mechanism as shown below:

import { createPublicClient, http } from 'viem';
import { soneiumMinato } from "viem/chains";

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

Reading Data from Soneium Minato

You can use the Public Client to read data from Soneium Minato using Public Actions.

Public Action is an action that maps one-to-one with a "public" Ethereum RPC method (eth_blockNumber, eth_getBalance, etc). They are used with a Public Client.

For instance, to get the balance of a specific wallet address, you can use the getBalance method:

import { publicClient } from './client'

const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
})
console.log(balance); // 10000000000000000000000n (wei)

Writing Data to Soneium Minato

To send transactions or interact with accounts, you need to create a Wallet Client using createWalletClient. This allows you to manage accounts, sign messages, and execute transactions via Wallet Actions. The createWalletClient function sets up a Wallet Client with a given Transport.

Here’s how to set up a Wallet Client:

import { createWalletClient, custom } from 'viem'
import { soneiumMinato } from "viem/chains";

const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' });

const walletClient = createWalletClient({
account,
chain: soneiumMinato,
transport: custom(window.ethereum),
});

// Example of sending a transaction
walletClient.sendTransaction({ ... });

Interacting with Smart contracts

Viem allows you to interact with smart contracts in a type-safe way by creating a Contract Instance with a specific ABI and contract address. The instance is created using the getContract function.

Below is an example of interacting with an ERC20 contract on Soneium Minato:

import { getContract, erc20Abi } from 'viem';
import { publicClient } from './client';
import { USDC_ADDRESS, SENDER_ADDRESS, SPENDER_ADDRESS } from './config'


const contract = getContract({
address: USDC_ADDRESS,
abi: erc20Abi,
client: publicClient,
});

// Read the value from the contract
const allowance = await contract.read.allowance([SENDER_ADDRESS, SPENDER_ADDRESS]);

// Send contract function
const amount = "1000000";

const txParam = {
account: SENDER_ADDRESS,
address: USDC_ADDRESS,
abi: erc20Abi,
functionName: "approve",
args: [SPENDER_ADDRESS, amount],
};

const { request } = await publicClient.simulateContract({
...txParam,
});

const hash = await walletClient.writeContract(request);

Getting Started with OP Stack

Viem simplifies interacting with OP Stack features, allowing developers to extend their Client with OP Stack Actions.

1. Extend Client with the OP Stack

You can extend the Public Client with OP Stack Actions (Read more):

import { createPublicClient, http } from 'viem';
import { soneiumMinato } from "viem/chains";
import { publicActionsL2 } from 'viem/op-stack';

const publicClient = createPublicClient({
chain: soneiumMinato,
transport: http(),
}).extend(publicActionsL2());

2. Consume OP Stack Actions

With your OP Stack Client ready, you can now interact with OP Stack-specific actions, such as estimating the total gas required for contract execution:

import { createPublicClient, http } from 'viem';
import { soneiumMinato } from "viem/chains";
import { publicActionsL2 } from 'viem/op-stack';
import { SENDER_ADDRESS, CONTRACT_ADDRESS } from './config'
import { tokenAbi } from './abi'

const publicClient = createPublicClient({
chain: soneiumMinato,
transport: http(),
}).extend(publicActionsL2());

const gas = await publicClient.estimateContractTotalGas({
account: SENDER_ADDRESS,
address: CONTRACT_ADDRESS,
abi: tokenAbi,
functionName: 'mint',
});