Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
466 0 0
业务需求; S8 @' A# @8 y; a3 A
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    8 b+ U4 @+ ]! c6 e% w+ `' P% w
& R" E" T$ u% I. f
8 c- {  g: v+ j, f9 W
' f! `0 C2 q0 x- K1 _
  1. 2 m& w" M( O" f" T: T% `
  2. // SPDX-License-Identifier: GPL-3.0
    + y1 c- n# q# H6 V& L) ?
  3. ! ]! o/ M4 x5 `$ P- S3 b
  4. pragma solidity >=0.7.0 <0.9.0;* H2 B& X; V! D0 I# u' w- ?) W3 @' H
  5. % h9 r8 F# {! z+ J9 g' M
  6. import "hardhat/console.sol";* v$ r" i* j6 X, Q

  7. 9 G" Y0 G/ S4 t) y( c8 l
  8. contract WorldCup {8 U: o. A8 h- U* ^' t2 w8 ?
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队
    " J7 z: n# r$ q& e1 I9 J
  10.     // 2. 核心方法:下注、开奖、兑现
    1 a4 D# f& Y( Z4 t
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    1 |8 ]% c& ?0 i' @+ d6 I% V
  12. " X2 o( }1 F/ l8 _
  13.     // 管理员1 Y& Q- [# Q8 P& u( p
  14.     address public admin;
    ) @; D' A+ A' A! q! ]: \/ K
  15.     // 第几期+ e( _9 ], R) y& S' V6 R
  16.     uint8 public currRound;
    5 ^& K& ~) ]1 N* w2 [

  17. ! D; Z0 }5 `# h/ u- X, M
  18.     // 参赛球队
    1 V: _2 i3 K( D
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];1 j# m  H8 V) l% b+ F5 x" A# m
  20.     // 期数 => 玩家
    - S/ H( H6 F% K2 ]" T% V* g/ V0 X
  21.     mapping(uint8 => mapping(address => Player)) players;+ b3 B: W" C2 T9 Z
  22.     // 期数 => 投注各球队的玩家
    6 f& O( A) W% f: B2 s) x' Z
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;- N* D4 e/ f$ k; J  u) e+ b
  24.     // 玩家对应赢取的奖金+ N5 H1 z$ y/ B
  25.     mapping(address => uint256) public winnerVaults;
    0 ?/ w- k8 c- K% _
  26. 3 z' K1 C- E2 X4 S$ w
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变
    7 X0 X  K- Z3 L' d$ E: ]
  28.     uint256 public immutable deadline;9 A+ C& m) g( [9 I8 R! c
  29.     // 所有玩家待兑现的奖金
    : W8 z$ \5 a8 B+ ~
  30.     uint256 public lockedAmts;
    $ w0 r  x8 w/ o; ?2 K
  31. % u: o; r5 {" M4 M: q
  32.     enum Country {" \5 H+ B4 P$ B+ I! I8 s2 ~( R
  33.         GERMANY,& O9 m9 Q$ p" q3 B4 |1 y
  34.         FRANCH,
    , l5 T9 R8 p. [$ R" b8 |
  35.         CHINA,) P: @8 l! U' \6 |# g- B) g
  36.         BRAZIL,5 \% M5 E/ d% U( f9 l& \
  37.         KOREA
    & g0 X0 r* e( V% i3 N, H1 O- r% [
  38.     }# F5 ?/ @/ ~% q$ y5 m: z" L
  39. 4 ~9 M* R+ _/ @" e7 R7 H. V
  40.     event Play(uint8 _currRound, address _player, Country _country);5 D$ P- d  D! B% I, P
  41.     event Finialize(uint8 _currRound, uint256 _country);
    ; `; J" ^; Y/ ~/ R
  42.     event ClaimReward(address _claimer, uint256 _amt);0 a1 B/ y) K- D# Q* P/ k- d
  43. ; m+ Z2 P* x) O, C7 A0 U% N
  44.     // 验证管理员身份
    2 V4 t& ~: D; w- {4 ?4 s1 S' \. V
  45.     modifier onlyAdmin {( r2 f$ C4 }* _( k  K+ j
  46.         require(msg.sender == admin, "not authorized!");$ G1 a" D& }# M- w( ~# J" Q- L
  47.         _;1 }  z5 p( K( n. N2 P! \9 k
  48.     }; o( A& A: C  ~$ H8 u0 x! g

  49.   r; Q  e* O: C- G
  50.     // 玩家投注信息
    0 e1 t+ f6 h# q+ X* e
  51.     struct Player {* q6 H6 `; K7 I$ |4 n9 p! k! `; ~( m
  52.         // 是否开奖4 B5 T# L/ j9 m! g
  53.         bool isSet;
    4 Y! X; A9 M4 |# {$ O8 O
  54.         // 投注的球队份额
    6 |& H# [& L+ _! L* d
  55.         mapping(Country => uint256) counts;- B+ f$ t* P$ I) {
  56.     }
      `! a2 i3 }# u+ M2 V- m

  57. ; E2 Y8 e$ @& }/ _# S% ^; y
  58.     constructor(uint256 _deadline) {
    - r$ Y- C" l+ n( ?# Y1 P6 G0 c
  59.         admin = msg.sender;( Z. k* p3 i: `) F% o$ M" R
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");: K/ K6 _1 r" a' E$ V6 s
  61.         deadline = _deadline;
    ! V% u+ C2 b! \7 s9 `/ M5 B: K
  62.     }
    8 G* V4 O& c8 T; x4 H
  63. * H- L" \! [& ^( h7 F2 Q
  64.     // 下注过程
    $ c  X+ f" R" ~6 D
  65.     function play(Country _selected) payable external {5 G% ]5 I: D1 N
  66.         // 参数校验
    ! ]' K. j" U  R$ e5 z) ?7 z+ ?# G. H
  67.         require(msg.value == 1 gwei, "invalid funds provided!");
    - x0 U' r; F8 C- E
  68. $ V9 H2 i9 A5 ?% J; C
  69.         require(block.timestamp < deadline, "it's all over!");; v; l( R+ v- F: {
  70. 0 Q/ s- Q4 i/ ~! U
  71.         // 更新 countryToPlayers
    3 t! p+ W7 Z7 Y0 L- e; T4 d
  72.         countryToPlayers[currRound][_selected].push(msg.sender);5 J( Q7 ~: ~6 t$ u
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    8 A: T( W6 i, `. n9 A( s0 U, B
  74.         Player storage player = players[currRound][msg.sender];9 S8 E- g& A& Q# ~* X! ~; a
  75.         // player.isSet = false;
    + E; u& A! h5 P7 z  `
  76.         player.counts[_selected] += 1;5 _1 L- I7 }" b. x( j

  77. 3 }6 |6 k0 Q" \, y9 B8 o$ l+ M
  78.         emit Play(currRound, msg.sender, _selected);1 X8 }7 J! d2 M5 ~# h  J
  79.     }8 w4 q' F2 h' ~2 v% ?% f4 B

  80. ; y4 p% Y8 P* S- U) f5 n
  81.     // 开奖过程# t# S2 J/ i' L# i: |! x
  82.     function finialize(Country _country) onlyAdmin external {5 X! i, f- H. e: A- h0 W, P, D
  83.         // 找到 winners
    # T7 o: j* }1 a  ~  j8 N
  84.         address[] memory winners = countryToPlayers[currRound][_country];6 B. J: i6 G9 n; B( O
  85.         // 分发给所有压中玩家的实际奖金8 Y* }9 W. y* T, F
  86.         uint256 distributeAmt;
    " F, v( W  Z- `& P  R3 W

  87. % ]  s6 }6 L- }* {2 s0 l
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    , u- j2 y* y. j+ V
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;
    ; h! p! O+ u# m
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    . E. t; |  n" p4 \- i& P

  91. + v" w1 e, s% A
  92.         for (uint i = 0; i < winners.length; i++) {
    # W" ?: \! R4 W6 e( T* z9 a
  93.             address currWinner = winners[i];! k+ d" T! a. S& F$ L! q) Z8 }

  94. , N$ |: ~0 o7 u$ j
  95.             // 获取每个地址应该得到的份额
    - k3 O( A0 L) m! y9 v7 x' o
  96.             Player storage winner = players[currRound][currWinner];. h3 @) a/ ^8 ?% G: Z$ T! [  f, \9 Y
  97.             if (winner.isSet) {8 N" }+ o- J3 y- T3 [
  98.                 console.log("this winner has been set already, will be skipped!");' R4 l, y) s3 D6 s
  99.                 continue;8 t& U4 n$ A9 ~, G$ F
  100.             }
    7 O7 \4 ]4 F9 A1 R6 I

  101. ! k% n" m9 W! R
  102.             winner.isSet = true;$ d8 ]7 |: o! c- D7 {
  103.             // 玩家购买的份额
      D; E* ]* k4 M0 Q
  104.             uint currCounts = winner.counts[_country];
    . E. {( o& E0 W& z5 V0 K
  105. 9 _4 Q) Y- @' @, K
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额* G2 K7 u- W# `. z% O1 M
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;& X9 l# G# f# M. r
  108.             // 玩家对应赢取的奖金+ }* n8 Y+ B2 t+ p! n! e. _
  109.             winnerVaults[currWinner] += amt;
    ; h# D1 w. N( w. M# J9 |# R
  110.             distributeAmt += amt;
    6 W4 |- C. X: q" _7 I* x1 g
  111.             // 放入待兑现的奖金池1 Y- H$ D- `# k, h$ ^1 G
  112.             lockedAmts += amt;
    2 X/ {$ Q- n) L" e

  113. 2 c& b" W6 I; w' ^# p4 n
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);% M$ m& _! w5 O; k3 O) @7 t+ u
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    6 a6 W7 ~: u7 t/ R+ c# w
  116.         }( R8 r/ _' R3 v, Y+ k
  117. 9 J9 r% H* Y7 {3 g5 z
  118.         // 未分完的奖励即为平台收益, d  a6 |) [$ H0 Z) P9 {5 v% v
  119.         uint giftAmt = currAvalBalance - distributeAmt;- y9 ]/ I8 l+ n8 Q  c  F
  120.         if (giftAmt > 0) {
    ; U" R8 N" m. j, n. A0 Z. r% D
  121.             winnerVaults[admin] += giftAmt;- H2 x# J1 v0 d! ?" W
  122.         }
    : ^1 k9 U1 t. v# Q9 v% j" {

  123. ' C( T8 |5 O' G" ?
  124.         emit Finialize(currRound++, uint256(_country));
    5 R. F" r0 K8 L5 Y  t
  125.     }7 _. u$ W& A+ f' j2 ^
  126. 3 i2 p$ C* h; U9 Q% P2 l3 F2 k
  127.     // 奖金兑现$ o! Y: m; ]# {
  128.     function claimReward() external {
    0 q3 p8 l5 m6 |; g
  129.         uint256 rewards = winnerVaults[msg.sender];
    . U0 O: z" c0 z4 R; x3 ~3 z
  130.         require(rewards > 0, "nothing to claim!");$ K# E4 P& s& A# h. z5 {$ X
  131. 5 @" q+ @; B" m/ d- e2 O3 x0 J
  132.         // 玩家领取完奖金置为 0
    1 S- D/ I0 Y" t  h+ {0 z0 g  V% Y4 K
  133.         winnerVaults[msg.sender] = 0;
    . M8 S$ o/ e, J
  134.         // 从待兑现奖金池中移除该玩家份额
    / p+ o, ~) x7 S- O+ S6 t  A
  135.         lockedAmts -= rewards;6 I2 D- L- g9 e) g5 E0 T
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");9 i$ b2 n: _' c' o% D, v/ e  [
  137.         require(succeed, "claim reward failed!");& V" }( E/ W+ v  N; j5 ^" Q
  138. / ?4 J, |6 C1 Q* J7 Z8 [4 J8 P$ \
  139.         console.log("rewards:", rewards);$ p* T' p9 H8 X( q, O
  140. 2 d8 H) T5 S% o7 D7 @) M( F
  141.         emit ClaimReward(msg.sender, rewards);# [2 T4 o5 p5 x9 K4 M
  142.     }
    * c; d# S( S! I) l. g  @/ A
  143. , E, {: E; x% e( x, p/ V, v
  144.     // 获取奖池金额
    ! z% }" ^. p! l  y
  145.     function getVaultBalance() public view returns(uint256 bal) {1 n6 a) T& x! M7 O9 Y* c$ p# K
  146.         bal = address(this).balance;1 C$ _9 m/ C9 [8 p7 `4 w4 U) W9 r, O
  147.     }
    + J# f  R) h& k7 o

  148. - A% ?- y5 \) M. ^" Q
  149.     // 获取当期下注当前球队的人数
    - ?9 r: d' H7 F: I6 M: I
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    7 M9 U8 T4 p  R
  151.         return countryToPlayers[_round][_country].length;
    2 J- L" E. y  F
  152.     }
    0 ?( `' y+ n# g4 n: N1 ]
  153. , J7 b5 S: v- k0 P' x% W
  154.     // 获取当前玩家当期押注份额
    4 J8 O9 c/ J$ Q2 B
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {- q' ]4 j5 X0 C3 a2 M" X
  156.         return players[_round][_player].counts[_country];4 m+ K5 F+ w5 r( s( d1 R0 m
  157.     }
    2 w3 c2 D) O3 O
  158. }
复制代码
4 k" Y1 y: S# e
) P" O1 H* a% {( N7 ]1 ~
! \. z" }  v3 \- p# d
" M$ [( B/ i# r. F. ~2 |

8 T" b, ]9 z! e3 `& ^% |
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4