Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
344 0 0
业务需求
- I  s4 L4 f4 p5 ^5 v
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始: V  u% ?- K& {. H1 v
% {, ]' u! a% `( }$ T, q/ i6 F2 o
) g; [! W% {* E1 I1 y- U0 x/ N+ [! L
9 z! R. M" ^' b5 l% v9 ~

  1. ' P3 m! B; X1 k) u5 h
  2. // SPDX-License-Identifier: GPL-3.04 z. E/ W$ P  e2 I6 q( }3 T
  3. 9 A& J& c% D4 h) I8 s$ k
  4. pragma solidity >=0.7.0 <0.9.0;% n# Z! `, F( P1 W  ~9 E0 F* Y4 F& o' e

  5. # ?" _0 H, X; \2 g5 X# W$ k* r4 x. G
  6. import "hardhat/console.sol";, c" _, z% j& p6 V4 ~1 r5 y: [

  7. ! v6 k: P, p  i5 G3 A7 b
  8. contract WorldCup {
    , S' r3 O2 N$ b; \, M5 \) ?
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队' l5 T" j$ l0 `# |; n: u6 y
  10.     // 2. 核心方法:下注、开奖、兑现
    ( x" l4 d/ m5 W
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    % W% b# _$ O- T7 N5 O" }0 _

  12. 7 N1 _3 j# x4 a' X$ Y
  13.     // 管理员. g" Z& q! E3 C! d' D, {- r
  14.     address public admin;
    * ?$ N" b: t. t0 a# J5 J* }
  15.     // 第几期/ a" Z1 f+ w8 s( D5 U2 ]7 W2 X1 O/ }
  16.     uint8 public currRound;: v+ q* V% e. {- I( w- S8 V
  17. ; V& H0 r. ^4 [% O! {
  18.     // 参赛球队
    & L( k5 @" R% ^0 h' s. @* \
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];. L! X6 m+ G7 j9 ?- d
  20.     // 期数 => 玩家9 p) b+ L, X* C7 E3 u% }
  21.     mapping(uint8 => mapping(address => Player)) players;0 J/ q' \, Y! @6 i" C# a$ a
  22.     // 期数 => 投注各球队的玩家- _; ~% G' T: M" j! k/ _
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
      p/ X$ f; _( f# L" Q7 B
  24.     // 玩家对应赢取的奖金
    ! Q; [% p8 S5 u3 M
  25.     mapping(address => uint256) public winnerVaults;
    2 K: n. v; ?& S0 G8 J
  26. 6 o3 {+ w' E0 {) e1 k
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变
    3 Q; W3 h1 L# J2 F% W# Z8 k
  28.     uint256 public immutable deadline;- u8 I. _8 o6 X2 d
  29.     // 所有玩家待兑现的奖金: e+ z# D/ C) x; v- K6 O  v9 T
  30.     uint256 public lockedAmts;! c( J' V# ~% U$ B2 k# B

  31. # v! L* T% ^( {, F% Y* Q1 M
  32.     enum Country {
    % z2 j5 ^1 ?8 U8 O0 @' [
  33.         GERMANY,6 V) ~0 i+ m. Z! ^  N; f
  34.         FRANCH,5 T3 f8 x& {6 f7 s& _1 j+ X
  35.         CHINA,) |8 m$ z6 T' a" l. d& O
  36.         BRAZIL,6 n  Z$ o+ t# p- E" [2 ?
  37.         KOREA/ B+ {: ~/ o6 a% ]
  38.     }
    / L$ R+ L2 ]8 y( e0 O3 K/ R- \

  39. ' x9 d4 Z! M; C: |' G( V4 W; c
  40.     event Play(uint8 _currRound, address _player, Country _country);3 W; i: L3 D% M
  41.     event Finialize(uint8 _currRound, uint256 _country);
    , _* a  t3 `; ]! G0 d" S: E6 W% J" m
  42.     event ClaimReward(address _claimer, uint256 _amt);
    9 l1 ]- l& G5 Q, ~

  43. 8 m5 J5 q; ^, D6 o/ O
  44.     // 验证管理员身份
    6 j8 I, E3 [* W! S8 c  N. J( V* y- E
  45.     modifier onlyAdmin {) j; [" f% e! g. [- K% |
  46.         require(msg.sender == admin, "not authorized!");
    * T, e2 c+ w2 r3 E
  47.         _;/ m; I8 j2 v3 C+ Q
  48.     }
    " H% D( i5 I: W
  49. - h5 R5 ?/ X7 n/ a% @
  50.     // 玩家投注信息
    4 o& V* x7 z- V% e- ]* x# d  [
  51.     struct Player {! T+ T% o% E$ c/ F6 e4 j
  52.         // 是否开奖' b( I, Z! D4 V& Q1 N, x. d8 `1 Y7 x
  53.         bool isSet;6 h8 Y0 S7 H5 X% l9 Y/ l8 u0 _
  54.         // 投注的球队份额( ]% Y) c6 l/ Y* [. ]# A
  55.         mapping(Country => uint256) counts;+ i) e; C8 f0 Q  o' I- d
  56.     }, F; H9 V) X2 d

  57. " F4 t- X# \0 M' ?
  58.     constructor(uint256 _deadline) {! l6 ?" E) d# A5 Y) T
  59.         admin = msg.sender;0 J2 j- i" V$ Y4 {
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");
    2 ]5 H  t! {- y+ V
  61.         deadline = _deadline;
    , q* Y8 R0 Y7 x
  62.     }5 B7 v: q: }+ F# C6 L1 x

  63. 1 ]! i' H6 [( \! r& {, }
  64.     // 下注过程, Q& |9 p1 v9 j8 N
  65.     function play(Country _selected) payable external {* j* L9 y3 W+ J( k. X
  66.         // 参数校验
    7 `5 T1 v" [# R1 h  ]
  67.         require(msg.value == 1 gwei, "invalid funds provided!");
    7 V- ^! U6 @2 v0 \! t
  68. $ W- A& O( ~& ]7 |9 y* k! H
  69.         require(block.timestamp < deadline, "it's all over!");( J7 L  s+ [- V0 B

  70. & \, u: s6 w) ^
  71.         // 更新 countryToPlayers8 X0 E7 w$ R, \! f7 d2 i1 a& u
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
    / u& Y/ H+ k7 t
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)2 `' g3 t6 G' N/ |  l
  74.         Player storage player = players[currRound][msg.sender];* G' \6 V# ]2 N" |6 L5 u
  75.         // player.isSet = false;
    # j1 I' I+ s- l8 q2 d
  76.         player.counts[_selected] += 1;! E: _. v8 a. ]) T8 D- `$ _
  77. 6 I  D, W/ M% U+ V8 [
  78.         emit Play(currRound, msg.sender, _selected);
    6 a/ C$ T; `- N, K5 Y# Z" m# r) }, c
  79.     }
    ) Q6 K) |" ^1 l0 u# r; D

  80. 4 L# F3 N) G9 b" T7 f
  81.     // 开奖过程
    . t. C+ U- Q5 Y
  82.     function finialize(Country _country) onlyAdmin external {0 ]3 A# W- _4 q6 z  E
  83.         // 找到 winners" G6 ]0 U1 e4 N9 M9 h% P
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    , z# k" `) W( ]9 ?; `8 u4 J
  85.         // 分发给所有压中玩家的实际奖金& T1 Y( [3 \3 o' Y, p
  86.         uint256 distributeAmt;* N4 V" S. \/ @& k; G& t2 [1 F9 e
  87. % \( M. P# Z  j2 `" S
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    2 ~$ q( f: ^2 J. `' ]0 y: U& K: Q
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;5 c( |7 `1 J" V0 [$ |! c
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    5 N- w: t9 A* ~: z  I9 I/ z  `1 Z6 g

  91. : q1 H3 j% j4 b
  92.         for (uint i = 0; i < winners.length; i++) {: N4 x" u' b1 C" V7 h
  93.             address currWinner = winners[i];
    0 O5 b  H# b# W: r; X

  94. 7 x2 h6 v  G( {1 G; d! Z! v
  95.             // 获取每个地址应该得到的份额3 [# q; }. f, P/ M1 }$ g
  96.             Player storage winner = players[currRound][currWinner];2 h3 j3 p! a3 o& h7 a& d
  97.             if (winner.isSet) {
    # q5 C8 c0 B, Q  b* n8 ?
  98.                 console.log("this winner has been set already, will be skipped!");
    8 v3 ^$ Z0 _! {! G, G
  99.                 continue;
    9 @) X/ y6 A( ^; I  _
  100.             }
    8 ^: s1 L4 G' S+ j

  101. 1 ?, M+ _1 q, L0 A2 T
  102.             winner.isSet = true;2 R$ j- U! e* P( F5 Y3 r' a& _/ E
  103.             // 玩家购买的份额
    # j) Z9 M/ R6 |6 |
  104.             uint currCounts = winner.counts[_country];! V+ l2 t( Q* U- U+ Q6 ^

  105. 0 I" F1 u+ i% B  U
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    1 o' ^% A! v' b  H; B8 F
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;! }) n: M$ r, Q
  108.             // 玩家对应赢取的奖金
    : F/ R; r5 p# N" g, L( p
  109.             winnerVaults[currWinner] += amt;: q" y( e2 i0 g" X( B5 u
  110.             distributeAmt += amt;
    8 v% u8 b& x6 R0 C
  111.             // 放入待兑现的奖金池
    9 K0 \/ ?# w. {7 m' ^* D0 I1 A
  112.             lockedAmts += amt;2 x0 K# J7 s4 ?! L

  113. 4 T" w" r- b" ~! V6 @7 S8 D; w4 T
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);, `, l: ?+ P* V! {
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    7 Z8 N2 q- d5 K! v% |4 V7 C
  116.         }- ~+ L( K' k- S+ m. y5 ]
  117. ! {& h' Q! R. m6 a+ Q
  118.         // 未分完的奖励即为平台收益; ^: b8 @" o& Y% Q6 E$ x, D4 i+ s
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    ! K! m* Q( }: ]+ I6 r5 @
  120.         if (giftAmt > 0) {' n) E  E# j) ]2 D6 Y  R; U
  121.             winnerVaults[admin] += giftAmt;
    5 z/ r+ R/ e8 n8 ?! i, |6 P& F% i
  122.         }7 W. b: M+ W2 E
  123. ( c7 \. `- _7 q) x0 j8 w$ s: y
  124.         emit Finialize(currRound++, uint256(_country));
    * W; ~# Q/ o9 o4 y) x# q$ ]
  125.     }
    * e# S. O. P% E$ T

  126. % S4 m( ~9 b$ v% u/ m, y" k
  127.     // 奖金兑现
    5 E- b3 }: M% `5 K3 d( g
  128.     function claimReward() external {" U! w, z/ k- b2 y2 K( L
  129.         uint256 rewards = winnerVaults[msg.sender];
    5 @/ m) p7 P) U$ }0 }
  130.         require(rewards > 0, "nothing to claim!");
    : g& [+ ^; T1 r" d

  131. ; L" j4 A0 m+ g7 X
  132.         // 玩家领取完奖金置为 0
    : B4 ~4 J' ], d  a5 k7 W
  133.         winnerVaults[msg.sender] = 0;" M( G- e3 \" D+ t; L
  134.         // 从待兑现奖金池中移除该玩家份额
    5 `& w& ?0 K9 ~0 u
  135.         lockedAmts -= rewards;0 D+ V& o& h- s) e  }) D4 o5 q
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    : i2 M7 {! y& A) Z
  137.         require(succeed, "claim reward failed!");/ e. J: s$ U" P( `& |
  138. 8 U. I$ E, s1 ]! K7 ]* r8 h
  139.         console.log("rewards:", rewards);, @) n' o) n6 ^6 E- m
  140. 2 Y. _3 Q0 h4 ~. z! |8 |' Y9 B
  141.         emit ClaimReward(msg.sender, rewards);
    0 t$ O) V% p# W$ r
  142.     }" b, E2 S# m% O5 `+ W

  143. 0 g% A+ T$ M$ S
  144.     // 获取奖池金额6 j1 R+ X/ @! A: D1 k0 Y
  145.     function getVaultBalance() public view returns(uint256 bal) {8 v$ W0 ?. D8 c8 i, ^$ @
  146.         bal = address(this).balance;
    & N% g8 y+ b0 C# H3 d! w
  147.     }5 v6 u) V8 Z: D6 T1 [
  148. 1 [0 K4 g1 j% n9 S/ m5 Z5 [
  149.     // 获取当期下注当前球队的人数+ _0 _+ w4 G0 |% F* w$ z; y
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {- E% s6 j! c9 l$ Q2 z/ {. E
  151.         return countryToPlayers[_round][_country].length;
      i8 p# K" I6 b6 S! o# w
  152.     }6 A" r" j2 n7 G- F+ W
  153. 4 g! Z: T" d0 N+ }8 z
  154.     // 获取当前玩家当期押注份额
    3 `! }' [, v& f  m1 z" j
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {
    * h; D7 l7 [6 e4 ?# d. i" o$ v' p
  156.         return players[_round][_player].counts[_country];5 e1 Z$ Y  ]1 T0 v/ d, J6 ?
  157.     }
    3 B( }* N3 }; L0 \
  158. }
复制代码

% T6 Z7 e8 K5 u/ _8 ^: s
$ V5 w  f0 g# D. ?: ?- q! j4 }( A- V' O2 D  @* @4 ^

7 M+ ^. x2 h- g
& W, `( Z* ?) |7 o* o" q& @: U
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

仙翁童子子os 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    4