0

Stuck with this for a few days already, looking for some help.

I write a contract that allows users to bet on a certain event and then once the result of the event is evaluated it should change their bet according to the results of the event (win/lose). Function that is in charge of iterating over a list of users to check the name of the chosen team and transfer the funds if the winner team is chosen, fails.

Defining contract and appending bets:

pragma solidity ^0.8.0;

contract Betting {
    uint256 public fee = 1000000000000000000 wei;

    address public owner;

    struct UserStruct {
        uint256 betAmount;
        uint256 potentialWinnings;
        string teamChosen;
    }

    mapping(address => UserStruct) public userStructs;
    address[] public userList;

    event LogUserBet(
        address user,
        uint256 userBetAmount,
        string userTeamChosen,
        uint256 userPotentialWinnings
    );

    function appendUserBet(string memory userTeamChosen) public payable {
        uint256 minimumFee = 1 * 10**17 wei;
        userList.push(payable(msg.sender));
        require(msg.value >= minimumFee);
        fee = msg.value;
        userStructs[msg.sender].betAmount += msg.value;
        userStructs[msg.sender].teamChosen = userTeamChosen;
    }

This function calculates total bet pools for both teams:

    function userLoop1()
        public
        returns (
            uint256 homePool,
            uint256 awayPool,
            uint256 totalPool
        )
    {
        for (uint256 i = 0; i < userList.length; i++) {
            emit LogUserBet(
                userList[i],
                userStructs[userList[i]].betAmount,
                userStructs[userList[i]].teamChosen,
                userStructs[userList[i]].potentialWinnings
            );
            string memory team = userStructs[userList[i]].teamChosen;
            if (
                keccak256(abi.encodePacked(team)) ==
                keccak256(abi.encodePacked("sab"))
            ) {
                homePool = homePool + userStructs[userList[i]].betAmount;
            } else {
                awayPool = awayPool + userStructs[userList[i]].betAmount;
            }
        }
        totalPool = homePool + awayPool;
        return (homePool, awayPool, totalPool);
    }

These 2 functions calculate the potential winning of each user and add them to the user Struct:

    function divider(
        uint256 numerator,
        uint256 denominator,
        uint256 precision
    ) public pure returns (uint256) {
        return
            ((numerator * (uint256(10)**uint256(precision + 1))) /
                denominator +
                5) / uint256(10);
    }

    function userLoop2() public {
        uint256 homePool;
        uint256 awayPool;
        uint256 totalPool;
        uint256 homePoolShare;
        uint256 awayPoolShare;
        uint256 userShare;
        (homePool, awayPool, totalPool) = userLoop1();
        homePoolShare = divider(homePool, totalPool, 5);
        awayPoolShare = divider(awayPool, totalPool, 5);
        for (uint256 i = 0; i < userList.length; i++) {
            string memory team = userStructs[userList[i]].teamChosen;
            uint256 bet;
            bet = userStructs[userList[i]].betAmount;
            if (
                keccak256(abi.encodePacked(team)) ==
                keccak256(abi.encodePacked(userStructs[userList[i]].teamChosen))
            ) {
                userShare = divider(bet, homePool, 5);
                userStructs[userList[i]].potentialWinnings =
                    (totalPool * userShare) /
                    100000;
            } else {
                userShare = divider(bet, awayPool, 5);
                userStructs[userList[i]].potentialWinnings =
                    (totalPool * userShare) /
                    100000;
            }
            emit LogUserBet(
                userList[i],
                userStructs[userList[i]].betAmount,
                userStructs[userList[i]].teamChosen,
                userStructs[userList[i]].potentialWinnings
            );
        }
    }

And here is the bit where the problem arises - when I run sendWinnings function, Remix throws this error "Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information." Please note that transferAmount works just fine:

    function transferAmount(address payable _recipient, uint256 _amount)
        public
        payable
    {
        _recipient.transfer(_amount);
    }

    function sendWinnings(string memory winnerTeam) public payable {
        uint256 winnings;
        address payable user;
        for (uint256 i = 0; i < userList.length; i++) {
            if (
                keccak256(abi.encodePacked(winnerTeam)) ==
                keccak256(abi.encodePacked("sab")) &&
                keccak256(abi.encodePacked(winnerTeam)) ==
                keccak256(abi.encodePacked(userStructs[userList[i]].teamChosen))
            ) {
                winnings =
                    (userStructs[userList[i]].potentialWinnings / 100) *
                    99;
                user = payable(userList[i]);
                transferAmount(user, winnings);
            } else {
                winnings =
                    (userStructs[userList[i]].potentialWinnings / 100) *
                    99;
                user = payable(userList[i]);
                transferAmount(user, winnings);
            }
        }
    }
}

Steps to reproduce the problem -> (1) choose 2 names for the teams (i choose "sab" and "kek") (2) appendUserBet() from a few addresses with the team name (3) userLoop1(), userLoop2() (4) sendWinnings() and on step 4 the contract breaks.

I tried adding the /100*99 bit to make sure that contract always has leftover balance after sending the winnings but it didnt help. I would be very thankful to the person who finds the time to guide me in the right direction.

1 Answer 1

0

If user is not a winner, stil the code is going in else block and trying to send him amount ? Infact the if and else blocks have exactly same statements...then why do we need the if-else.

1
  • Thank you very much! My overworked mind just forgot that i copypasted the if/else statement unchanged from another contract. Deleting the else statement completely did the trick. May 19, 2022 at 13:46

Your Answer

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

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