多账户发起交易时出现from地址不匹配错误的排查求助
问题:Hardhat测试多账户进入Lottery合约失败
使用Hardhat和Mocha测试需要转入ETH的Lottery合约时,单账户进入的测试用例「Allows player to enter」可正常通过,但多账户进入的测试用例「Allow multiple players to enter」失败。
原测试代码
const hre = require("hardhat"); const {expect} = require ("chai"); let account, account2, account3; let lottery; beforeEach(async () => { [account, account2, account3] = await hre.ethers.getSigners(); const Lottery = await hre.ethers.getContractFactory("Lottery"); lottery = await Lottery.deploy(); await lottery.waitForDeployment(); }); describe("Lottery Contract", () => { it("Deploys a contract", () =>{ expect(lottery.target).to.be.ok; }); it("Allows player to enter", async() =>{ await lottery.enter({ from: account, value: hre.ethers.parseUnits("0.11","ether"), }); const players = await lottery.getPlayers({ from: account }); expect(account.address, players[0]).to.equal; expect(1, players.length).to.equal; }); it("Allow multiple players to enter", async() =>{ await lottery.enter({ from: account.address, value: hre.ethers.parseUnits("0.11","ether"), }); await lottery.enter({ from: account2.address, value: hre.ethers.parseUnits("0.11","ether"), }); await lottery.enter({ from: account3, value: hre.ethers.parseUnits("0.11","ether"), }); const players = await lottery.getPlayers({ from: account }); expect(account.address, players[0]).to.equal; expect(account2.address, players[1]).to.equal; expect(account3.address, players[2]).to.equal; expect(3, players.length).to.equal; }); });
合约enter函数
function enter() external payable minLimit{ players.push(msg.sender); }
错误信息
Lottery Contract √ Deploys a contract √ Allows player to enter 1) Allow multiple players to enter 2 passing (2s) 1 failing 1) Lottery Contract Allow multiple players to enter: TypeError: from address mismatch (argument="transaction", value={ "data": "0xe97dcb62", "from": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "to": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", "value": 110000000000000000 }, code=INVALID_ARGUMENT, version=6.13.1) at makeError (node_modules\ethers\src.ts\utils\errors.ts:687:21) at assert (node_modules\ethers\src.ts\utils\errors.ts:715:25) at assertArgument (node_modules\ethers\src.ts\utils\errors.ts:727:5) at C:\Users\Заур\Desktop\lottery\node_modules\@nomicfoundation\hardhat-ethers\src\signers.ts:214:25 at async Promise.all (index 0) at HardhatEthersSigner._sendUncheckedTransaction (node_modules\@nomicfoundation\hardhat-ethers\src\signers.ts:256:7) at HardhatEthersSigner.sendTransaction (node_modules\@nomicfoundation\hardhat-ethers\src\signers.ts:125:18) at send (node_modules\ethers\src.ts\contract\contract.ts:313:20) at Proxy.enter (node_modules\ethers\src.ts\contract\contract.ts:352:16) at Context.<anonymous> (test\Lottery.test.js:39:5)
问题原因
- Signer使用错误:在ethers.js v6和Hardhat环境中,不能直接在合约调用参数里用
from指定账户地址或signer对象,正确方式是用对应账户的signer连接合约后再调用方法。 - Chai断言顺序错误:
expect(实际值, 期望值).to.equal的参数顺序颠倒,正确语法为expect(实际值).to.equal(期望值)。
修正后的测试代码
const hre = require("hardhat"); const {expect} = require ("chai"); let account, account2, account3; let lottery; beforeEach(async () => { [account, account2, account3] = await hre.ethers.getSigners(); const Lottery = await hre.ethers.getContractFactory("Lottery"); lottery = await Lottery.deploy(); await lottery.waitForDeployment(); }); describe("Lottery Contract", () => { it("Deploys a contract", () =>{ expect(lottery.target).to.be.ok; }); it("Allows player to enter", async() =>{ // 用account连接合约后调用enter await lottery.connect(account).enter({ value: hre.ethers.parseUnits("0.11","ether"), }); const players = await lottery.getPlayers(); expect(players[0]).to.equal(account.address); expect(players.length).to.equal(1); }); it("Allow multiple players to enter", async() =>{ // 分别用不同账户连接合约调用enter await lottery.connect(account).enter({ value: hre.ethers.parseUnits("0.11","ether"), }); await lottery.connect(account2).enter({ value: hre.ethers.parseUnits("0.11","ether"), }); await lottery.connect(account3).enter({ value: hre.ethers.parseUnits("0.11","ether"), }); const players = await lottery.getPlayers(); expect(players[0]).to.equal(account.address); expect(players[1]).to.equal(account2.address); expect(players[2]).to.equal(account3.address); expect(players.length).to.equal(3); }); });
说明
- 使用
lottery.connect(signer)方法指定交易发起账户,替代原有的from参数,这是ethers.js v6和Hardhat推荐的调用方式。 - 修正Chai断言的参数顺序,确保实际值在前、期望值在后,符合断言语法规范。
- 只读方法
getPlayers无需指定from参数,因为不涉及交易发起者。
内容的提问来源于stack exchange,提问作者BurniEye
相关产品推荐
相关产品推荐

