[Ethereum] change transaction msg.value and msg.sender on hardhat test

etherhardhatsoliditytest

I have a lottery kind of app for which users send money to a contract that at the time pays rewards. Simplified, the method I'm trying to test is something like this:

struct Bet {
    address payable user;
    bytes32 gameId;
    uint amount;
    uint num;
}

function placeBet(bytes32 _gameId, uint _num) public payable {
    ...
    // add the new bet
    Bet[] storage bets = gameBets[_gameId];
    bets.push(Bet(msg.sender, _gameId, msg.value, _num));

    // add the mapping
    bytes32[] storage userBets = userToBets[msg.sender];
    userBets.push(_gameId);
    ...
}

In order to test this properly I need to manually set the sender and value of the transaction I'm triggering, in this case placeBet().

I tried adding a hash with from and value keys after the method's params (like { from: addr, value: 5 }), which I understand works for truffle:

    before(async function () {
        LoteryApp = await ethers.getContractFactory("LoteryApp");
        [owner, addr1, addr2] = await ethers.getSigners();

        contract = await LoteryApp.deploy();
    });

    describe("it takes bets", function() {
        it("and assigns them properly", async function() {
            // user places Bet on 2
            await contract.placeBet(game.id, 2, { from: addr1, value: 5000 });

            // user places Bet on 1
            await contract.placeBet(game.id, 2, { from: addr2, value: 3000 });
            ...
        })
    })

And I also tried with connect method, taken from hardhat docs:

describe("it takes bets", function() {
    it("and assigns them properly", async function() {
        // user places Bet on 2
        await contract.connect(addr1).placeBet(game.id, 2);

        // admin places Bet on 1
        await contract.connect(addr2).placeBet(game.id, 1);
        ...
    });
})

But non of these options worked. Transactions always seem to be sent from the same address with a value of 0.

I'm using solidity 0.7.3, hardhat 2.3.3, ethers 5.4

Best Answer

It seems like the value you entered is a bit too small. I think this is why the transaction value is 0.

await contract.placeBet(game.id, 2, { value: ethers.utils.parseEther("0.5") }); // msg.value = 0.5 eth

To call the function from another account try:

await contract.connect(addr1).placeBet(game.id, 2, { value: ethers.utils.parseEther("0.5") }); 
Related Topic