Solidity

遍歷應付地址列表會引發“您發送的值應小於目前餘額”的錯誤

  • May 19, 2022

已經堅持了幾天,尋求幫助。

我寫了一個契約,允許使用者在某個事件上下注,然後一旦評估了事件的結果,它應該根據事件的結果(贏/輸)改變他們的賭注。負責迭代使用者列表以檢查所選團隊的名稱並在選擇獲勝團隊時轉移資金的功能失敗。

定義契約和附加賭注:

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;
   }

此函式計算兩支球隊的總投注池:

   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);
   }

這 2 個函式計算每個使用者的潛在獲勝機率,並將它們添加到使用者結構中:

   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
           );
       }
   }

這是出現問題的地方 - 當我執行 sendWinnings 函式時,Remix 拋出此錯誤“注意:如果您發送值並且您發送的值應該小於您目前的餘額,則呼叫的函式應該是應付的。調試交易以獲取更多資訊。” 請注意, transferAmount 工作得很好:

   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);
           }
       }
   }
}

重現問題的步驟 -> (1) 為團隊選擇 2 個名稱(我選擇“sab”和“kek”)(2) appendUserBet() 從帶有團隊名稱的幾個地址中 (3) userLoop1(), userLoop2( ) (4) sendWinnings() 並在第 4 步中合約中斷。

我嘗試添加 /100*99 位以確保合約在發送獎金後始終有剩餘餘額,但它沒有幫助。我會非常感謝能抽出時間引導我走向正確方向的人。

如果使用者不是贏家,程式碼仍然會進入 else 塊並嘗試向他發送金額嗎?事實上 if 和 else 塊有完全相同的語句……那我們為什麼需要 if-else。

引用自:https://ethereum.stackexchange.com/questions/128503