Home > Mobile >  Smart Contract could transfer ether to an address, but the balance of that address does not update
Smart Contract could transfer ether to an address, but the balance of that address does not update

Time:03-07

I am trying to get my smart contract to transfer all its balance to another address. The transfer line doesn't throw any errors but the balance of contract does not change afterwards.

I am using web3js with ganache to test this function:

My contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.12;

contract Lottery {
    address payable public manager;
    address payable[] public players;

    constructor() {
        manager = payable(msg.sender);
    }

    function enterLottery() public payable {
        require(msg.value >= .01 ether);
        players.push(payable(msg.sender));
    }

    function getPlayers() public view returns (address payable[] memory) {
        return players;
    }

    function random() public view returns (uint256) {
        return
            uint256(
                keccak256(
                    abi.encodePacked(block.difficulty, block.timestamp, players)
                )
            );
    }

    function pickWinner() public { // this transfer contract balance to the account
        uint256 index = random() % players.length;
        players[index].transfer(address(this).balance);
    }
}

My test case:

beforeEach(async () => {
    accounts = await web3.eth.getAccounts();
    contract = await new web3.eth.Contract(abi)
        .deploy({ data: evm.bytecode.object })
        .send({ from: accounts[0], gas: "1000000" })
})

describe("Lottery", () => {
    it("Contract has an address? ", () => {
        assert.ok(contract.options.address)
    })

    it("Prize pool can receive ether", async () => { 
        await contract.methods.enterLottery().send({ from: accounts[1], gas: "1000000", value: "10000000000000000" });
        const contractBalance = await web3.eth.getBalance(contract.options.address)

        const hasContractReceivedEntry = contractBalance === "10000000000000000";
        assert.equal(hasContractReceivedEntry, true)
    })

    it("Winner can receive the prize pool", async () => {
        await contract.methods.enterLottery().send({ from: accounts[1], gas: "1000000", value: "10000000000000000" });
        await contract.methods.pickWinner().call();

        const contractBalance = await web3.eth.getBalance(contract.options.address)

        console.log(contractBalance) // the contract balance should be 0 after the pickWinner call, but it is still 10000000000000000 wei the enterLottery function gave
    })
})

Edit: It is confirmed that the smart contract can run enterLottery and random() as intended

CodePudding user response:

await contract.methods.pickWinner().call();

On this line, you're invoking a read-only call that doesn't update the contract state. You need to send a transaction using the .send() function - just like on the previous line.

  • Related