Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
376 0 0
业务需求% w1 C+ Y& u/ O
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始8 `6 R! m" V# a" N- a1 a  V
5 n6 N1 O1 A, f8 t3 T
) S& V7 j9 ^, ~6 |2 i
* K. ~! ]8 ?0 |# |0 E8 g' `- G
  1. / a  u9 Z. D& W; j- L
  2. // SPDX-License-Identifier: GPL-3.0* [# J# ^# l' I/ D- W& L. F

  3. # I* ~% W7 c' W; d, w
  4. pragma solidity >=0.7.0 <0.9.0;
    5 Y0 D0 c& ^' P+ x% |1 }& H
  5. . i! Z% W. [: o: u& E9 K* ], X
  6. import "hardhat/console.sol";
    3 h1 _. G- K9 _

  7. 8 ?$ x) |0 J3 w+ [8 ~7 n
  8. contract WorldCup {
    . l( W! f3 R0 K& b
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队
    ( r, d1 m  H' P/ C4 j
  10.     // 2. 核心方法:下注、开奖、兑现3 |5 a/ m2 N$ D- ~, B; j5 F& {
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    1 p' u/ h5 Y8 `$ E1 O8 K+ M5 d
  12. 9 V9 r2 C% r* u! ?2 ^+ F: R" I. m
  13.     // 管理员. G' k; q& E3 t% {" i2 C
  14.     address public admin;' f7 [0 B  C# p, u, G( p% H0 H* J
  15.     // 第几期
    - N+ }- z/ S; ]3 L& D  m8 y7 ?
  16.     uint8 public currRound;
    : |4 G* P3 q& _+ M
  17. # F0 F$ ]" Q2 P/ H# Z) ?0 [
  18.     // 参赛球队
    ; i7 Y" e2 [2 ?* M% W, s
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    * T7 Y3 K" C1 U, T
  20.     // 期数 => 玩家
    : J% {8 x, G' l. ^
  21.     mapping(uint8 => mapping(address => Player)) players;8 G6 Q7 n  Q8 A! C! a# x/ s- \' A" E4 n
  22.     // 期数 => 投注各球队的玩家
      o8 h/ F/ N  @
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;+ X7 [% P$ B* b2 L, X  k
  24.     // 玩家对应赢取的奖金1 \1 M5 P4 L# F7 V: C
  25.     mapping(address => uint256) public winnerVaults;: }! y2 A/ o0 c! k/ W

  26. 2 C6 W& i  Q( ]6 A# ^  ?
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变; u" ]& e" L* D% d# B' n/ K
  28.     uint256 public immutable deadline;; g# }2 `  L# O" V$ i
  29.     // 所有玩家待兑现的奖金, h) H  ?/ U/ g2 _) `
  30.     uint256 public lockedAmts;3 E0 k6 Y; W# B2 o& w

  31. 1 H" A7 I5 _1 e. R9 h
  32.     enum Country {1 d! w9 K% U1 l8 Y. \, E
  33.         GERMANY,
    # [( ?' d/ B+ \% C6 @
  34.         FRANCH,
    0 t  z4 m3 b  \
  35.         CHINA,
    # G6 l  t/ D6 l
  36.         BRAZIL,7 U/ i3 ~0 h: @: |& u% {
  37.         KOREA
      [/ m9 X4 S+ [
  38.     }! I& |$ U0 D  Y2 m4 o
  39. 6 G1 [& w7 a) u/ A9 x
  40.     event Play(uint8 _currRound, address _player, Country _country);
    ! r4 ?. p8 R$ D5 D3 h
  41.     event Finialize(uint8 _currRound, uint256 _country);1 N7 k% i. _; g, p6 Y3 w, d4 r
  42.     event ClaimReward(address _claimer, uint256 _amt);9 H) _  W* S: S. k
  43. - B  r: u, d  U" W  M0 [& K# ?
  44.     // 验证管理员身份  A3 y) E& s! w7 r/ K+ w
  45.     modifier onlyAdmin {7 A' k6 T- D3 A! o2 w# v) Y6 }
  46.         require(msg.sender == admin, "not authorized!");
    . f7 K1 k% D" |, e
  47.         _;
    ! s* @  M" M3 K
  48.     }
    8 o" d2 ?; G# \! d9 b
  49. 6 L+ n2 |4 A3 P; \7 F1 G+ T) m( }
  50.     // 玩家投注信息
    " F1 {" `  z9 O7 M2 j% R5 `; a$ c) N. q
  51.     struct Player {
    ) l; n4 A- M; ^: Q* H
  52.         // 是否开奖( N) E% @' p( `. J# [% S" V
  53.         bool isSet;
    ' L: I4 C6 f7 A2 ]: E6 h
  54.         // 投注的球队份额
    1 x  C, [4 w( H4 |& S! s+ n
  55.         mapping(Country => uint256) counts;& p/ C0 @) I4 v, {- l; q; {
  56.     }+ N, F9 z; T$ k7 c

  57. # l1 O5 U- Y% j1 u
  58.     constructor(uint256 _deadline) {
    # G. j4 p& \! j4 `. {; |# B  y+ X$ R
  59.         admin = msg.sender;8 H; ^* L- Y" |1 O6 W  L0 s
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");1 g+ h8 U5 W- ^7 ^% d. z
  61.         deadline = _deadline;. T- m2 [  u, v5 l; [5 [: s" N
  62.     }
    ; b  s: `" C8 ^
  63. , }- \3 k) r+ U2 Z" X" b7 D
  64.     // 下注过程
    * P* ]5 E6 Z/ K4 f5 A- Z6 M
  65.     function play(Country _selected) payable external {
    - p3 q$ o8 M1 C
  66.         // 参数校验* Z( ?) N( l. m8 p  |( M* h
  67.         require(msg.value == 1 gwei, "invalid funds provided!");, `; ?) ?( L9 x+ S( [

  68. 2 [5 h: ]% W! \1 T! Y# ]2 P
  69.         require(block.timestamp < deadline, "it's all over!");
    1 q. n: g: F2 {) J+ C
  70. & X0 p7 V1 g0 w
  71.         // 更新 countryToPlayers
    : ?. m" g" k" z5 p9 J- t
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
    8 M. }  ?1 _5 O5 `+ E, a
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    " D7 A: |# q1 i# Q" t4 s3 }+ e
  74.         Player storage player = players[currRound][msg.sender];. v& z) t7 ^  B
  75.         // player.isSet = false;! y2 X. x1 G) U' E/ G2 p
  76.         player.counts[_selected] += 1;& q( {1 [) c  ~( a4 M

  77. ) i/ ~, ]7 K: v( c& S
  78.         emit Play(currRound, msg.sender, _selected);2 U9 P# w- o2 v* ~0 ^5 L% w7 G
  79.     }+ [3 i+ @, `) j# l9 e/ K+ q% C
  80. 9 u% I5 j+ u" }& c, {: d- `
  81.     // 开奖过程
    # h% P) F% Z2 |. c- f
  82.     function finialize(Country _country) onlyAdmin external {
    % p4 t  |9 b! g2 g$ s
  83.         // 找到 winners
    * ]2 |) S7 C$ E9 M# d
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    7 x3 ]* Z8 T: N
  85.         // 分发给所有压中玩家的实际奖金7 f% h( a. b9 t9 A$ I) m
  86.         uint256 distributeAmt;
    6 M/ n* t' V4 l6 l7 n' y
  87. 5 X3 T4 f" q7 Q5 E% l
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    # w0 K# v0 K- W4 j
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;1 c! x+ e6 V* J  c. B& M1 i/ w% X
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);( A1 y, {3 t2 o7 D3 `0 a: _. F$ M7 W9 j
  91. ! f$ U) R  H9 F4 ]$ p
  92.         for (uint i = 0; i < winners.length; i++) {
    - y& f# L  y' w* Y; C+ F
  93.             address currWinner = winners[i];
    * c, O0 D. \" {8 k' d2 k
  94. * k8 M$ z( [# L" H2 |$ U
  95.             // 获取每个地址应该得到的份额
    1 ]! G2 t. y8 u. U# c
  96.             Player storage winner = players[currRound][currWinner];( ?# f" I; Q5 L% U# m/ E5 M' ~
  97.             if (winner.isSet) {& r+ f+ n) C2 S6 d9 \7 z
  98.                 console.log("this winner has been set already, will be skipped!");
    2 B4 o) S5 ]( q/ \0 l
  99.                 continue;( ^  j. v2 K8 C6 Y, o* x9 B7 P% V' }' u
  100.             }% A8 q# U9 e' x) }/ R

  101. 6 d6 D. ^. I% X
  102.             winner.isSet = true;
    ( F" _5 B+ Q( I7 o9 O
  103.             // 玩家购买的份额
    " E2 g% p0 |, b) ~
  104.             uint currCounts = winner.counts[_country];
      d0 u- j+ j& m% D
  105. % @9 I1 @9 D# t2 R5 {* d. n# R0 R
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
      b+ a8 V8 t6 c
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;$ A  ^7 x3 B0 Z
  108.             // 玩家对应赢取的奖金
    ( H4 u: t3 c2 X% q3 w" m1 a- r
  109.             winnerVaults[currWinner] += amt;; M$ h2 h8 L" r# Q- @  Z. }8 y" x' p
  110.             distributeAmt += amt;3 J+ l9 N) w( \; ]- Z1 {
  111.             // 放入待兑现的奖金池: R6 G$ t1 n& u! U' M
  112.             lockedAmts += amt;( s$ _2 V  v3 q& @" w. e

  113. 6 M- _+ q. l1 `5 M- M2 e
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    5 j' r! C2 {& c( E, w+ Q- i
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
      y# l7 _& c" A, p
  116.         }. r/ `' {9 L0 e; S+ P( u
  117. " i& F$ H! f  a
  118.         // 未分完的奖励即为平台收益- E1 X4 G" o8 A, G6 M$ y3 A
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    5 I8 R6 M7 c" N! j- Y$ F1 v
  120.         if (giftAmt > 0) {
    6 O5 K6 U! n& ]9 J; @
  121.             winnerVaults[admin] += giftAmt;
    7 ^; c6 |% x+ U9 T/ @
  122.         }
    5 m  U2 j' S/ A

  123. 1 m4 g- M& X. t  u7 ^: h0 S% a
  124.         emit Finialize(currRound++, uint256(_country));
    - C/ G& O4 ]5 V3 C/ \& c( P
  125.     }
    3 V) C) d8 Y% J0 s1 y# w* a/ k0 u

  126. " D2 H3 v+ ~' d! b$ v2 K7 ?, ]
  127.     // 奖金兑现
    9 m8 W" a4 O( x
  128.     function claimReward() external {
    7 x0 u- P1 N6 a$ l4 ^; ?0 N
  129.         uint256 rewards = winnerVaults[msg.sender];7 v' i7 l" O* d6 W  l& y: n1 ]
  130.         require(rewards > 0, "nothing to claim!");+ Y9 \- l5 A, n4 O) v9 e

  131. " c- t5 ^5 U$ o/ K. C
  132.         // 玩家领取完奖金置为 0
    2 {' W" x: M6 ]. d
  133.         winnerVaults[msg.sender] = 0;
    : W! C: H& O, }  j; x5 x5 g
  134.         // 从待兑现奖金池中移除该玩家份额
    ( w) j) c+ \" W- ]- `, [- C. J
  135.         lockedAmts -= rewards;1 _+ I5 X0 g9 _6 l
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    4 `4 d3 C' F# W6 i
  137.         require(succeed, "claim reward failed!");6 z9 g0 k# C& _
  138. $ [1 f+ ~9 R0 ]. y
  139.         console.log("rewards:", rewards);6 S2 b* [: x* {! V: o5 F: E5 W3 _
  140. , N" L) [- C6 C7 _. X
  141.         emit ClaimReward(msg.sender, rewards);
    ( ~8 K. ?  F9 Y8 m
  142.     }" c) A' n8 ^; u7 I! O

  143. ( @- Q% B9 i4 z: |: _; ^
  144.     // 获取奖池金额% g2 G- O0 }  _  U/ o+ v
  145.     function getVaultBalance() public view returns(uint256 bal) {
    6 F/ T% r& R- c+ i' m4 `. p9 O& Y$ w
  146.         bal = address(this).balance;) {9 w% m7 o! j+ o
  147.     }
    7 g0 d8 D$ W# w5 d4 p" x; |

  148. , }- n" b* h- N: d; i
  149.     // 获取当期下注当前球队的人数
    ) I. W$ S  x( g. A, ^
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    - \) |0 z  U% F1 S. `8 S& a
  151.         return countryToPlayers[_round][_country].length;
    6 i- E# J3 `: g7 `" z, o0 m6 K
  152.     }! D7 }7 L% |& y
  153. $ o. M( J" l* j% c
  154.     // 获取当前玩家当期押注份额; U3 _2 S; Y9 Y5 @+ S$ Q/ O
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {' [( ]$ o6 M( U# y9 c
  156.         return players[_round][_player].counts[_country];
    ) ~' [+ l- w) J
  157.     }
      s( H/ m! Z- h: d; Q' }
  158. }
复制代码
. M3 b2 u& G: A% E5 w

* @. c7 k, y  K& R7 |, Y1 i$ y: {6 ?. B1 M. {. {. @' \" i
2 e# `& Y1 H% }# E9 Z

; V6 u0 U6 F: B
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4