在 Sonic Blaze 测试网上用 USDC 快速构建转账 DApp

·

只需 30 分钟,你就能在 Sonic EVM Layer-1 区块链上完成一次去中心化的数字美元转账体验。

项目概览

使用 Circle 原生发行的 USDC,通过 Viem + React + TypeScript 生态,无需后端服务器,即可完成“钱包连接 → 查询余额 → 转账 USDC → 回执确认”的全流程。下文会以 Sonic Blaze 测试网 为主要环境,避免真实资金风险。
关键词:USDC、Sonic 区块链、React、钱包连接、EVM、Blaze 测试网、CCTP、数字美元


开发前准备

1. 工具与环境

初学者常见问题

Q1. Blaze 测试网水龙头在哪里?
官方文档每 24 小时可领取 0.2 S;若遇高峰期,可加入社区 Discord 额外申请。

Q2. 为何不建议用主网直接测试?
Blaze 测试网与主网数据隔离,链速度更快,费率极低,适合连续调试。


步骤合理拆解

阶段关键词预估耗时
项目初始化Vite、React5 分钟
链端配置Sonic Blaze、Viem5 分钟
合约调用USDC ABI、转账方法10 分钟
界面封装React Hooks、事件驱动10 分钟

动手实践:从零到转账

2. 创建并初始化项目

# 创建目录
mkdir usdc-dapp && cd usdc-dapp
npm init -y

# 安装依赖
npm install react react-dom \
            typescript vite @vitejs/plugin-react \
            viem @types/react @types/react-dom

修改 package.json,确保出现:

