0

I've recently started to play around with solidity and have a question regarding my dapp. Basically, it's the betting site where people can guess the weather forecast (cloudy, sunny, etc) on a specific date. Ex: weather in seattle on March 10th, 2018. Let's say 5 people have bet (0.1 ether each) and one person guessed it right. The winner gets all the money from the rest of 4 people. Now, based on this scenario I assume each person has to send ether to contract address when he/she bets,

function setBettingInfo (string _forecast, string _date) payable returns (bool success) {    
    // ... codes

    address(this).transfer(msg.value); // send betting price to contract address
}

and the winners will be evenly distributed with ether from the contract address on March 11th, 2018 when the dapp calls a forecast api to find out what the weather was like on March 10th. Sending ethers winners, I'm trying to use

function transfer(string _forecast, string _date) returns (bool success) {
    // ... code to get the winners
    // Distribute ethers to winners
    for (uint i = 0; i < winners.length; i++) {
        if (contractBalance[address(this)] < value) throw;
        contractBalance[address(this)] -= value;
        winners.account.transfer(value);
    }    

    return true;
}

Just wondering if this is a correct approach.

  1. send betting price to contract address
  2. pull result from forecast api and access contract method to find out winners
  3. calculate and evenly distribute ethers from contract to those winner accounts

Help is appreciated!

1 Answer 1

4

You should avoid any loops of unknown length. For example if there is one person that wins then the function will cost (made up number) 5000 gas to execute. If 1000 people all win, then the function could suddenly cost 1 million gas to execute.

A better approach to this would probably be to implement a claimWinnings() function that each winner can call once the results are released. That way the contract will only ever need to make one transfer at a time. And in claimWinnings() it would remove that person from the list of winners so that they cannot claim it a second time.

This also has the added benefit (for you, the contract owner) that you would not be having to pay gas fees every time a competition ends.

5
  • Thanks. So based on your answer, I need to declare mapping(address => uint256) public balanceOf; and in claimWinnings() once the result is released from api, find the winner(s) who got the answer right and add the prize to the address ex: balanceOf[winner] += prize; and create a button in frontend to let the winner receive/withdraw his prize for this bet and mark hasReceivedPrize to true so the winner cannot claim it a second time?
    – bbusdriver
    Jan 29, 2018 at 20:38
  • and I am going to run claimWinnings() on background task every 12 hours to pull forecast api to check the result and assign prize to each winner. So they can see the result by putting their account addess on frontend to see the result via table format and withdraw it by clicking a button. Does this make sense to you?
    – bbusdriver
    Jan 29, 2018 at 20:47
  • I don't think you necessarily need to do most of that. For each competition create a new mapping for address -> guess. Once a competition ends you will need to run some sort of finaliseCompetition(results) function. When the user calls claimWinnings() it just needs to check that the mapped guess for msg.sender is equal to the competition results. In that function you can also have a mapping for address -> claimedWinnings
    – Nanolucas
    Jan 30, 2018 at 5:55
  • Okay, so I assume claimWinnings() is the function for each user to check whether they've won the competition and can withdraw prize from it. I guess that function can be initiated by clicking a button with its name Withdraw prize on UI? One last question before I accept it as an answer, if I run claimWinnings() on a background task for every 12 hours to check who the winners are for the competition and assign prize to each winner, would that cost gas for the contract owner?
    – bbusdriver
    Jan 30, 2018 at 7:55
  • Yes, if you want to cronify your finaliseCompetition() function to automatically distribute the prizes it would cost gas to whoever is calling that function (in this case it is expected to be the owner of the contract). Since you want to go through each winner it would need to be run in a loop or unknown length which could cost a wildly varying amount of gas. If the users are using claimWinnings() (which would be some sort of Withdraw Prize button, yes) then it is a fixed amount of gas every time and the player pays the gas.
    – Nanolucas
    Jan 30, 2018 at 8:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.