SuperAPI AI Directory

contract

Agents & models

View repository

Updated 10-30 07:59

About this skill

Contract Skill

Purpose

This skill enables Claude to help users read from and write to smart contracts on EVM-compatible networks.

Key Concepts

  • ABI - Application Binary Interface, defines how to interact with a contract
  • View/Pure Functions - Read-only functions that don't modify state
  • State-Changing Functions - Functions that modify blockchain state (require gas)
  • EOA vs Contract - Externally Owned Account vs Smart Contract

Quick Start

Check if Address is a Contract

import { createPublicClient, http } from 'viem'
import { bsc } from 'viem/chains'

const client = createPublicClient({
  chain: bsc,
  transport: http()
})

const address = '0x...'

// Get bytecode - contracts have code, EOAs don't
const bytecode = await client.getBytecode({ address })

const isContract = bytecode && bytecode !== '0x'
console.log(`${address} is a ${isContract ? 'contract' : 'wallet (EOA)'}`)

Read Contract Data

import { createPublicClient, http } from 'viem'
import { bsc } from 'viem/chains'

// Example: Read ERC20 token info
const ERC20_ABI = [
  {
    name: 'name',
    type: 'function',
    inputs: [],
    outputs: [{ name: '', type: 'string' }]
  },
  {
    name: 'symbol',
    type: 'function',
    inputs: [],
    outputs: [{ name: '', type: 'string' }]
  },
  {
    name: 'decimals',
    type: 'function',
    inputs: [],
    outputs: [{ name: '', type: 'uint8' }]
  },
  {
    name: 'totalSupply',
    type: 'function',
    inputs: [],
    outputs: [{ name: '', type: 'uint256' }]
  }
]

const client = createPublicClient({
  chain: bsc,
  transport: http()
})

const tokenAddress = '0x...'

const [name, symbol, decimals, totalSupply] = await Promise.all([
  client.readContract({ address: tokenAddress, abi: ERC20_ABI, functionName: 'name' }),
  client.readContract({ address: tokenAddress, abi: ERC20_ABI, functionName: 'symbol' }),
  client.readContract({ address: tokenAddress, abi: ERC20_ABI, functionName: 'decimals' }),
  client.readContract({ address: tokenAddress, abi: ERC20_ABI, functionName: 'totalSupply' })
])

console.log(`Token: ${name} (${symbol})`)
console.log(`Decimals: ${decimals}`)
console.log(`Total Supply: ${totalSupply}`)

Write to Contract

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

const account = privateKeyToAccount('0x...')

const walletClient = createWalletClient({
  account,
  chain: bsc,
  transport: http()
})

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

// Example: Call a custom contract function
const CUSTOM_ABI = [
  {
    name: 'stake',
    type: 'function',
    inputs: [{ name: 'amount', type: 'uint256' }],
    outputs: []
  }
]

const hash = await walletClient.writeContract({
  address: '0xContractAddress...',
  abi: CUSTOM_ABI,
  functionName: 'stake',
  args: [parseEther('100')]
})

// Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash })
console.log('Transaction confirmed:', receipt.status)

MCP Tools

Tool Description
is_contract Check if address is contract or EOA
read_contract Call view/pure functions
write_contract Call state-changing functions

Common Patterns

Multi-Call (Read Multiple Values)

import { createPublicClient, http } from 'viem'
import { bsc } from 'viem/chains'

const client = createPublicClient({
  chain: bsc,
  transport: http()
})

// Read multiple values in one call
const results = await client.multicall({
  contracts: [
    {
      address: tokenAddress,
      abi: ERC20_ABI,
      functionName: 'name'
    },
    {
      address: tokenAddress,
      abi: ERC20_ABI,
      functionName: 'symbol'
    },
    {
      address: tokenAddress,
      abi: ERC20_ABI,
      functionName: 'decimals'
    }
  ]
})

console.log(results)

Simulate Transaction Before Sending

// Simulate the transaction to check if it would succeed
const { result } = await publicClient.simulateContract({
  address: contractAddress,
  abi: CONTRACT_ABI,
  functionName: 'someFunction',
  args: [arg1, arg2],
  account: account.address
})

console.log('Simulation result:', result)

// If simulation succeeds, execute the actual transaction
const hash = await walletClient.writeContract({
  address: contractAddress,
  abi: CONTRACT_ABI,
  functionName: 'someFunction',
  args: [arg1, arg2]
})

Decode Transaction Data

import { decodeFunctionData } from 'viem'

const txData = '0x...' // Transaction input data

const decoded = decodeFunctionData({
  abi: CONTRACT_ABI,
  data: txData
})

console.log('Function:', decoded.functionName)
console.log('Args:', decoded.args)

Encode Function Call

import { encodeFunctionData } from 'viem'

const data = encodeFunctionData({
  abi: CONTRACT_ABI,
  functionName: 'transfer',
  args: ['0xRecipient...', parseEther('100')]
})

console.log('Encoded data:', data)

Working with ABIs

Minimal ABI

You don't need the full ABI - just the functions you're calling:

// Only include what you need
const MINIMAL_ABI = [
  {
    name: 'balanceOf',
    type: 'function',
    inputs: [{ name: 'account', type: 'address' }],
    outputs: [{ name: '', type: 'uint256' }]
  }
]

Human-Readable ABI

Viem supports human-readable format:

import { parseAbi } from 'viem'

const abi = parseAbi([
  'function balanceOf(address account) view returns (uint256)',
  'function transfer(address to, uint256 amount) returns (bool)',
  'event Transfer(address indexed from, address indexed to, uint256 value)'
])

Security Warnings

  1. Verify contract source - Check on block explorer before interacting
  2. Understand what you're signing - Review function calls carefully
  3. Test on testnet first - Avoid costly mistakes
  4. Be careful with approvals - Unlimited approvals are risky
  5. Check for proxy contracts - Implementation may be different

Error Handling

try {
  const result = await client.readContract({
    address: contractAddress,
    abi: CONTRACT_ABI,
    functionName: 'someFunction'
  })
} catch (error) {
  if (error.message.includes('execution reverted')) {
    console.log('Contract reverted - check your inputs')
  } else if (error.message.includes('could not coalesce')) {
    console.log('ABI mismatch - verify contract ABI')
  } else {
    console.log('Error:', error.message)
  }
}

References