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

调用智能合约时MetaMask未唤起报eth_sendTransaction不存在问题

问题背景

以太坊开发新手此前在Ganache环境下无需MetaMask即可正常调用合约函数,尝试通过Infura连接Rinkeby测试网开展合约预生产环境测试时,怀疑使用了旧版API但无法定位问题,检索技术资料未找到有效解决方案,运行时报错:

method eth_sendTransaction does not exist/is not available

涉及代码

Solidity合约代码

pragma solidity ^0.4.24;

contract Message {
    string myMessage;

    function setMessage(string x) public {
        myMessage = x;
    }

    function getMessage() public view returns (string) {
        return myMessage;
    } 
}

纯HTML前端交互代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Deploy a Remix Contract</title>

    <link rel="stylesheet" type="text/css" href="main.css">

    <script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>

</head>

<body>

    <div>
        <h1>Ethereum Secret Messenger</h1>
        <hr>

        <label for="message">This site writes a secret message to the Ethereum
            blockchain!</label>

        <input id="userInput" type="text">
        <button id="setMessageButton">Set secret message</button>

    </div>

    <script>
    
        // 连接web3 provider
        if (typeof web3 !== 'undefined') {
            web3 = new Web3(web3.currentProvider);
            console.log("Not defined");
        } else {
            web3 = new Web3(new Web3.providers.HttpProvider("https://rinkeby.infura.io/v3/.....My_Connection"));
            console.log("Defined")
        }
                
        web3.eth.defaultAccount = web3.eth.accounts[0];
        console.log("eth.account " + web3.eth.accounts[0]);

        var RemixContract = new web3.eth.Contract([
    {
        "constant": false,
        "inputs": [
            {
                "name": "x",
                "type": "string"
            }
        ],
        "name": "setMessage",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getMessage",
        "outputs": [
            {
                "name": "",
                "type": "string"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
],'0x.....');


    console.log(RemixContract);

    $("#setMessageButton").click(function () {
        let userMessage = $("#userInput").val()
    console.log("user message " + userMessage)
        RemixContract.methods.setMessage(userMessage)
.send({from:"0x....."})
.then(console.log);
});

    </script>
</body>

</html>

附加疑问

  • 已知使用Infura连接Rinkeby节点时,理论上无需MetaMask即可自行构造交易、用私钥签名后发送,这种场景下搭配使用MetaMask与Infura是否具备合理性?

问题解答

报错根因

这个报错和API版本没有关系,核心是节点能力的差异:
eth_sendTransaction这个RPC接口要求节点本身持有发送账户的私钥,才能帮用户完成交易签名再广播。你之前在Ganache本地环境能直接调用成功,是因为Ganache作为本地测试节点,默认托管了10个预置测试账户的私钥,收到请求会自动签名广播。
而Infura是公共远程节点,出于安全原则永远不会存储用户私钥,自然不支持eth_sendTransaction接口,仅支持接收已经完成签名的原始交易、做链上广播(对应eth_sendRawTransaction接口)。
你当前的代码还有两个隐性问题:

  • 直接通过Infura的HttpProvider连接时,web3.eth.accounts拿不到任何可用账户,你设置的web3.eth.defaultAccount = web3.eth.accounts[0]实际是undefined
  • 调用合约写方法时仅传入了from地址,没有做本地签名步骤,web3会默认发起eth_sendTransaction请求,直接触发报错。

修复方案

方案1:不依赖MetaMask,本地签名后通过Infura广播

这种方案需要你自行在代码中管理私钥,web3会在本地完成签名后,自动调用eth_sendRawTransaction把签名后的交易发给Infura广播。
注意:纯前端环境直接硬编码私钥有极高的资产被盗风险,仅适合本地测试使用,绝对不能上线到公开环境。
核心代码调整:

// 把测试账户私钥导入web3钱包(不要往这个测试地址存主网资产)
const testAccount = web3.eth.accounts.privateKeyToAccount('你的测试账户私钥');
web3.eth.accounts.wallet.add(testAccount);
web3.eth.defaultAccount = testAccount.address;

// 后续调用合约send方法时,web3会自动完成本地签名再广播
RemixContract.methods.setMessage(userMessage)
.send({from: testAccount.address})
.then(console.log);

方案2:MetaMask + Infura组合使用

这个组合是非常合理的生产级方案,二者没有任何冲突,分工非常明确:

  • MetaMask负责在用户本地浏览器侧安全存储私钥、完成交易签名,全程私钥不会发送给Infura或任何第三方,从根源避免私钥泄露风险
  • Infura负责提供稳定的链上接入能力,接收MetaMask签好名的交易做广播,同时支持查询链上数据、合约状态等只读请求
    这种方案下你不需要自己处理复杂的签名逻辑,只需要把代码里的provider逻辑调整为优先使用MetaMask注入的provider即可,不需要硬编码Infura的HttpProvider地址,MetaMask会默认匹配对应的节点服务,你也可以在MetaMask的网络配置中自定义Infura节点地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:54:26