Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
328 0 0
业务需求
+ U/ q: o) W6 i2 y
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始; V7 H0 l1 i" e8 R
$ H1 t0 q: b" j: X
; c3 X& ^: a8 f3 j2 h# b) _
- a+ }. B0 l; _0 l: V9 F: s: r

  1. " H" X6 m( }/ l* M! A3 h& X
  2. // SPDX-License-Identifier: GPL-3.0" Y; F5 }. p7 J# u! [

  3. 2 g; Q) R% a& `" [  z
  4. pragma solidity >=0.7.0 <0.9.0;
    , }( f" F) z% W1 B' a, ^3 m
  5. ( q% ?/ I( a; ~2 b4 \
  6. import "hardhat/console.sol";+ e% l8 `* ?1 z/ n; o

  7. & y1 }. f. b, Q/ R( T, h
  8. contract WorldCup {
    0 Y6 R# K0 O" n" ]! ?+ e$ E& r
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队7 k" i- Y1 S0 b) m3 h& M$ [
  10.     // 2. 核心方法:下注、开奖、兑现
    6 g) j2 U( w$ ~% i# a" I& d
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队4 Y* Y' g, R) M" m* i

  12. 8 w" F6 I8 ~" n! p3 R) X  N
  13.     // 管理员  ~4 z7 V: [& D4 t8 n* F
  14.     address public admin;- n+ H" O( F6 n* f# v0 a6 ~% Q2 s1 ?5 ]
  15.     // 第几期) i) g% D/ j9 m0 ?/ \
  16.     uint8 public currRound;
    : z- A* f2 _$ e
  17. & h3 t6 |0 v0 |$ w7 E
  18.     // 参赛球队
    - U3 L( y( o' t! S2 P1 @
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    " R: _9 Z8 P1 g& k& S
  20.     // 期数 => 玩家
    ( \  d3 X3 {* W( \( F( G. w$ e
  21.     mapping(uint8 => mapping(address => Player)) players;
    ; |+ D* R# i9 q0 m
  22.     // 期数 => 投注各球队的玩家
    / m' e  U: Q6 w' H$ P8 g
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
    ( V+ b% L4 T. w5 t* J" [. [. F
  24.     // 玩家对应赢取的奖金. S, s! F# ^$ s7 D8 s- b
  25.     mapping(address => uint256) public winnerVaults;
    . Y% \* U- ~: o) C7 S3 O6 f

  26. 7 }  a) k- c' y& e, J8 h8 A4 X
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变( o; J7 |  g) g& w
  28.     uint256 public immutable deadline;
    : p' q9 e9 O- R; K1 ?
  29.     // 所有玩家待兑现的奖金
    ; S+ a0 \& h* V9 W6 v# R; x- d
  30.     uint256 public lockedAmts;* V6 P3 L6 Z, ~8 _5 U9 O4 u

  31. 3 N$ U  r' ]; U
  32.     enum Country {
    " G2 ]! \. N- I4 j9 A
  33.         GERMANY,
    , U& I6 U  _" M5 O+ w: _
  34.         FRANCH,
    * N. p) w! u! |2 P% d
  35.         CHINA,( ?$ S: v* Y1 [# D% P
  36.         BRAZIL,
    ' t7 U* e; w1 Y% ]1 w: |* ]7 t* T
  37.         KOREA" @/ n" M; x: k5 _) D
  38.     }
    + ^( `5 i! w3 w4 z
  39. % m0 M3 A( T$ o4 s% _
  40.     event Play(uint8 _currRound, address _player, Country _country);
    % u$ g( h% v' x
  41.     event Finialize(uint8 _currRound, uint256 _country);
    . w1 r# M! N4 I, F  U; @# W  \
  42.     event ClaimReward(address _claimer, uint256 _amt);
    " ^! a% Y, A3 q' V

  43. 3 a0 y% c- U9 ^
  44.     // 验证管理员身份- w- S) Q! }# y. T1 S) e4 h
  45.     modifier onlyAdmin {
    ' O  L( P7 g$ ~; O: G2 o8 y
  46.         require(msg.sender == admin, "not authorized!");
    7 P0 ~" a0 g8 ?& ^  K: E
  47.         _;
    $ S/ ^# y1 h- E5 t
  48.     }
    ' Q! Y9 f. I4 b& r. N
  49.   F0 C- s, Q( {  I3 S
  50.     // 玩家投注信息: x6 R' i& ]  f6 {0 K" ~
  51.     struct Player {2 z7 d, H# q1 w1 M* \5 H
  52.         // 是否开奖" [1 H% J! |+ j. b
  53.         bool isSet;7 B% V5 U) O% I: K
  54.         // 投注的球队份额
    ' c: F& {/ V4 e3 B, }4 A
  55.         mapping(Country => uint256) counts;/ o1 l7 G. B# C  C: g
  56.     }
    ' M, }% M8 v& }) S$ n

  57. $ O: U; y1 m5 j) S+ g
  58.     constructor(uint256 _deadline) {
    0 d. O2 d% v5 y1 r3 a0 [% k
  59.         admin = msg.sender;$ J! R4 v8 i* q0 c" h
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");
    3 L) L7 T4 ^% n( L  t; @6 \8 T
  61.         deadline = _deadline;
    9 _0 H+ Q0 O: t: n7 I0 O' M6 ?! S
  62.     }
    0 A$ v- T5 q: ^! c; B

  63. $ z8 P8 w1 r+ ]4 {1 d- R* c
  64.     // 下注过程+ z% @8 t7 B7 ]' \) N; }* M
  65.     function play(Country _selected) payable external {
    % p, s' a' l* y9 P
  66.         // 参数校验
    0 E) Y9 p. A$ i& m9 d
  67.         require(msg.value == 1 gwei, "invalid funds provided!");5 z, _0 v, p/ ]/ C

  68. ! Q! e  ^4 B! W; ~. {
  69.         require(block.timestamp < deadline, "it's all over!");
    ' m3 s5 X/ P2 h4 o; c$ G2 T) O1 m
  70. , [1 C7 T" w, G* @
  71.         // 更新 countryToPlayers
    1 u8 o1 M5 N# P' m
  72.         countryToPlayers[currRound][_selected].push(msg.sender);$ G2 U- r2 Z  h6 j  T
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)+ ~% c0 Q. ?! L5 {
  74.         Player storage player = players[currRound][msg.sender];/ l, A9 Q! G6 ~' x9 P
  75.         // player.isSet = false;, Z* T# n) d5 Y3 H9 w( j8 I
  76.         player.counts[_selected] += 1;
    , ~$ H4 [9 ?9 l  ^( r
  77. 6 ]8 R8 v2 Z( G" E
  78.         emit Play(currRound, msg.sender, _selected);
    4 w+ F% ?( j$ `) q* r( u
  79.     }9 s8 x5 d# n& Y0 g
  80. & }  u) j' W; H( v: f9 C- e
  81.     // 开奖过程
    , n/ b3 k5 y* O+ C3 ~+ `
  82.     function finialize(Country _country) onlyAdmin external {% g5 [: W0 ?1 k0 v5 S7 M% ~
  83.         // 找到 winners
    , u3 J, r& f0 G& E
  84.         address[] memory winners = countryToPlayers[currRound][_country];; |( g1 K' `# V4 X/ w
  85.         // 分发给所有压中玩家的实际奖金
    . P4 W1 X% \5 r7 ?& q
  86.         uint256 distributeAmt;
    2 {8 S- K5 e& \/ f2 E$ ^
  87. $ p+ r: r4 b5 f8 l0 i4 i* n: O( ~
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    $ l3 I7 e: Q2 H9 m. W* W* ]6 M
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;  W6 _2 J; T7 O
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    4 v8 Q' m" ]7 X6 v

  91. $ u1 E& N4 b0 z" C+ i
  92.         for (uint i = 0; i < winners.length; i++) {6 A4 M! D& K! U6 z7 p) j' h2 m
  93.             address currWinner = winners[i];
    9 U! W8 `1 g/ @# J2 K; D# l3 R
  94. 1 U& o, h- @8 N  c9 }
  95.             // 获取每个地址应该得到的份额( s+ x) y( {2 L; G. W
  96.             Player storage winner = players[currRound][currWinner];; [' v0 B; l; j9 T
  97.             if (winner.isSet) {
    - a/ e; U$ K! Q, z
  98.                 console.log("this winner has been set already, will be skipped!");) q% o7 }  u, w- U& o0 \( L5 H- n; I
  99.                 continue;
    * z/ A5 P3 m& A1 s' w
  100.             }. U. D) f; x5 e* ?" B, s

  101. : ^# `" |8 B* t, |
  102.             winner.isSet = true;
    + h" B5 _2 d5 k0 b/ Y4 z8 p
  103.             // 玩家购买的份额+ f2 J" P- L2 [: \" t
  104.             uint currCounts = winner.counts[_country];  K& h" ?; M) ~% @- C
  105. ) g1 H, ^0 i: q2 ]  L/ B
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    % J% Z1 r9 J. m
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;
    / i( z/ N$ Y: V' _
  108.             // 玩家对应赢取的奖金2 g$ k( f4 |0 P4 k
  109.             winnerVaults[currWinner] += amt;8 Q& \2 ~% D8 T* Z: C$ g) k1 }
  110.             distributeAmt += amt;
    ( Y; ]# F6 p; s3 \7 u' c: k
  111.             // 放入待兑现的奖金池# v) l" V& [6 j) F
  112.             lockedAmts += amt;
    % {7 t9 ]7 Y% c8 r  C  C1 s
  113. 5 F7 B! Z+ `" t! V
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    ) N* b! o0 K1 @! P+ g
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    ) l' F$ c+ M1 }
  116.         }- C% t9 ^7 p- x4 `- C

  117. , j7 S( P6 C9 j0 T' z: b7 v
  118.         // 未分完的奖励即为平台收益' J! P2 T+ k3 K3 C( K
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    * K% \) A7 I5 G) s# F/ Z; R2 }
  120.         if (giftAmt > 0) {
    + m; y' q9 E! l. u
  121.             winnerVaults[admin] += giftAmt;
    " s- D2 M3 p0 q2 o' i6 X8 h
  122.         }
    8 H# J3 i! {* E4 U. P# D+ f4 [

  123. 1 g* B2 E. b. V% j( o
  124.         emit Finialize(currRound++, uint256(_country));. t  n" i) d7 e& j' I5 I
  125.     }
    % O, h2 D. m) @- J8 j& I6 M$ C2 w

  126. % V% @0 V! V& I, ^( A8 x
  127.     // 奖金兑现
    ! K- p  `1 W( S( W/ x
  128.     function claimReward() external {$ o0 {4 |' D1 w
  129.         uint256 rewards = winnerVaults[msg.sender];
    0 I* Y. }4 {7 h( a
  130.         require(rewards > 0, "nothing to claim!");
    . P* ~( @$ n" }% N9 s
  131. / n9 D5 k" w  k1 T8 _7 `6 B
  132.         // 玩家领取完奖金置为 0
    7 m( u1 i+ G( J. i
  133.         winnerVaults[msg.sender] = 0;
    2 J& }8 `% E& S5 I1 V
  134.         // 从待兑现奖金池中移除该玩家份额: ?8 d7 T: y0 M8 `9 |- M+ {
  135.         lockedAmts -= rewards;
    8 Q5 \" e! t, f( ~7 M" y) o
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    $ L- r: O0 x8 U4 ~  L8 p) |! b! n
  137.         require(succeed, "claim reward failed!");
    : U1 `: M5 C" S0 R9 l' u; M0 [

  138. & A. n  j: y4 \4 \1 Y
  139.         console.log("rewards:", rewards);
    8 [$ J; y' n7 c  n9 G/ A. |

  140. 7 \5 g3 @8 W: W& G
  141.         emit ClaimReward(msg.sender, rewards);
    4 f& s0 N' e5 b
  142.     }
    / o: b: |0 g9 c- H, n  v$ z

  143. 8 h0 v  V' _2 N7 [1 K1 e* ~% V
  144.     // 获取奖池金额) n- u& i" A) C/ H
  145.     function getVaultBalance() public view returns(uint256 bal) {6 {. X8 s( w) z/ J
  146.         bal = address(this).balance;# i) b! e+ {9 C1 I# }  E  {
  147.     }* z; H) V. Z  b. u9 N( u
  148. # X1 q: r- E6 w9 o7 k
  149.     // 获取当期下注当前球队的人数$ A5 z! K1 Z1 D2 z& F$ s6 Y
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    5 ^) r; k' q) o/ u6 c
  151.         return countryToPlayers[_round][_country].length;
    * o. ^& O0 |. b0 m4 w/ m
  152.     }
    ! g. a2 \2 L% N
  153. # z( A) h+ ?6 l) c/ m4 ~+ ^
  154.     // 获取当前玩家当期押注份额
      i2 m( i/ J7 M6 e$ f
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {' A* H2 x) t1 D' \5 D/ ]
  156.         return players[_round][_player].counts[_country];
    2 P: E3 r) z! T$ b7 Y0 U
  157.     }
    " i# J4 E" m' L& p: p& @
  158. }
复制代码
' e* p& a( {! T' C, q4 a5 H0 e

+ J7 O4 n: r; a7 O# _/ u( Q6 `- Q; l% v  ^# K+ Q( K# I8 a
- i  a: [' }# b/ o  j
' e0 g' v5 [- f0 J( }( j
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4