MetaMask 交易全流程指南:Wagmi 与原生 JavaScript 双方案

·

想在 DApp 里优雅地处理以太坊交易?无论是 Wagmi 的 React Hook 魔力,还是原生 JavaScript 的灵活组合,本文围绕 MetaMask 交易Wagmi发送交易Gas估算交易状态追踪 等核心关键词,提供可落地的完整范式与防坑须知。

什么场景需要 MetaMask 交易 SDK

开发者常遇到这些槽点:
用户点击按钮却迟迟看不到结果,Gas 报溢,交易被链上回滚。借助 MetaMask SDK,你可以:

👉 点此查看一键调起钱包、自动检测链 ID 的完整封装方案


Wagmi:三步写出发送交易的 React 组件

Wagmi 提供了功能完备的 React Hook,开箱即用。下面给出两种典型场景:标准转账与带 Gas 估算的合约交互。

1. 基础转账:0.1 ETH 极速到账

import { parseEther } from 'viem'
import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi'

export default function SendTransaction() {
  const { data: hash, error, isPending, sendTransaction } = useSendTransaction()
  const { isLoading: isConfirming, isSuccess: isConfirmed } =
    useWaitForTransactionReceipt({ hash })

  const handleSend = async () => {
    sendTransaction({ to: '0xRecipientAddress', value: parseEther('0.1') })
  }

  return (
    <>
      <button disabled={isPending} onClick={handleSend}>
        {isPending ? '等待签名中…' : '发送 0.1 ETH'}
      </button>

      {hash && (
        <p>
          交易哈希:{hash.slice(0, 10)}…
          {isConfirming && '⏳ 等待确认…'}
          {isConfirmed && '✅ 交易确认成功!'}
        </p>
      )}

      {error && <p style={{ color: 'red' }}>错误:{error.shortMessage}</p>}
    </>
  )
}

2. 进阶用法:动态 Gas 估算 + 合约交互

import {
  useSendTransaction,
  useWaitForTransactionReceipt,
  useEstimateGas,
} from 'wagmi'

export default function AdvancedTransaction() {
  const tx = { to: '0xDaiContract', data: '0x1234', value: 0n }

  // 1. 预先估算 Gas,无需死记硬背
  const { data: gasEstimate } = useEstimateGas(tx)

  // 2. 发送时带上估算值
  const { sendTransaction } = useSendTransaction({
    ...tx,
    gas: gasEstimate,
    onSuccess: (hash) => console.log('交易已广播', hash),
  })

  return (
    <button onClick={() => sendTransaction()}>
      使用 Gas 估算发交易
    </button>
  )
}

要点:


原生 JavaScript:无框架的扫码即用方案

如果你开发的是纯 HTML 页面或小程序,排斥 React,也可以直接用浏览器注入的 ethereum Provider 处理交易。

1. 标准转账 RPC 组合

async function sendTransaction(recipient, amount) {
  try {
    const accounts = await ethereum.request({ method: 'eth_requestAccounts' })
    const from = accounts[0]

    // 金额转 wei
    const value = `0x${(amount * 1e18).toString(16)}`

    const tx = { from, to: recipient, value }
    const txHash = await ethereum.request({
      method: 'eth_sendTransaction',
      params: [tx],
    })
    return txHash
  } catch (err) {
    if (err.code === 4001) throw new Error('用户已拒绝交易')
    throw err
  }
}

2. 轮询交易回执

function watchTransaction(txHash) {
  return new Promise((resolve, reject) => {
    const check = async () => {
      const receipt = await ethereum.request({
        method: 'eth_getTransactionReceipt',
        params: [txHash],
      })

      if (receipt) {
        receipt.status === '0x1' ? resolve(receipt) : reject('交易失败')
      } else {
        setTimeout(check, 2000)
      }
    }
    check()
  })
}

3. 动态 Gas 估算

async function estimateGas(txParams) {
  const gasHex = await ethereum.request({
    method: 'eth_estimateGas',
    params: [txParams],
  })
  const safeGas = BigInt(gasHex) * 120n / 100n // 20% 缓冲
  return safeGas.toString(16)
}

执行流程:用户点击按钮 → JS 弹 MetaMask → 监听器每隔 2 秒轮询 receipt → 页面更新提示“交易确认成功”。

👉 10 分钟上手可复用的 Vanilla JS 模板仓库


最佳实践:稳稳避免翻车

关注点推荐方案
交易安全所有地址做正则校验,到账前二次弹窗让用户确认金额、地址。
错误码处理4001 用户拒绝、-32603 余额不足,需要给出具体下一步,比如换网络或充值。
Gas估算策略在估算值上加 20% 缓冲,夜间高峰时可考虑 30%。
并发限制同一时间只能有一笔 pending,设置全局锁防止重复发送。

FAQ:5 个碉堡级高频疑问

Q1:为什么 MetaMask 估算的 Gas 与实际不符?
A:合约内部逻辑可能会随着合约状态变化而变化,建议保守地加 10~20% 的 buffer。若链上拥堵,可再提升 gasPrice 而非单纯提高 gasLimit。

Q2:交易pending 卡住怎么办?
A:在状态监听里,若超过 5 分钟仍未确认,提示用户手动 SPEED UP(MetaMask 内置加速器),或调用 eth_getTransactionByHash 读取 gasPrice 做比较。

Q3:Wagmi 能在服务端渲染(SSR)里用吗?
A:Wagmi 依赖客户端钱包方法,建议在浏览器端执行;Next.js 场景可使用 dynamic(() => import(..), { ssr: false }) 做懒加载。

Q4:弹窗中如何展示“等待区块确认”动画?
A:利用 isConfirming 布尔值,结合 CSS 加载条形成“从0到6个确认”的渐进式提示,可同步展示当前 blockNumber 与目标差异。

Q5:用 vanilla JS 可以做批量交易吗?
A:可以。反复调用 eth_sendTransaction 并在前端做状态映射即可,但需仔细控制 nonce 顺序;若使用 EIP 1559,可构造 maxPriorityFeePerGasmaxFeePerGas 双字段。


下一步:追加功能升级路线

看完这篇,你已经在 MetaMask 交易Wagmi发送交易Gas估算交易状态追踪 四大维度迈入高手行列。祝你在主网上线 DApp 十次无事故!