Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
257 0 0
业务需求4 ~2 c) x# K' R; D% g3 f1 `9 l
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    ; U, t* |& h- Q' L/ i2 P8 W
8 M4 t8 Q, T: Y' W& J4 z& X
' A2 n7 F2 ~9 B2 T) {' k

; T+ g9 f1 @# Z

  1. 2 ^$ Z* ?' r. T+ K+ u' L6 {) m
  2. // SPDX-License-Identifier: GPL-3.0
    + j# t) k  l- h* X  q
  3. 5 ~/ V: M5 n% V' W& C' l' }+ M4 z
  4. pragma solidity >=0.7.0 <0.9.0;
    9 v6 j" m: m( V" Y

  5. 7 O7 f* T" s+ @4 n
  6. import "hardhat/console.sol";! D; u+ N5 U" O$ m# h. h0 ^" ^8 q

  7.   G) B& T' a: Y$ R: S9 B1 K
  8. contract WorldCup {  `8 O4 Y' \+ p
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队7 ^3 k. v- t( ~0 ?& M
  10.     // 2. 核心方法:下注、开奖、兑现/ S# x% B+ F6 Q' D* k% @
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队; J. A9 M, C- y( {# ~* J

  12. " t4 x7 N9 }( Y$ L$ }# l
  13.     // 管理员
    5 X8 u# N1 m, [- d& F) V
  14.     address public admin;% U9 \" o$ y0 ^0 @0 L7 R4 z0 X+ [
  15.     // 第几期5 C9 r+ w$ A: d1 `3 Q* w  _
  16.     uint8 public currRound;; X  Q7 y( c7 R6 ^9 V6 B- {
  17. 1 e3 p2 _+ Z7 m& R0 [
  18.     // 参赛球队( Q+ V5 b. ]. x+ ?9 s/ f
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    & j! W  r6 k" v8 }* y6 q6 w
  20.     // 期数 => 玩家
    % n+ ]: v: Q" k/ R6 a4 \  Z9 E
  21.     mapping(uint8 => mapping(address => Player)) players;% e! N+ A* z6 l
  22.     // 期数 => 投注各球队的玩家
    . t4 I: a1 K, \$ g' _
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
    $ ^* R4 }) {3 Z- S) q
  24.     // 玩家对应赢取的奖金
    " [: G4 S( s- r' u! M
  25.     mapping(address => uint256) public winnerVaults;
    2 v3 r3 D' A  d  r2 C/ c' ~9 D

  26. 4 m' h& n5 S. [; y7 c" s5 R- k
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变0 b$ N0 E. Z# @9 ~
  28.     uint256 public immutable deadline;
    6 q8 r+ |" \6 J
  29.     // 所有玩家待兑现的奖金
    ( P0 x; s9 }: i  o8 l1 b
  30.     uint256 public lockedAmts;( C9 f* \9 M: \; R

  31. 5 e9 G6 C$ O* R8 ~" J2 [. S
  32.     enum Country {
    5 |8 p+ ^  V* G) Z% x# X3 w
  33.         GERMANY,% P; x$ d0 ^1 n9 ?$ X/ q
  34.         FRANCH,
    0 V1 F+ Q$ a* {+ o/ w. l( v0 F
  35.         CHINA,1 L# V# z9 X! [& l: F% e) W
  36.         BRAZIL,
    . l/ W. d0 ~. d5 E/ J
  37.         KOREA
      l( r& ?2 w" |2 e: v3 p# `
  38.     }
    3 F6 [) u8 @! @! j* k# }
  39. " M# ?9 |% y0 H7 K; O' a3 o  H$ K
  40.     event Play(uint8 _currRound, address _player, Country _country);- m7 n; o4 y8 A0 B4 g
  41.     event Finialize(uint8 _currRound, uint256 _country);
    ; u  p  Z" F# I) ^! g) t. T
  42.     event ClaimReward(address _claimer, uint256 _amt);: o) R# K6 @6 n: p
  43. 4 M3 \1 |0 U6 D+ d# a: W
  44.     // 验证管理员身份
    # T7 K' O# i6 {/ ?# M, T' F
  45.     modifier onlyAdmin {
    , q& ^! |: \' k, N, G' v
  46.         require(msg.sender == admin, "not authorized!");
    / G1 x/ \# t6 V6 g& x" ~9 m% ?
  47.         _;% e) {& e+ X/ G/ z+ ?" I8 k# V7 f
  48.     }' y' d* ]& s% Z, y# v" A

  49. 1 H* I& L4 D9 |# P8 Z) s; Q! `0 ^
  50.     // 玩家投注信息2 L# L" W1 n) B
  51.     struct Player {# S0 Q7 o/ J& Q. J* ^9 }! K  F, B8 m
  52.         // 是否开奖1 x! q( f! k4 _- [6 x
  53.         bool isSet;
    6 M+ b, q8 l3 r9 M9 Z. W
  54.         // 投注的球队份额" b0 G+ [4 A3 p6 L0 @; F
  55.         mapping(Country => uint256) counts;$ p/ N0 g5 x. \% D% P' E/ Y
  56.     }
      J$ p8 V: R& F$ d$ i7 g5 s2 ]0 i4 Y) B
  57. : P7 z, J4 L2 h0 j+ K* }2 K
  58.     constructor(uint256 _deadline) {
    ' h# x# b8 m/ {
  59.         admin = msg.sender;
    3 ~! U2 t" s7 e5 o7 C, O; h  }+ i  h
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");* U0 Z9 a6 c+ w$ i0 }5 b7 Z
  61.         deadline = _deadline;8 \; i& h5 s9 F" _* U/ o; l/ L
  62.     }
    ( T& n$ X' F5 u1 e
  63. * |- L/ u: O4 e8 R" Z
  64.     // 下注过程8 h  L) @5 Z# s9 T
  65.     function play(Country _selected) payable external {' m- P, T- @- I! E, h- s
  66.         // 参数校验" P# ^, r# y7 X4 E7 j# F
  67.         require(msg.value == 1 gwei, "invalid funds provided!");/ j: ^+ S+ v. L: d  f- |( r( X
  68. 2 n. P- p8 J" f8 Z! T) N
  69.         require(block.timestamp < deadline, "it's all over!");
    . e2 i5 m) e; Y% i2 d
  70. 6 c9 ?) q$ M- y
  71.         // 更新 countryToPlayers$ T  D, ?5 n% d6 T; `& o" @+ j
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
    & ], z$ ?) }- B" x6 P
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    9 |$ v5 a6 P5 X1 x8 `/ }# o
  74.         Player storage player = players[currRound][msg.sender];
    4 ]6 |: j% @+ r( B0 ^4 ^1 p
  75.         // player.isSet = false;1 c0 k" \$ p/ K' Y0 N
  76.         player.counts[_selected] += 1;
    / y( @  R, i0 m. B

  77. 0 |9 H1 C3 T8 X2 T8 R
  78.         emit Play(currRound, msg.sender, _selected);& Z9 g! d! C9 Y
  79.     }0 C# F9 b2 J# G6 |& ^
  80. ! R7 g  {7 t" T+ W
  81.     // 开奖过程& N+ H" t2 O6 `6 Q8 f: W# M
  82.     function finialize(Country _country) onlyAdmin external {! w8 s+ f* @' z% z3 M3 S
  83.         // 找到 winners. x) v! V- W8 E9 v
  84.         address[] memory winners = countryToPlayers[currRound][_country];( v6 Q) o/ i+ E' k4 x
  85.         // 分发给所有压中玩家的实际奖金3 g/ X7 @+ x! \" o' R
  86.         uint256 distributeAmt;
    # |0 G/ p. r; _* j2 ]3 O: K
  87. ' U" G2 O( r6 ?, B' ~$ G2 ^
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    , }: W  [& @$ {# M( [  {
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;
    3 r3 M5 b1 E7 i0 ?9 W- z- E1 D
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    6 c- K( G+ K8 w; g- U$ O
  91. . F1 X/ x) K4 O
  92.         for (uint i = 0; i < winners.length; i++) {
    6 I2 A: f& b- p, y( t( {  ?, x9 z
  93.             address currWinner = winners[i];6 _- t4 a" s) E0 `# I, c& v  u9 M/ c2 l' S

  94. 0 \, `6 l5 q; l( R1 Q! ?6 s
  95.             // 获取每个地址应该得到的份额
    7 l% T. P( h2 x: x
  96.             Player storage winner = players[currRound][currWinner];6 N* ^3 g8 z) Q$ c
  97.             if (winner.isSet) {/ U6 L0 l& Y# B4 N2 V4 ]
  98.                 console.log("this winner has been set already, will be skipped!");
    6 L1 v3 P% r& a5 T. L4 {
  99.                 continue;5 f+ F; B6 h$ \
  100.             }! j; G+ Q4 |) o% F) o

  101. 6 E' b# h( [* o1 L0 ]2 s
  102.             winner.isSet = true;, x: i0 Z( D! c0 w3 k8 W
  103.             // 玩家购买的份额
    6 B: ~* C  i" o1 O8 q5 J9 ~6 F( `
  104.             uint currCounts = winner.counts[_country];
    7 X( ^6 ]$ [' e2 `

  105. * ]. T* u8 B2 x/ C* r
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额, F3 @. y0 a) o+ t
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;3 R2 _$ j' n3 _* I
  108.             // 玩家对应赢取的奖金. y4 s( S+ T9 f1 f2 K0 U) P
  109.             winnerVaults[currWinner] += amt;
    0 \5 N$ Z9 F% b% x/ C
  110.             distributeAmt += amt;# V: N! m) s: D7 N! T& J
  111.             // 放入待兑现的奖金池$ y- T5 c8 X6 J  _8 k0 ^! B( O
  112.             lockedAmts += amt;( M/ f& P9 V: D" y% _, Y
  113. 7 G' R/ n. [) Y- ~+ _
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    / @, k, l" \& `9 A, ~+ Q
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);, S5 Z! c2 _' `0 f. V" w' V4 O
  116.         }
    ' _0 A& f* D- t. R" `' ]& s$ y

  117. * [8 B: R( F* [
  118.         // 未分完的奖励即为平台收益
    $ L5 M$ U1 N+ m' _0 i& q
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    4 Z: f9 O; V! p1 q2 C1 E7 K
  120.         if (giftAmt > 0) {5 B3 S& Q/ @, u) B3 I+ m6 L3 s7 m; k
  121.             winnerVaults[admin] += giftAmt;
    ' F0 Q3 a3 {8 N) E2 J
  122.         }9 V7 z1 I' G- H3 w) m

  123. $ L5 z: w& U# L7 p
  124.         emit Finialize(currRound++, uint256(_country));! e/ {( Z% n5 J' C
  125.     }: W$ t* q7 i! t  E) Q1 n
  126. 1 M  @2 r2 m# B) `3 o, C" a
  127.     // 奖金兑现) s& w5 N) \- j4 H2 o* @0 m- f
  128.     function claimReward() external {
    ) c3 m. m% ^, X- F- Y% K, u
  129.         uint256 rewards = winnerVaults[msg.sender];
    2 T' f4 s: {5 g2 j5 ^4 c5 k
  130.         require(rewards > 0, "nothing to claim!");! v# B2 u9 u# z( C& Z) [" J

  131. - G, x* g# i0 v1 K
  132.         // 玩家领取完奖金置为 0
    2 x5 K! F+ \! [% d
  133.         winnerVaults[msg.sender] = 0;
    % }5 E1 b* B" L9 c7 }
  134.         // 从待兑现奖金池中移除该玩家份额" a# v+ {' [9 ~; i* c5 }. t
  135.         lockedAmts -= rewards;6 z5 R% r2 G/ `$ G: p; Z7 N
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    2 T. v+ E1 z$ c
  137.         require(succeed, "claim reward failed!");+ ~, k9 q3 q6 K, p
  138. $ F3 U2 r1 H( |5 w" V& {/ l
  139.         console.log("rewards:", rewards);
    . _7 Z" I# k; P4 y  W+ Q

  140. * [3 r. v& f" y" ~& O. B( d; O
  141.         emit ClaimReward(msg.sender, rewards);
    ( l# D( y  k- |1 k3 ^- i
  142.     }4 [/ ?- {! b2 l4 g. z6 Q( {* ]

  143. - [# P9 u# o, r. j; Z7 e) y5 v
  144.     // 获取奖池金额
    7 {' x( K. y9 s5 m& `
  145.     function getVaultBalance() public view returns(uint256 bal) {
    7 K7 A% N3 q! V' ~' J+ I) ^! ]  O
  146.         bal = address(this).balance;
    7 e' t) x, O* g% g8 y1 b1 D3 l
  147.     }
    , ?8 X$ e& B( `; l- d

  148. ) A7 C6 u  h' K  h. d( f; @
  149.     // 获取当期下注当前球队的人数) A% o* O1 }6 y4 e: Q+ G0 E* G
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {! [! q+ b9 Q0 O! E$ ~& b
  151.         return countryToPlayers[_round][_country].length;
    4 Q8 b% @! Z  D8 i; O
  152.     }9 ]* d) _! ?+ b

  153. . w( J# p  H; `9 x
  154.     // 获取当前玩家当期押注份额2 E4 B" W: E! ?, X- G! _, V
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {
      g5 W/ z$ {8 D% x! T1 m1 q- L0 b9 a
  156.         return players[_round][_player].counts[_country];
    ( |7 `" U9 n0 `3 k0 V, z
  157.     }
    + P: a5 V) }; L" v% W& }4 Z% J& u1 O
  158. }
复制代码

, X& |' k2 g8 _) e% w; _4 l" }7 H# z# l) Z2 u

+ I  [1 p& N- g' R
& j2 I3 O8 Y/ x, s. X/ e* H5 h8 m8 m$ Q" Y/ D9 B" t. y' m
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4