返回章节列表
第 03 章入门

读取合约数据

掌握 useReadContract、useReadContracts 和实时数据订阅

5 课时2.5小时

概述

读取链上数据是 DApp 的基础能力。本章讲解如何高效地从智能合约读取数据。

ABI 与类型安全

wagmi 和 viem 提供完整的类型推导: 1. **ABI 定义**: 使用 `as const` 确保类型推导 2. **函数参数**: 自动推导参数类型 3. **返回值**: 自动推导返回类型 4. **错误处理**: 类型安全的错误处理

代码示例

读取 ERC20 代币信息

使用 useReadContract 读取 ERC20 代币余额

typescript
1'use client'
2
3import { useReadContract, useReadContracts } from 'wagmi'
4import { formatUnits } from 'viem'
5
6const erc20Abi = [
7 {
8 name: 'balanceOf',
9 type: 'function',
10 stateMutability: 'view',
11 inputs: [{ name: 'account', type: 'address' }],
12 outputs: [{ type: 'uint256' }],
13 },
14 {
15 name: 'symbol',
16 type: 'function',
17 stateMutability: 'view',
18 inputs: [],
19 outputs: [{ type: 'string' }],
20 },
21 {
22 name: 'decimals',
23 type: 'function',
24 stateMutability: 'view',
25 inputs: [],
26 outputs: [{ type: 'uint8' }],
27 },
28] as const
29
30const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
31
32export function TokenBalance({ address }: { address: `0x${string}` }) {
33 const { data: balance, isLoading } = useReadContract({
34 address: USDC_ADDRESS,
35 abi: erc20Abi,
36 functionName: 'balanceOf',
37 args: [address],
38 })
39
40 const { data: decimals } = useReadContract({
41 address: USDC_ADDRESS,
42 abi: erc20Abi,
43 functionName: 'decimals',
44 })
45
46 if (isLoading) return <span>加载中...</span>
47
48 const formatted = balance && decimals
49 ? formatUnits(balance, decimals)
50 : '0'
51
52 return <span>{formatted} USDC</span>
53}

批量读取合约数据

使用 useReadContracts 批量读取多个代币余额

typescript
1'use client'
2
3import { useReadContracts } from 'wagmi'
4import { erc20Abi } from 'viem'
5
6const tokens = [
7 { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', symbol: 'USDC' },
8 { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', symbol: 'USDT' },
9 { address: '0x6B175474E89094C44Da98b954EesdfAHD7e40C', symbol: 'DAI' },
10]
11
12export function MultiTokenBalance({ account }: { account: `0x${string}` }) {
13 const { data, isLoading } = useReadContracts({
14 contracts: tokens.map((token) => ({
15 address: token.address as `0x${string}`,
16 abi: erc20Abi,
17 functionName: 'balanceOf',
18 args: [account],
19 })),
20 })
21
22 if (isLoading) return <div>加载中...</div>
23
24 return (
25 <ul>
26 {tokens.map((token, i) => (
27 <li key={token.address}>
28 {token.symbol}: {data?.[i]?.result?.toString() ?? '0'}
29 </li>
30 ))}
31 </ul>
32 )
33}

相关资源

useReadContractviem formatUnits
上一章: 钱包连接与账户管理下一章: 写入合约与交易处理