Skip to Content
Playground@core · ERC-20 Info

ERC-20 Token Info

Read token metadata (name, symbol, decimals, total supply) and holder balances using client.publicClient.readContract() with the built-in ERC20_ABI.

Change TOKEN to any ERC-20 address on testnet. The default is WCFX (Wrapped CFX on testnet), a contract that always has liquidity.

network:Testnet· chain 71
import { EspaceClient, EVM_TESTNET, ERC20_ABI, formatUnits } from '@cfxdevkit/core'

// WCFX (Wrapped CFX) — always-live ERC-20 on Conflux eSpace testnet
const TOKEN  = '0x2ED3dddae5B2F321AF0806181FBFA6D049Be47d8'
const HOLDER = '0x85d80245dc02f5A89589e1f19c5c718E405B56AA'
const SPENDER = '0x33e5E5B262e5d8eBC443E1c6c9F14215b020554d' // AutomationManager testnet

const client = new EspaceClient({
chainId: EVM_TESTNET.id,
rpcUrl:  EVM_TESTNET.rpcUrls.default.http[0],
})

console.log('-- Token: ' + TOKEN + ' --')

;(async () => {
// Batch-read all standard ERC-20 metadata in one round-trip
const [name, symbol, decimals, totalSupply] = await Promise.all([
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'name' }),
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'symbol' }),
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'decimals' }),
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'totalSupply' }),
])

console.log('-- Metadata --')
console.log('Name         : ' + name)
console.log('Symbol       : ' + symbol)
console.log('Decimals     : ' + decimals)
console.log('Total Supply : ' + formatUnits(totalSupply, decimals) + ' ' + symbol)

// Read holder balance and allowance
const [balance, allowance] = await Promise.all([
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'balanceOf', args: [HOLDER] }),
  client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'allowance', args: [HOLDER, SPENDER] }),
])

console.log('-- Holder ' + HOLDER.slice(0,10) + '... --')
console.log('Balance   : ' + formatUnits(balance, decimals) + ' ' + symbol)
console.log('Allowance : ' + formatUnits(allowance, decimals) + ' ' + symbol + ' (for AutomationManager)')
})().catch(console.error)


How it works

  1. ERC20_ABI is exported from @cfxdevkit/core and covers all standard ERC-20 methods (name, symbol, decimals, totalSupply, balanceOf, allowance, transfer, approve, transferFrom).
  2. client.publicClient.readContract({ address, abi, functionName, args }) is viem’s publicClient.readContract — accessible via the publicClient property on EspaceClient.
  3. Promise.all([...]) runs all four metadata reads in a single burst for efficiency.
  4. Wrap calls in Promise.all([...]) to batch multiple reads in one round-trip — essential for reading all metadata at once.
// Production import import { EspaceClient, ERC20_ABI, formatUnits } from '@cfxdevkit/core' const client = new EspaceClient({ chainId: 71, rpcUrl: 'https://evmtestnet.confluxrpc.com' }) const [name, symbol, decimals] = await Promise.all([ client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'name' }), client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'symbol' }), client.publicClient.readContract({ address: TOKEN, abi: ERC20_ABI, functionName: 'decimals' }), ])
Last updated on