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

Hardhat中connect()切换账户签名交易在Rinkeby测试网异常问题

多账户调用合约测试网部署异常排查

开发背景

  • 实现功能:开发支持多用户发送链上留言的智能合约,合约会将用户提交的留言内容message、区块时间戳block.timestamp、发送者地址三类数据,存储到链上的结构体数组中。
  • 脚本逻辑:部署脚本scripts/deploy.js通过调用getSigners()获取签名账户发起交易,核心代码为const [_, randomPerson,addr1, addr2] = await hre.ethers.getSigners(),其中返回数组第一个元素为默认部署账户(owner),代码中用下划线_指代。

相关代码

WavePortal.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0 <0.9.0;

import "hardhat/console.sol";

contract WavePortal {
    uint256 totalWaves;
    event NewWave(address indexed from, uint timestamp, string message);

    struct Wave{
        address waver;
        string message;
        uint timestamp;
    }

    Wave[] waves;

    constructor() {
        console.log("Yo yo, I am a contract and I am smart");
    }

    function wave(string memory _message) public {
        totalWaves += 1;
        console.log("%s waved with message %s", msg.sender, _message);
        waves.push(Wave(msg.sender, _message, block.timestamp));
        emit NewWave(msg.sender, block.timestamp, _message);
    }

    function getAllWaves() public view returns (Wave[] memory){
        return waves;
    }

    function getTotalWaves() public view returns (uint256) {
        console.log("We have %d total waves!", totalWaves);
        return totalWaves;
    }
}

scripts/deploy.js

const hre = require("hardhat");

const main = async () => {
  const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
  const waveContract = await waveContractFactory.deploy();
  await waveContract.deployed();
  console.log("Contract address:", waveContract.address);

  let waveCount;
  waveCount = await waveContract.getTotalWaves();
  console.log(waveCount.toNumber());

  let waveTxn = await waveContract.wave("A message!");
  await waveTxn.wait();

  const [_, randomPerson, addr1, addr2] = await hre.ethers.getSigners();
  console.log("Address of _  is: ",_.address);
  console.log("Random Person: ", randomPerson);
  console.log("Address of Random Person is: ", randomPerson.address);

  waveTxn = await waveContract.connect(randomPerson).wave("Another message!");
  await waveTxn.wait();

  let allWaves = await waveContract.getAllWaves();
  console.log(allWaves);
};

const runMain = async () => {
  try {
    await main();
    process.exit(0);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

runMain();

问题现象

  • 本地环境运行正常:执行npx hardhat node启动本地区块链节点后,另一终端执行npx hardhat run scripts/deploy.js --network localhost部署,所有功能运行正常,可正常获取_、randomPerson的地址,通过connect()切换账户调用合约方法无异常。
  • 测试网部署异常:通过Alchemy或Infura接入Rinkeby测试网,执行npx hardhat run scripts/deploy.js --network rinkeby部署时,仅默认owner账户_可正常使用,randomPerson、addr1、addr2等其余解构获取的账户均为undefined,执行console.log("randomPerson is: ", randomPerson)输出undefined,无法通过connect()方法切换上述账户调用合约方法,仅能使用owner账户发起交易,无法完成测试网部署。已确认hardhat.config.js中Rinkeby、Ropsten等网络的RPC、链ID配置正确,多次尝试未解决问题。

故障原因

本地启动hardhat node时,Hardhat会自动预生成10个预置了测试ETH的开发账户,全部注入signer列表,因此解构多个账户时可以正常拿到对应实例。
连接远程测试网时,Hardhat不会自动生成测试账户,只会读取hardhat.config.js中对应网络配置下accounts字段内配置的私钥,生成对应的signer实例。如果配置中只填入了1个部署账户的私钥,getSigners()返回的数组长度就为1,解构位置靠后的randomPerson、addr1、addr2自然会返回undefined。

修复方案

  • 提前准备3-4个独立的测试钱包,记录好私钥,先到Rinkeby测试网水龙头领取足够的测试ETH用于支付交易gas费。
  • 打开hardhat.config.js,找到Rinkeby网络的配置项,将所有测试账户的私钥按脚本中解构的顺序添加到accounts数组中,参考配置如下:
module.exports = {
  solidity: "0.8.0",
  networks: {
    rinkeby: {
      url: "你的Alchemy/Infura Rinkeby节点RPC地址",
      accounts: [
        "部署账户(对应代码中_)的私钥",
        "randomPerson对应测试账户的私钥",
        "addr1对应测试账户的私钥",
        "addr2对应测试账户的私钥"
      ]
    }
  }
};
  • 配置完成后重新执行部署脚本,即可正常获取多个signer实例,通过connect()切换账户发起交易。

安全提示:不要直接使用本地hardhat node默认生成的测试账户私钥连接公网测试网/主网,这类账户私钥是公开的,存入的资产会被立即盗取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:01:04