You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sepolia测试网ETH转账报错:TypeError及MetaMask未唤起求助

问题排查:Sepolia测试网ETH转账失败及MetaMask未唤起问题

错误原因分析

  1. Ethers.js API版本不匹配:报错TypeError: (intermediate value).providers is undefined,说明代码中Ethers.js 5.x API写法存在问题,或实际安装版本与声明的5.7.2不符(比如误装6.x,该版本已移除ethers.providers命名空间)。
  2. Window.ethereum获取时机错误:全局提前赋值const { ethereum } = window;,但MetaMask是异步注入window.ethereum对象的,页面加载初期该对象可能尚未存在,导致后续函数调用时ethereum为undefined,触发No ethereum object错误。
  3. 交易逻辑冗余:sendTransaction中同时调用eth_sendTransaction直接转账和合约addToBlockchain方法,逻辑冲突且错误处理不完整,提前终止代码执行导致MetaMask未被唤起。

解决方案

1. 确认并修复Ethers.js版本

  • 检查package.json中的ethers版本,确保为5.7.2:
    "dependencies": {
      "ethers": "^5.7.2"
    }
    
  • 若版本不符,重新安装指定版本:
    npm uninstall ethers
    npm install ethers@5.7.2
    
  • 若仍出现providers未定义错误,修改导入方式:
    import * as ethers from "ethers"; // 替代原import { ethers } from "ethers";
    

2. 修正Window.ethereum获取逻辑

移除全局的window.ethereum赋值,在需要的函数内部动态获取并增加存在性检查:

  • 删除全局代码const { ethereum } = window;
  • 在所有依赖ethereum的函数中,直接使用window.ethereum并做存在性校验。

3. 优化交易逻辑与错误处理

  • 移除sendTransaction中冗余的eth_sendTransaction调用(若合约addToBlockchain方法已包含转账逻辑),统一通过合约处理交易;
  • 移除不必要的页面刷新,改用重新获取交易列表的方式更新状态;
  • 完善表单校验与错误提示,避免因参数缺失导致交易失败。

修改后的TransactionContext.jsx代码示例

import React, { useEffect, useState } from "react";
import * as ethers from "ethers";

import { contractABI, contractAddress } from "../utils/constants";

export const TransactionContext = React.createContext();

const createEthereumContract = () => {
  const ethereum = window.ethereum;
  if (!ethereum) throw new Error("请安装MetaMask钱包");
  
  const provider = new ethers.providers.Web3Provider(ethereum);
  const signer = provider.getSigner();
  const transactionsContract = new ethers.Contract(contractAddress, contractABI, signer);

  return transactionsContract;
};

export const TransactionsProvider = ({ children }) => {
  const [formData, setformData] = useState({ addressTo: "", amount: "", keyword: "", message: "" });
  const [currentAccount, setCurrentAccount] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [transactionCount, setTransactionCount] = useState(() => {
    const storedCount = localStorage.getItem("transactionCount");
    return storedCount ? parseInt(storedCount) : 0;
  });
  const [transactions, setTransactions] = useState([]);

  const handleChange = (e, name) => {
    setformData((prevState) => ({ ...prevState, [name]: e.target.value }));
  };

  const getAllTransactions = async () => {
    try {
      const ethereum = window.ethereum;
      if (!ethereum) {
        console.log("未检测到Ethereum环境");
        return;
      }
      const transactionsContract = createEthereumContract();
      const availableTransactions = await transactionsContract.getAllTransactions();

      const structuredTransactions = availableTransactions.map((transaction) => ({
        addressTo: transaction.receiver,
        addressFrom: transaction.sender,
        timestamp: new Date(transaction.timestamp.toNumber() * 1000).toLocaleString(),
        message: transaction.message,
        keyword: transaction.keyword,
        amount: parseInt(transaction.amount._hex) / (10 ** 18)
      }));

      setTransactions(structuredTransactions);
    } catch (error) {
      console.log("获取交易列表失败:", error);
    }
  };

  const checkIfWalletIsConnect = async () => {
    try {
      const ethereum = window.ethereum;
      if (!ethereum) return alert("请安装MetaMask钱包");

      const accounts = await ethereum.request({ method: "eth_accounts" });

      if (accounts.length) {
        setCurrentAccount(accounts[0]);
        getAllTransactions();
      } else {
        console.log("未检测到已连接的钱包账户");
      }
    } catch (error) {
      console.log("检查钱包连接状态失败:", error);
    }
  };

  const checkIfTransactionsExists = async () => {
    try {
      const ethereum = window.ethereum;
      if (!ethereum) {
        console.log("未检测到Ethereum环境");
        return;
      }
      const transactionsContract = createEthereumContract();
      const currentTransactionCount = await transactionsContract.getTransactionCount();
      
      window.localStorage.setItem("transactionCount", currentTransactionCount.toString());
      setTransactionCount(currentTransactionCount.toNumber());
    } catch (error) {
      console.log("获取交易计数失败:", error);
    }
  };

  const connectWallet = async () => {
    try {
      const ethereum = window.ethereum;
      if (!ethereum) return alert("请安装MetaMask钱包");

      const accounts = await ethereum.request({ method: "eth_requestAccounts" });
      setCurrentAccount(accounts[0]);
      getAllTransactions();
    } catch (error) {
      console.log("连接钱包失败:", error);
    }
  };

  const sendTransaction = async () => {
    try {
      const ethereum = window.ethereum;
      if (!ethereum) return alert("请安装MetaMask钱包");

      const { addressTo, amount, keyword, message } = formData;
      if (!addressTo || !amount || !keyword || !message) {
        return alert("请填写所有表单字段");
      }

      const transactionsContract = createEthereumContract();
      const parsedAmount = ethers.utils.parseEther(amount);

      setIsLoading(true);
      // 调用合约方法,若合约需要接收ETH,需添加value参数
      const transactionHash = await transactionsContract.addToBlockchain(
        addressTo,
        parsedAmount,
        message,
        keyword,
        { value: parsedAmount }
      );

      console.log(`交易处理中 - ${transactionHash.hash}`);
      await transactionHash.wait();
      console.log(`交易成功 - ${transactionHash.hash}`);

      const transactionsCount = await transactionsContract.getTransactionCount();
      setTransactionCount(transactionsCount.toNumber());
      getAllTransactions();
      setformData({ addressTo: "", amount: "", keyword: "", message: "" });
    } catch (error) {
      console.log("交易失败:", error);
      alert(`交易失败: ${error.message}`);
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    checkIfWalletIsConnect();
    checkIfTransactionsExists();
  }, []);

  return (
    <TransactionContext.Provider
      value={{
        transactionCount,
        connectWallet,
        transactions,
        currentAccount,
        isLoading,
        sendTransaction,
        handleChange,
        formData,
      }}
    >
      {children}
    </TransactionContext.Provider>
  );
};

额外注意事项

  • 确保MetaMask已切换至Sepolia测试网,且账户中有足够的测试ETH;
  • 合约的addToBlockchain方法需正确实现转账逻辑(如使用payable修饰符,并处理ETH转账);
  • 若仍无法唤起MetaMask,检查浏览器是否允许MetaMask注入,或尝试重启浏览器及MetaMask扩展。

内容的提问来源于stack exchange,提问作者Mahan Tehrani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:52:01