Skip to content

Getting Started ​

This page sets up a viem environment that all the function-reference examples build on.

Install ​

bash
pnpm add viem

Clients ​

ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)

export const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(process.env.RPC_URL),
})

export const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http(process.env.RPC_URL),
})

Constants ​

ts
export const VAULT = '0x273DA948ACa9261043fbdb2a857BC255ECC29012' as const
export const USDC  = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as const

// USDC has 6 decimals; vault shares have 18 decimals (standard ERC-4626 default).
export const USDC_DECIMALS = 6
export const SHARE_DECIMALS = 18

ABI ​

Use the snippet files in this project:

  • snippets/abi.ts for vault functions (read + write) sourced from the contract interface

For standard share-token reads such as balanceOf and allowance, use viem's bundled erc20Abi.

Approving USDC ​

deposit and mint pull USDC from the caller, so they require an ERC-20 approval on USDC, not on the vault:

ts
import { parseUnits } from 'viem'
import { walletClient, publicClient } from './client'
import { USDC, VAULT, USDC_DECIMALS } from './constants'

const usdcAbi = [{
  type: 'function',
  name: 'approve',
  stateMutability: 'nonpayable',
  inputs: [
    { name: 'spender', type: 'address' },
    { name: 'value', type: 'uint256' },
  ],
  outputs: [{ name: 'success', type: 'bool' }],
}] as const

const amount = parseUnits('1000', USDC_DECIMALS) // 1000 USDC

const hash = await walletClient.writeContract({
  address: USDC,
  abi: usdcAbi,
  functionName: 'approve',
  args: [VAULT, amount],
})
await publicClient.waitForTransactionReceipt({ hash })

You only need to do this once per allowance window (or use a large value if you prefer infinite approvals).

Simulate before writing ​

Every example uses the simulate-then-write pattern. simulateContract runs the call against state and returns the human-readable revert reason if it would fail — much better than a raw execution reverted:

ts
const { request, result } = await publicClient.simulateContract({
  account,
  address: VAULT,
  abi: liteUsdVaultAbi,
  functionName: 'deposit',
  args: [amount, account.address],
})

const hash = await walletClient.writeContract(request)
const receipt = await publicClient.waitForTransactionReceipt({ hash })