Cadogan
Cadogan

Reputation: 33

How to call Solidity Function to return Ether from Smart Contract?

I have deployed a smart contract on a local truffle project and I am trying to interact with it in a React project using web3. The following solidity function should send Ether what was previously deposited in the contract to a user address on a boolean condition:

     function Payout() public{

            require( voteEndTime< block.timestamp, "Voting Time is not up. Please come back later" );
            Voter storage sender = voters[msg.sender];

                if (negativeVotes > positiveVotes){
                    require(!sender.option, "Wrong Vote. Stake is distributed among winners");
                    payable(address(msg.sender)).transfer((stakes*sender.amount) / negativeStakes);
                    }

                else if (positiveVotes > negativeVotes){
                    require(sender.option, "Wrong Vote. Stake is distributed among winners");
                    payable(address(msg.sender)).transfer((stakes*sender.amount) / positiveStakes);
                }

                else{
                    payable(address(msg.sender)).transfer((stakes*sender.amount) / stakes);
                }
            }

The contract is definitely able to read the user's address using msg.sender because it has worked in the other functions I have. Every other function in the contract is also working fine. I can interact with it and I am able to send Ether to it. The problem occurs when I am trying to return the Ether stored in the contract to an account. I am trying to call my Payout() function using the following web3 call in React on button click:

    var response = await BallotContract.methods.Payout().send({ from: account, gas: 310000 })

I have specified a higher gas limit, because the contract runs out of gas if I try to use the gas estimation seen below. The function this call is present in looks like this:

     const giveMeMoney = async (e) => {
        const web3 = await new Web3(window.ethereum);
        await window.ethereum.enable();
        
        var Accounts = await web3.eth.getAccounts() 
            account = Accounts[0]
            console.log(account)
    
          const gas = await BallotContract.methods.Payout().estimateGas();
          console.log(gas)
          
          var response = await BallotContract.methods.Payout().send({ from: account, gas: 310000 })

    
      }

I am able to access the function from the frontend and it is returning the correct string if a "require" condition is not met. My problem is that the contract does not return any Ether if the conditions are met and this line:

    payable(address(msg.sender)).transfer((stakes*sender.amount) / positiveStakes);

...is accessed. I am getting the following error:

    Uncaught (in promise) Error: Returned error: VM Exception while processing transaction: revert
        at Object.ErrorResponse (errors.js:30)
        at onJsonrpcResult (index.js:162)
        at XMLHttpRequest.request.onreadystatechange (index.js:123)
    ErrorResponse   @   errors.js:30

Now I am unsure what could be the problem, because the contract is running perfectly fine if I test it in Remix. Does anybody see the problem or have a workaround for this kind of problem?

Upvotes: 3

Views: 1174

Answers (1)

jhonny
jhonny

Reputation: 858

The "out of gas" error is caused by the transfer function. This function has a gas limit of 2100; I recommend you use call, you can check how here.

Also the boolean value of the Voter struct defaults to false. So if the negative votes win, but the user didn't vote, they still can try to claim the reward, even if the amount is 0. I recommend you check how to use an enum, it can be very useful.

Upvotes: 0

Related Questions