Hi Guest

More contents, please log on!

Bitmere.com 区块链技术 Content

足球竞猜智能合约源代码

仙翁童子子os
35 0 0
业务需求
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始




  1. // SPDX-License-Identifier: GPL-3.0

  2. pragma solidity >=0.7.0 <0.9.0;

  3. import "hardhat/console.sol";

  4. contract WorldCup {
  5.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队
  6.     // 2. 核心方法:下注、开奖、兑现
  7.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队

  8.     // 管理员
  9.     address public admin;
  10.     // 第几期
  11.     uint8 public currRound;

  12.     // 参赛球队
  13.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
  14.     // 期数 => 玩家
  15.     mapping(uint8 => mapping(address => Player)) players;
  16.     // 期数 => 投注各球队的玩家
  17.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
  18.     // 玩家对应赢取的奖金
  19.     mapping(address => uint256) public winnerVaults;

  20.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变
  21.     uint256 public immutable deadline;
  22.     // 所有玩家待兑现的奖金
  23.     uint256 public lockedAmts;

  24.     enum Country {
  25.         GERMANY,
  26.         FRANCH,
  27.         CHINA,
  28.         BRAZIL,
  29.         KOREA
  30.     }

  31.     event Play(uint8 _currRound, address _player, Country _country);
  32.     event Finialize(uint8 _currRound, uint256 _country);
  33.     event ClaimReward(address _claimer, uint256 _amt);

  34.     // 验证管理员身份
  35.     modifier onlyAdmin {
  36.         require(msg.sender == admin, "not authorized!");
  37.         _;
  38.     }

  39.     // 玩家投注信息
  40.     struct Player {
  41.         // 是否开奖
  42.         bool isSet;
  43.         // 投注的球队份额
  44.         mapping(Country => uint256) counts;
  45.     }

  46.     constructor(uint256 _deadline) {
  47.         admin = msg.sender;
  48.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");
  49.         deadline = _deadline;
  50.     }

  51.     // 下注过程
  52.     function play(Country _selected) payable external {
  53.         // 参数校验
  54.         require(msg.value == 1 gwei, "invalid funds provided!");

  55.         require(block.timestamp < deadline, "it's all over!");

  56.         // 更新 countryToPlayers
  57.         countryToPlayers[currRound][_selected].push(msg.sender);
  58.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
  59.         Player storage player = players[currRound][msg.sender];
  60.         // player.isSet = false;
  61.         player.counts[_selected] += 1;

  62.         emit Play(currRound, msg.sender, _selected);
  63.     }

  64.     // 开奖过程
  65.     function finialize(Country _country) onlyAdmin external {
  66.         // 找到 winners
  67.         address[] memory winners = countryToPlayers[currRound][_country];
  68.         // 分发给所有压中玩家的实际奖金
  69.         uint256 distributeAmt;

  70.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
  71.         uint currAvalBalance = getVaultBalance() - lockedAmts;
  72.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);

  73.         for (uint i = 0; i < winners.length; i++) {
  74.             address currWinner = winners[i];

  75.             // 获取每个地址应该得到的份额
  76.             Player storage winner = players[currRound][currWinner];
  77.             if (winner.isSet) {
  78.                 console.log("this winner has been set already, will be skipped!");
  79.                 continue;
  80.             }

  81.             winner.isSet = true;
  82.             // 玩家购买的份额
  83.             uint currCounts = winner.counts[_country];

  84.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
  85.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;
  86.             // 玩家对应赢取的奖金
  87.             winnerVaults[currWinner] += amt;
  88.             distributeAmt += amt;
  89.             // 放入待兑现的奖金池
  90.             lockedAmts += amt;

  91.             console.log("winner:", currWinner, "currCounts:", currCounts);
  92.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
  93.         }

  94.         // 未分完的奖励即为平台收益
  95.         uint giftAmt = currAvalBalance - distributeAmt;
  96.         if (giftAmt > 0) {
  97.             winnerVaults[admin] += giftAmt;
  98.         }

  99.         emit Finialize(currRound++, uint256(_country));
  100.     }

  101.     // 奖金兑现
  102.     function claimReward() external {
  103.         uint256 rewards = winnerVaults[msg.sender];
  104.         require(rewards > 0, "nothing to claim!");

  105.         // 玩家领取完奖金置为 0
  106.         winnerVaults[msg.sender] = 0;
  107.         // 从待兑现奖金池中移除该玩家份额
  108.         lockedAmts -= rewards;
  109.         (bool succeed,) = msg.sender.call{value: rewards}("");
  110.         require(succeed, "claim reward failed!");

  111.         console.log("rewards:", rewards);

  112.         emit ClaimReward(msg.sender, rewards);
  113.     }

  114.     // 获取奖池金额
  115.     function getVaultBalance() public view returns(uint256 bal) {
  116.         bal = address(this).balance;
  117.     }

  118.     // 获取当期下注当前球队的人数
  119.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
  120.         return countryToPlayers[_round][_country].length;
  121.     }

  122.     // 获取当前玩家当期押注份额
  123.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {
  124.         return players[_round][_player].counts[_country];
  125.     }
  126. }
Copy the Code





You have to log in before you can reply Login | 立即注册

Points Rules

Write the first review

仙翁童子子os 小学生
  • Follow

    0

  • Following

    0

  • Articles

    4

币圈江左盟
Promoted