{
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

运行 npm run dev,浏览器打开 http://localhost:5173 立即预览空壳页面。

👉 单击立刻查看模板代码配套最佳实践,无缝对接区块链行情数据


3. 配置链端客户端与 USDC 合约信息

3.1 创建 src/clients.ts

import { http, createPublicClient, createWalletClient, custom } from 'viem'
import { sonicBlazeTestnet } from 'viem/chains'

declare global {
  interface Window { ethereum?: any }
}

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

export const walletClient = createWalletClient({
  chain: sonicBlazeTestnet,
  transport: custom(window.ethereum),
})

3.2 定义 USDC 合约常量 src/constants.ts

export const USDC_CONTRACT_ADDRESS =
  '0xA4879Fed32Ecbef99399e5cbC247E533421C4eC6'

export const USDC_ABI = [
  {
    constant: false,
    inputs: [
      { name: '_to', type: 'address' },
      { name: '_value', type: 'uint256' },
    ],
    name: 'transfer',
    outputs: [{ name: '', type: 'bool' }],
    type: 'function',
  },
  {
    constant: true,
    inputs: [{ name: '_owner', type: 'address' }],
    name: 'balanceOf',
    outputs: [{ name: 'balance', type: 'uint256' }],
    type: 'function',
  },
] as const

常见问题

Q3. 我可以用其他工具包吗?
当然可以。Web3.js、Ethers.js 也能完成,但 Viem 对 TypeScript 类型支持更完备,大幅提升开发体验。

Q4. ABI 不完整会影响转账吗?
如果我们仅用到 balanceOftransfer 两条函数,现有 ABI 足够;如需 Metamask 额外签名提示,再补充编码即可。


4. 构建 React 交互界面 src/App.tsx

核心状态与流程:

  1. 点击 连接钱包
  2. 读取 USDC 余额
  3. 填写 接收地址与金额(USDC)
  4. 点击 转账 → 等待 TransactionHash → 读取 Receipt
import { useEffect, useState } from 'react'
import { publicClient, walletClient } from './clients'
import { USDC_CONTRACT_ADDRESS, USDC_ABI } from './constants'
import { formatUnits, parseUnits } from 'viem'

export default function App() {
  const [account, setAccount] = useState<`0x${string}`>()
  const [balance, setBalance] = useState('0')
  const [recipient, setRecipient] = useState('')
  const [amount, setAmount] = useState('')
  const [hash, setHash] = useState<string>()
  const [receipt, setReceipt] = useState<any>()
  const [transferring, setTransferring] = useState(false)

  // 连接钱包
  const connect = async () => {
    const [addr] = await walletClient.requestAddresses()
    setAccount(addr)
  }

  // 读取余额
  const fetchBalance = async () => {
    if (!account) return
    const raw = await publicClient.readContract({
      address: USDC_CONTRACT_ADDRESS,
      abi: USDC_ABI,
      functionName: 'balanceOf',
      args: [account],
    })
    setBalance(formatUnits(raw, 6))
  }

  // 发起转账
  const handleTransfer = async (e: React.FormEvent) => {
    e.preventDefault()
    if (!account || !recipient || !amount) return
    try {
      setTransferring(true)
      const value = parseUnits(amount, 6)

      // 模拟交易
      const { request } = await publicClient.simulateContract({
        account,
        address: USDC_CONTRACT_ADDRESS,
        abi: USDC_ABI,
        functionName: 'transfer',
        args: [recipient as `0x${string}`, value],
      })

      const txHash = await walletClient.writeContract(request)
      setHash(txHash)

      const rcpt = await publicClient.waitForTransactionReceipt({ hash: txHash })
      setReceipt(rcpt)

      // 余额及时刷新
      await fetchBalance()
    } finally {
      setTransferring(false)
    }
  }

  // 每次账户变化后刷新余额
  useEffect(() => {
    fetchBalance()
  }, [account])

  return (
    <main style={{ fontFamily: 'Segoe UI', margin: 40 }}>
      <h1>USDC 转账演示</h1>

      {!account ? (
        <button onClick={connect}>Connect Wallet</button>
      ) : (
        <section>
          <p>账户:{account}</p>
          <p>余额:{balance} USDC</p>

          <form onSubmit={handleTransfer}>
            <div>
              <label>接收地址 </label>
              <input
                type="text"
                required
                placeholder="0x..."
                value={recipient}
                onChange={(e) => setRecipient(e.target.value)}
              />
            </div>

            <div style={{ marginTop: 10 }}>
              <label>金额 (USDC) </label>
              <input
                type="number"
                required
                min="0.01"
                step="0.01"
                value={amount}
                onChange={(e) => setAmount(e.target.value)}
              />
            </div>

            <button type="submit" disabled={transferring}>
              {transferring ? '处理中' : '立即转账'}
            </button>
          </form>

          {hash && <p>Tx Hash: {hash}</p>}
          {receipt && <p>Status: {receipt.status}</p>}
        </section>
      )}
    </main>
  )
}

👉 点此查看链上实时交易演示与日志追踪工具


5. 启动与验证

  1. 创建 index.html 并挂载 React 根节点:

    <!doctype html>
    <head>
      <meta charset="utf-8" />
      <title>USDC 区块链转账 Demo</title>
    </head>
    <body>
      <div id="root"></div>
      <script type="module" src="/src/main.tsx"></script>
    </body>
  2. 创建 src/main.tsx

    import ReactDOM from 'react-dom/client'
    import App from './App'
    ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
  3. 重新执行 npm run dev,浏览器控制台应打印状态日志即可开始调试。

踩坑记录与调试技巧


常见问题(FAQ)

Q5. 如何安全保存 USDC?
主网请使用硬件钱包或移动端多重签名方案。测试网可大胆尝试,但务必别把私钥塞进开源仓库。

Q6. React 能否拓展成多链支持?
通过配置 <RainbowKit><WagmiConfig>,耦合 10 余条 EVM 链只需数行变更。

Q7. 将来主网迁移要注意什么?


结语

至此,你已经完成了在 Sonic 区块链上使用 原生 USDC 构建前端转账 DApp 的全部流程:环境检查、合约交互、UI 封装、调试验证。把这段模板继续拓展,就能添加 Token Swap、NFT 展示或其它 DeFi 功能。祝编码愉快!