Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
456 0 0
业务需求
7 I' U; h0 A1 s: `5 j! S) v0 |" ?
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    8 B4 d5 J" C  Q0 _. R; f+ G

7 r2 i9 p$ y, T) d$ ]
" t' K- X" H' K1 R+ a8 D! |& d- K- w8 ^/ ?8 S" E% l3 V8 j" O
  1. # c! [0 ^3 p5 q& g
  2. // SPDX-License-Identifier: GPL-3.0( D1 b( t  B1 h* P0 t# N
  3. " }! G% c. \; Z; \) d8 A8 ?
  4. pragma solidity >=0.7.0 <0.9.0;
    $ C8 Q6 N& m) m6 a

  5. , h' w+ s  B& D( g+ u
  6. import "hardhat/console.sol";- ]+ ^6 q) ]2 B  b2 B) q

  7. % j1 h8 p$ K# J6 H) A- N
  8. contract WorldCup {1 `( |. O- z5 d# e
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队
    - o5 R2 ^- b; `" Q) m7 B- g3 w" Q8 u
  10.     // 2. 核心方法:下注、开奖、兑现
    7 T' p) J; d. D0 K+ a3 M
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    ' _* Z6 S' t9 ^4 f/ W

  12. - I4 R% N# A' [* w% M: R
  13.     // 管理员$ [. g- ~2 H- w+ R% |
  14.     address public admin;* ~! g. B% V, v; s+ b
  15.     // 第几期
    . `& v& V0 y) F- a6 v
  16.     uint8 public currRound;) T) w. v# ]/ Z9 H/ q/ \( w
  17. ' W$ P: j, n6 b) P) J
  18.     // 参赛球队
    : w8 q( T& |8 c
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];) G; ?+ q" l6 }3 f
  20.     // 期数 => 玩家) G6 M0 s) X* o* N! V; C, z4 \
  21.     mapping(uint8 => mapping(address => Player)) players;% t' o2 w  L* L& a" h+ c
  22.     // 期数 => 投注各球队的玩家7 G# G  ?/ Z6 O0 A0 S4 `4 ^& k
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;9 t* h4 t( _$ Q0 l0 T, m; \
  24.     // 玩家对应赢取的奖金
    # A* C0 x5 ?7 s+ w5 P
  25.     mapping(address => uint256) public winnerVaults;
    # }2 T$ S. z. l  k
  26. , Q& E$ A1 K7 {7 e5 _4 n" p2 {
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变' ~$ K: A9 j7 N
  28.     uint256 public immutable deadline;
    / o9 y2 _, a' n9 ]* n
  29.     // 所有玩家待兑现的奖金
    $ W* Q3 X8 C, l- ]9 e! Z
  30.     uint256 public lockedAmts;
    8 U8 c* F* `. Q! M' x% k

  31.   d( ~, D8 d. _, }1 @) ]3 ]
  32.     enum Country {
    0 k  w5 H% y8 l3 B
  33.         GERMANY,
    3 A  ^; M) N  ?1 u
  34.         FRANCH,
    0 J) n+ s2 p' Z" \. n
  35.         CHINA,
    / `/ Z' R) ?) d8 [5 w+ c
  36.         BRAZIL,' f9 X5 Q) M- Q
  37.         KOREA. J2 F  y0 G6 Y0 B$ T
  38.     }
    9 n* S/ V# |1 |5 w0 K
  39.   g3 A* v0 c; m, U, H" C
  40.     event Play(uint8 _currRound, address _player, Country _country);
    1 `1 N3 S& D7 u
  41.     event Finialize(uint8 _currRound, uint256 _country);
    * Z8 L. C: g4 _3 t; G; x) g% c4 ?
  42.     event ClaimReward(address _claimer, uint256 _amt);
    + R3 M9 s1 j- b; }6 [5 l$ F- ^
  43. 8 O7 s2 {6 i$ s' r9 ?6 ]7 d
  44.     // 验证管理员身份3 {7 C; d2 y& B# f* ?
  45.     modifier onlyAdmin {
    : v2 x8 L: ^! g& ?- ~
  46.         require(msg.sender == admin, "not authorized!");" z7 E9 m0 p% j
  47.         _;
      V2 D% v# ^' F+ z1 J$ k* J
  48.     }+ r2 i$ U: C0 k* C- D. b+ n
  49. : {, |0 {7 ?; ]  R. _
  50.     // 玩家投注信息
    ! \, Y3 |1 a+ r- b& ~" _: D( z. @
  51.     struct Player {6 B( t8 C8 O7 x9 ]- N* r
  52.         // 是否开奖
    / b/ Z) R/ o6 ?# d4 R9 C, H+ i
  53.         bool isSet;. ?# C' F+ k- d8 u
  54.         // 投注的球队份额
    ( ]3 p0 k# t8 C  ?- j' q
  55.         mapping(Country => uint256) counts;
    0 N( ?% {/ V" e  i( p. ?; L2 j
  56.     }
    5 @2 ?( w2 K& ?9 Y9 J: m

  57. 2 f" ^  f( G0 m; N8 o: [) F
  58.     constructor(uint256 _deadline) {
    ( z) O! d# Y9 n6 B% s0 T
  59.         admin = msg.sender;3 x0 M6 E* G$ {
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");
    ; U8 R  ~4 O; e: R- M3 s! a
  61.         deadline = _deadline;9 X% y6 g# L0 K! p. [! {" v" Y
  62.     }' ?+ Z$ G5 ~- F. w: Z$ l

  63. ; M7 Y" X0 L: p( ]
  64.     // 下注过程2 L) u& y1 s$ e
  65.     function play(Country _selected) payable external {4 w: e7 e6 U) k2 U' \. ~8 Q8 _0 x/ a
  66.         // 参数校验
    & E; o( N7 @4 \. H
  67.         require(msg.value == 1 gwei, "invalid funds provided!");8 V/ k* ~/ `6 M) U
  68. 8 X% ~/ D9 G6 ~
  69.         require(block.timestamp < deadline, "it's all over!");
    ) `( c4 y1 y( e/ c) Z3 P
  70. & E5 I% d' i3 @7 W) [
  71.         // 更新 countryToPlayers
    ( Y' z6 s4 i! B# G& l$ G
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
      r5 w# D# D2 `  P8 m
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)5 f- p4 D, j5 U1 d: r) C
  74.         Player storage player = players[currRound][msg.sender];% u# e' J! u2 A9 D# B
  75.         // player.isSet = false;
    * A% C/ }2 V7 `
  76.         player.counts[_selected] += 1;
    5 ^4 `' y4 p# i$ W6 E

  77. ! q* r) B- l" @( ?* f) `8 E6 g
  78.         emit Play(currRound, msg.sender, _selected);
    $ F$ d( F8 R6 M
  79.     }1 g- W, m$ b+ Z9 K4 F
  80. + M/ X/ _! q; K1 m
  81.     // 开奖过程6 g, d8 T( H" {' i9 V9 l, g
  82.     function finialize(Country _country) onlyAdmin external {/ G2 @% b' L) M, C! e
  83.         // 找到 winners
    ( \, J4 d$ w6 S7 ^) C* s& V
  84.         address[] memory winners = countryToPlayers[currRound][_country];/ `8 Z$ Z5 r/ ?( R; }* N
  85.         // 分发给所有压中玩家的实际奖金5 p  N$ A3 p2 o$ ?' W- N
  86.         uint256 distributeAmt;
    ; d% B6 k8 J0 r* N& f+ D; c8 @
  87. / E& e. O, r6 ~! ]$ m
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    5 t: w: b0 P/ N# w; g( V3 M
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;, @* L8 ]& @0 E# J$ X* ?) a
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    4 W" W; a1 H+ q, g+ Z+ ^& B/ P# ]

  91. 7 u% Q( O$ I2 g7 Z, q* B
  92.         for (uint i = 0; i < winners.length; i++) {
    4 g* U& E/ d+ o. `2 @; {% b# [
  93.             address currWinner = winners[i];
    ; O+ `4 n% y8 X

  94. # w7 R; Q: ?9 h
  95.             // 获取每个地址应该得到的份额
    # r7 }+ W* r% g# ?5 R
  96.             Player storage winner = players[currRound][currWinner];
    8 I( `9 @) o. u1 a
  97.             if (winner.isSet) {
    6 E4 q+ ]5 |: a& u) c8 T; T; O8 K
  98.                 console.log("this winner has been set already, will be skipped!");
    ) J/ z) X( f. F% j
  99.                 continue;
      c2 Q+ @+ K  u+ N: d
  100.             }
    5 a# X* [7 G2 z$ \
  101. ! n  L9 m' A/ Y) C# F$ [
  102.             winner.isSet = true;
      w  l0 u3 ]6 {7 ]4 \& ]# t6 W
  103.             // 玩家购买的份额, D8 |/ q( S7 ~: L- ]- O; v4 k
  104.             uint currCounts = winner.counts[_country];
    . f$ b# n/ R% a( Z9 Z4 p

  105. ! H/ v# b* Z& P( n/ i! M' w
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额% d9 _! d) c: _/ W) n
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;  A  R/ v6 }5 O" O
  108.             // 玩家对应赢取的奖金
    $ P; i7 x! x  y; O6 G
  109.             winnerVaults[currWinner] += amt;; l& _7 p9 x6 ^
  110.             distributeAmt += amt;
    - Y  m( c( U5 I" o3 v/ ]
  111.             // 放入待兑现的奖金池% i% K$ K) P- F9 \' ]
  112.             lockedAmts += amt;& ~+ R2 ~/ b5 r& P1 x1 G
  113.   I" U7 [4 P8 y# G( U8 w
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    4 U: z6 A5 F7 h% w7 I
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);! s$ ]% J7 e5 ^! p. y
  116.         }
    ! j1 J* g3 d4 Q; g& q; e: y

  117. : c6 n8 w$ ^: W0 Q7 k: e5 [1 q! n
  118.         // 未分完的奖励即为平台收益5 q8 i. V& ~( z* s, j! f  S& e
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    0 \  W& g! D% O/ C, F
  120.         if (giftAmt > 0) {
    . O0 N( ]+ C2 h% o) e
  121.             winnerVaults[admin] += giftAmt;- Y' S1 |3 _  T) h, d: P
  122.         }
    & E% _+ f) S2 p0 P! E5 G7 q
  123. 1 G7 |! S- a0 U7 i0 C5 u
  124.         emit Finialize(currRound++, uint256(_country));
    , d8 j$ T* c9 |' P! ~/ S4 `
  125.     }) Y: `! ?  ?$ j& q& [

  126. $ S% i/ O' T) k, e! R
  127.     // 奖金兑现
    ' O: O  q- H: s0 n+ K0 V8 [
  128.     function claimReward() external {) C; z* A0 ^7 ~, n; q, L
  129.         uint256 rewards = winnerVaults[msg.sender];) Q0 L- I0 u4 v+ H0 Y
  130.         require(rewards > 0, "nothing to claim!");  l4 I2 c/ v$ \' o

  131. . ^/ |  f1 b) c" i; M- e6 \) |, B$ X3 ~
  132.         // 玩家领取完奖金置为 0, o2 [% X) \1 t+ r" p
  133.         winnerVaults[msg.sender] = 0;
      m8 F; Z/ B  m; j0 @5 n
  134.         // 从待兑现奖金池中移除该玩家份额
    , I7 r" u- M" W8 I
  135.         lockedAmts -= rewards;; J4 x8 j" y) `# a
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");# ~- }6 }* s" C6 g$ u, T
  137.         require(succeed, "claim reward failed!");
    * a" o; X1 |& O/ b: T2 t0 U4 Z" e
  138. ! E- R+ |6 n, v, e9 i
  139.         console.log("rewards:", rewards);. ]% j  N8 X+ b
  140. 6 M# E6 m+ ?. G: M+ z, z
  141.         emit ClaimReward(msg.sender, rewards);/ r& i, H1 w1 U: Y
  142.     }
    9 g  F. `9 u4 P' r8 J2 D) e% z

  143. $ P$ I9 q+ @; o+ u0 w& b7 _- X
  144.     // 获取奖池金额
    , {% `8 T- T" R8 H/ {
  145.     function getVaultBalance() public view returns(uint256 bal) {
    6 R$ L8 l6 D+ \: R6 n2 I
  146.         bal = address(this).balance;' ?, \, P1 K3 \
  147.     }3 Z! w2 Z0 J' E# _* Q" _" P) w- ?( o
  148. 7 ^. X, |2 K  K' Z
  149.     // 获取当期下注当前球队的人数
    4 I1 s/ v) x' N) O
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {8 s9 p8 k$ z( u+ I' T* Q% M% i
  151.         return countryToPlayers[_round][_country].length;& s1 c+ f, s( }1 c: a
  152.     }$ @/ g4 K1 ?- {. o

  153. , C! E$ g0 c0 e6 i% ?8 k
  154.     // 获取当前玩家当期押注份额
    3 X/ I2 m& ]( |' t4 f! ^. l
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {
    7 o3 b  m* e: v0 U. _3 U
  156.         return players[_round][_player].counts[_country];) c# \5 o8 h  T% y$ I( \/ d
  157.     }
    ! l2 s2 K! r  O8 A" t
  158. }
复制代码
) I1 O2 i0 j8 E4 y! D
' _* d6 O: j9 y" V1 a$ K7 ~
- D0 T  H; |4 B0 k3 T: e2 h4 l

: ]$ z" }3 y$ h9 d. |) q/ Q7 X9 g/ C2 b9 I/ e
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4