viem

SKILL.md

Viem for Celo

Viem is a lightweight TypeScript library with first-class Celo support. It powers wagmi and RainbowKit.

Source: https://viem.sh/docs/chains/celo

When to Use

  • Building dApps that interact with Celo
  • Sending transactions with alternative fee currencies
  • Reading contract state and blockchain data
  • Signing messages and transactions

Installation

npm install viem

Chain Configuration

Source: https://github.com/wevm/viem (chain definitions)

Mainnet

import { celo } from "viem/chains";

// Chain ID: 42220
// RPC: https://forno.celo.org
// Explorer: https://celoscan.io

Testnet (Celo Sepolia)

import { celoSepolia } from "viem/chains";

// Chain ID: 11142220
// RPC: https://forno.celo-sepolia.celo-testnet.org
// Explorer: https://celo-sepolia.blockscout.com

Custom Chain with Celo Config

import { defineChain } from "viem";
import { chainConfig } from "viem/celo";

export const customCeloChain = defineChain({
  ...chainConfig,
  id: 42220,
  name: "Custom Celo",
  // ...
});

Client Setup

Public Client (Read Operations)

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

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

// Read contract state
const balance = await publicClient.getBalance({
  address: "0x...",
});

Wallet Client (Write Operations)

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

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

const [address] = await walletClient.getAddresses();

Fee Currency Support

Celo allows paying gas fees in tokens other than CELO. Use whitelisted fee currency adapters.

Source: https://viem.sh/docs/chains/celo

Fee Currency Addresses - Mainnet

Token Adapter Address
USDC 0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B
USDT 0x0e2a3e05bc9a16f5292a6170456a710cb89c6f72

Fee Currency Addresses - Celo Sepolia

Token Adapter Address
USDC 0x4822e58de6f5e485eF90df51C41CE01721331dC0

Serialize Transaction with Fee Currency

import { serializeTransaction } from "viem/celo";
import { parseGwei, parseEther } from "viem";

const serialized = serializeTransaction({
  chainId: 42220,
  gas: 21001n,
  feeCurrency: "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B", // USDC adapter
  maxFeePerGas: parseGwei("20"),
  maxPriorityFeePerGas: parseGwei("2"),
  nonce: 69,
  to: "0x1234512345123451234512345123451234512345",
  value: parseEther("0.01"),
});

Send Transaction with Fee Currency

import { createWalletClient, custom, parseEther } from "viem";
import { celo } from "viem/chains";

const USDC_ADAPTER = "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B";

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

const [address] = await walletClient.getAddresses();

// Send transaction paying gas in USDC
const hash = await walletClient.sendTransaction({
  account: address,
  to: "0x...",
  value: parseEther("1"),
  feeCurrency: USDC_ADAPTER,
});

Contract Call with Fee Currency

const hash = await walletClient.writeContract({
  address: CONTRACT_ADDRESS,
  abi: CONTRACT_ABI,
  functionName: "transfer",
  args: [recipient, amount],
  feeCurrency: USDC_ADAPTER,
});

Celo Utilities

Parse Transaction

import { parseTransaction } from "viem/celo";

// Supports CIP-64, EIP-1559, EIP-2930, and Legacy transactions
const transaction = parseTransaction("0x7cf846...");

Serialize Transaction

import { serializeTransaction } from "viem/celo";

const serialized = serializeTransaction({
  chainId: 42220,
  feeCurrency: "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B",
  // ... other params
});

Reading Contract Data

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

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

const ERC20_ABI = [
  {
    name: "balanceOf",
    type: "function",
    stateMutability: "view",
    inputs: [{ name: "account", type: "address" }],
    outputs: [{ type: "uint256" }],
  },
] as const;

const balance = await publicClient.readContract({
  address: "0x765de816845861e75a25fca122bb6898b8b1282a", // USDm
  abi: ERC20_ABI,
  functionName: "balanceOf",
  args: ["0x..."],
});

Multicall

Batch multiple read calls efficiently:

const results = await publicClient.multicall({
  contracts: [
    {
      address: TOKEN_ADDRESS,
      abi: ERC20_ABI,
      functionName: "balanceOf",
      args: [userAddress],
    },
    {
      address: TOKEN_ADDRESS,
      abi: ERC20_ABI,
      functionName: "totalSupply",
    },
  ],
});

Important Notes

  • Viem is the recommended library for Celo (ethers.js and web3.js don't support feeCurrency)
  • Fee currency transactions use type 0x7b (CIP-64)
  • Transactions with fee currencies incur ~50,000 additional gas
  • Omitting feeCurrency defaults to paying in CELO
  • Use viem/celo for Celo-specific utilities (parseTransaction, serializeTransaction)

Dependencies

{
  "dependencies": {
    "viem": "^2.0.0"
  }
}

Additional Resources

Weekly Installs
1
GitHub Stars
6
First Seen
5 days ago
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1