Skills agent-wallet-local-balance
Check native or token contract balances for an address using viem. Use when the user asks for wallet balance, native coin balance, ERC-20/token balance, or balance verification for an address.
install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/beardkoda/agent-wallets/local-wallet/balance" ~/.claude/skills/clawdbot-skills-agent-wallet-local-balance && rm -rf "$T"
manifest:
skills/beardkoda/agent-wallets/local-wallet/balance/SKILL.mdsource content
Check Address Balance
Runtime Requirements
- Runtime: Node.js 18+
- Required package:
viem - Required network input:
RPC_URL
Required Secrets / Inputs
- Required:
,address
,RPC_URLchain - Optional:
,tokenAddress
,decimalssymbol - No signer secret is required for read-only balance checks
Required Inputs
addressrpcUrl
(for examplechain
,mainnet
, or a custom chain object)sepolia- optional for token balance:
(contract address)tokenAddress- optional
anddecimals
(if known)symbol
Workflow
- Validate address with
.isAddress - Create a
.publicClient - If no
is provided, check native balance:tokenAddress- call
publicClient.getBalance({ address }) - convert with
formatEther
- call
- If
is provided, check contract token balance:tokenAddress- validate
withtokenAddressisAddress - call
with ERC-20publicClient.readContractbalanceOf - optionally read
/decimals
, then format withsymbolformatUnits
- validate
- Return raw and formatted values for the selected mode.
- If token metadata calls fail, return raw token amount and note missing metadata.
Viem Example (Native)
import { createPublicClient, http, isAddress, formatEther } from 'viem' import { sepolia } from 'viem/chains' const address = '0xabc...' if (!isAddress(address)) throw new Error('Invalid address') const publicClient = createPublicClient({ chain: sepolia, transport: http(process.env.RPC_URL!), }) const wei = await publicClient.getBalance({ address }) const eth = formatEther(wei) console.log({ address, wei: wei.toString(), eth })
Viem Example (Contract Token / ERC-20)
import { createPublicClient, http, isAddress, formatUnits } from 'viem' import { sepolia } from 'viem/chains' const erc20Abi = [ { type: 'function', name: 'balanceOf', stateMutability: 'view', inputs: [{ name: 'owner', type: 'address' }], outputs: [{ name: '', type: 'uint256' }], }, { type: 'function', name: 'decimals', stateMutability: 'view', inputs: [], outputs: [{ name: '', type: 'uint8' }], }, ] as const const address = '0xabc...' const tokenAddress = '0xdef...' if (!isAddress(address) || !isAddress(tokenAddress)) throw new Error('Invalid address') const publicClient = createPublicClient({ chain: sepolia, transport: http(process.env.RPC_URL!), }) const raw = await publicClient.readContract({ address: tokenAddress, abi: erc20Abi, functionName: 'balanceOf', args: [address], }) const decimals = await publicClient.readContract({ address: tokenAddress, abi: erc20Abi, functionName: 'decimals', }) const formatted = formatUnits(raw, decimals) console.log({ address, tokenAddress, raw: raw.toString(), formatted })
Response Template
- Address:
<address> - Chain:
<chain> - Mode:
ornativetoken - Native balance (wei):
(when mode is native)<wei> - Native balance (formatted):
(when mode is native)<formatted> - Token contract:
(when mode is token)<tokenAddress> - Token balance (raw):
(when mode is token)<raw> - Token balance (formatted):
(when mode is token)<formatted> - Status:
|successfailed - Next step:
<verify token decimals|switch RPC|recheck address>
Standard Response Contract
:actionbalance
: chain id/name usedchain
: queried wallet addressaddress
:txHashnull
:status
|successfailed
: one clear follow-up actionnext_step
Guardrails
- Validate address before querying.
- Validate
when token mode is requested.tokenAddress - Use read-only RPC for balance checks when possible.
- Never expose secret material while performing balance checks.
Failure Handling
- Invalid address or token contract address -> stop and request corrected input.
- RPC/network timeout -> retry once, then request alternate RPC endpoint.
- Token contract missing
-> return raw amount and optionally format with user-supplied decimals.decimals - Contract call revert/proxy edge case -> return native balance fallback plus contract read error details.