Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
331 0 0
业务需求  \& X' K5 |7 ^5 [, t" J4 I( S
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始# ^$ r4 L3 V# \+ Q. \

2 ~( p' B) l# N  y
0 Z; G+ l9 M- `. B. I4 \
2 u/ W1 L' _# J4 r1 ?. c% U1 P4 r3 j
  1. 4 ^9 W/ j6 Y" D$ i7 H+ J) c  ^# h
  2. // SPDX-License-Identifier: GPL-3.0
    ' p7 R' o# N) D

  3. ' k3 o% O: P- x
  4. pragma solidity >=0.7.0 <0.9.0;4 a7 B7 e1 ?% z+ c( ?! ^/ s1 L
  5. " i' X  a" l6 i6 l0 `! p/ \
  6. import "hardhat/console.sol";
    . h. u4 {' }/ x
  7. , a, s: W* f( y! a# T2 ?6 c2 k
  8. contract WorldCup {
    7 v$ f6 g# @3 h/ j  ?+ F& F! ~# f' _
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队' s, r: w) H- h! O2 e
  10.     // 2. 核心方法:下注、开奖、兑现9 o$ `7 z* O* r* G# Q1 h- A
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队  ]- H, h/ }% \
  12. 3 E% Z7 @+ Y3 r1 B  P* o
  13.     // 管理员( Y/ k; l$ h6 Y. E
  14.     address public admin;8 R7 F; H; I& l' S
  15.     // 第几期
    8 S6 O7 h' O, i' D( n  A: N
  16.     uint8 public currRound;1 U% T4 u8 `$ N, C' v/ _
  17. - x% C8 s6 F% F5 y& `3 J
  18.     // 参赛球队
    5 V7 ~* C3 r1 n8 y/ F
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    2 k; b2 a( r+ ~4 S7 Z
  20.     // 期数 => 玩家2 u# U7 u, v+ K% L' q- d" s
  21.     mapping(uint8 => mapping(address => Player)) players;
    # y( w6 x8 _5 O9 b7 `1 r- v  p
  22.     // 期数 => 投注各球队的玩家2 H) R# q% [+ s3 i
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
    ! _* u* a; ?: L- X4 c; c% \
  24.     // 玩家对应赢取的奖金
    & C0 c) h- u5 Y+ L- e
  25.     mapping(address => uint256) public winnerVaults;6 [2 H& {3 `) q  p; j- o: A/ V' y, e
  26. . J5 O4 u8 }2 G- r
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变/ V8 M/ _" ^- G7 H6 y- Y. N5 v
  28.     uint256 public immutable deadline;
    & c: s  q- b! u5 z' P
  29.     // 所有玩家待兑现的奖金( L0 c5 S+ r7 ]' G7 B2 _
  30.     uint256 public lockedAmts;! r. @& W* r- I6 s+ e

  31. 0 s9 O" ^/ E" R, }- k6 K
  32.     enum Country {2 P) a( }$ X7 e
  33.         GERMANY,
    0 {0 p" {8 p+ F0 M0 Q. e
  34.         FRANCH,. L/ ~7 U9 @# T
  35.         CHINA,6 K. H! _) m8 |. }  b
  36.         BRAZIL,& E' h* d) K* H
  37.         KOREA, Q3 c( L7 V4 l" `$ z* D
  38.     }) D, Z) ]4 j' l
  39. 9 A4 T/ j+ L. |7 d
  40.     event Play(uint8 _currRound, address _player, Country _country);; O" s% Y$ _9 S
  41.     event Finialize(uint8 _currRound, uint256 _country);
    " u0 E& D& V0 F, C
  42.     event ClaimReward(address _claimer, uint256 _amt);/ d5 e0 R6 ?7 t8 ^- f
  43. 2 |8 F& N9 {) @/ G4 W
  44.     // 验证管理员身份
    9 J, ?- T5 m4 e
  45.     modifier onlyAdmin {
    ' W  _3 E3 ~+ P( C$ I3 _, \8 P. X
  46.         require(msg.sender == admin, "not authorized!");
    ' i8 Q0 P- j8 I8 Z! w5 _
  47.         _;
    ' W/ P: T, s8 N8 M1 N! K" x
  48.     }
    : Q+ E+ `* P# T/ c* n4 v$ m, f* h; S
  49. ; Q( Y7 n* I6 {2 a) G
  50.     // 玩家投注信息
    5 E1 `, q  J( m
  51.     struct Player {
    & v7 C7 ~; R6 [; [# z+ B/ E
  52.         // 是否开奖
      X. @; ~1 J5 K
  53.         bool isSet;# v( i6 S; b+ P
  54.         // 投注的球队份额3 n" K- q' }- a7 F3 d: ]
  55.         mapping(Country => uint256) counts;
    ( Y& B; l) L4 K$ B' H: w& m
  56.     }& H7 K6 P$ T9 n: Y

  57. $ D# N6 R. n* k4 P  u! e( K% q+ N
  58.     constructor(uint256 _deadline) {
    " U" V2 ]1 K2 v4 R' P/ \1 L
  59.         admin = msg.sender;" ?  F. y1 c7 F& D$ D
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");& T( W4 o4 H% i
  61.         deadline = _deadline;
    * Z. k) p/ e# v: \6 n9 J1 i
  62.     }/ F* b; D5 R: l. H3 p
  63. 6 i* j1 k- f3 k  s3 ]
  64.     // 下注过程+ c8 ?- L, b8 H8 u* m7 H6 C
  65.     function play(Country _selected) payable external {
    ) x. q1 ~* u2 n
  66.         // 参数校验$ \( p9 Q8 C  \7 u& X
  67.         require(msg.value == 1 gwei, "invalid funds provided!");' R- C1 f6 h. `% k* t

  68. $ O( Z$ \, v$ D- L7 A4 _
  69.         require(block.timestamp < deadline, "it's all over!");! Q! Z3 Y/ U5 g0 ]- c: V

  70. 4 ]4 L- u7 f0 ~, ], C' f9 J9 l
  71.         // 更新 countryToPlayers+ |0 b; Q" [# h
  72.         countryToPlayers[currRound][_selected].push(msg.sender);2 i, v, @' v- ]/ Y
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    & t8 s0 G$ W" p7 \8 o3 q& I9 }2 Q
  74.         Player storage player = players[currRound][msg.sender];) Y1 |, Z5 f4 u) f" I, M
  75.         // player.isSet = false;) n5 {; ~$ s: _" Q' a
  76.         player.counts[_selected] += 1;
    # l5 H" J& v& k' R2 W3 \
  77. 7 s0 ~( `( t2 m. \8 n" I
  78.         emit Play(currRound, msg.sender, _selected);
    2 z8 ~6 T; j5 A3 G8 m6 I8 u
  79.     }* Y  c# ]! Q, v% Y
  80. 7 V# i( ^7 C: f5 Z6 A- }, z8 [! F# ~
  81.     // 开奖过程
    6 J  B) e/ q0 K- |4 z
  82.     function finialize(Country _country) onlyAdmin external {1 U3 N0 g/ o, p$ n' S
  83.         // 找到 winners$ B) H. r$ R4 K2 L2 ?7 i
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    9 M2 L1 |1 F$ {5 z7 B
  85.         // 分发给所有压中玩家的实际奖金
    2 ?8 U. `2 I: O) H4 m) C8 o+ u" }
  86.         uint256 distributeAmt;
    5 D5 R6 S6 ?6 U& J/ h" z

  87.   O3 K- r( P& K( k) N) H
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    / M1 V9 E# A' O- H* I  U
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;
    ; y# l( L4 f9 c0 B5 ~
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);0 g( g$ E2 x1 ^
  91. % y- D5 v) Z7 R& C& B8 B2 u. [
  92.         for (uint i = 0; i < winners.length; i++) {# l+ D' y2 [0 S2 a  J5 _1 X0 i$ m
  93.             address currWinner = winners[i];
    / {6 f8 i, b4 s. o$ i

  94. ; x* z! \" I/ M6 J9 I' ^; T7 E
  95.             // 获取每个地址应该得到的份额
    , n7 U( m( P. j$ Z) s- U/ r
  96.             Player storage winner = players[currRound][currWinner];
    ( T2 r4 s. M, F+ N
  97.             if (winner.isSet) {
    # C3 Q& ], R* n! ^
  98.                 console.log("this winner has been set already, will be skipped!");
    # X- P& u! J5 s
  99.                 continue;6 f7 ~' v7 @: }3 ^5 M% V
  100.             }
    2 ^; ^+ A% S. J* J* R
  101. $ X$ \" K' m* e/ Q& n( u1 N3 L
  102.             winner.isSet = true;; ]  t3 w( W- V) _
  103.             // 玩家购买的份额% j9 a0 y) P  p2 b% c; o; H
  104.             uint currCounts = winner.counts[_country];/ o) v3 |& A* E$ Y  ?2 n. d

  105. 3 b- h: D) j- Y" P. L$ O6 A7 @
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    : }/ b( v) C- W) {  E" q4 @# X$ j
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;- S, {% M: i  y: J9 [
  108.             // 玩家对应赢取的奖金: e1 o# b$ U# ^+ K$ @9 p, N7 K$ ^6 z
  109.             winnerVaults[currWinner] += amt;
    9 ?9 _8 f& D: B+ W" `0 P
  110.             distributeAmt += amt;
    5 h4 |6 f) `) j& m2 h, w# y, i
  111.             // 放入待兑现的奖金池) n* x4 g1 r8 [9 w. y+ G, T; z3 S
  112.             lockedAmts += amt;5 e0 a) [) r. X" ?% [

  113. , D! @% k  e8 |9 Y
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);- h8 S  E& E# k1 R
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    0 {, L% }# X: X" F3 v
  116.         }8 L: s, ^" w3 C' x
  117. 6 A2 ]0 f+ h9 |% P, D: K9 R
  118.         // 未分完的奖励即为平台收益* d% P8 ^4 i! h0 `$ ~. e
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    , T  l! |/ c2 d; j+ ]: z! F
  120.         if (giftAmt > 0) {7 ?. V9 ^5 ~( ~3 L& D0 E) A5 t) @
  121.             winnerVaults[admin] += giftAmt;
    4 R8 Y* U2 F0 b+ R; I* B7 W5 }" S- u& A
  122.         }# p  G* B1 `/ ^4 N4 G! ?' U

  123. ' n' k, H. a6 i6 S0 X6 ^+ }
  124.         emit Finialize(currRound++, uint256(_country));- r6 P) F, Q- X3 S; E0 |
  125.     }+ H% \, f9 O' l
  126. 2 i# z% X. }, R9 u
  127.     // 奖金兑现+ y. b1 a, D( {
  128.     function claimReward() external {
      O) h/ c, F7 ]% [! H% V
  129.         uint256 rewards = winnerVaults[msg.sender];
    4 p% I5 r  k1 A& U8 \: X8 Z
  130.         require(rewards > 0, "nothing to claim!");. Y2 C. ?3 ~# C1 \) J8 j

  131. ( C' ]& T8 J0 _% {1 P, V- m& ?, {
  132.         // 玩家领取完奖金置为 0
    # m( m0 {/ A6 s& t
  133.         winnerVaults[msg.sender] = 0;
    4 L7 n. Z& w* Y6 B4 N; c2 X
  134.         // 从待兑现奖金池中移除该玩家份额& O. v( B! Q1 }6 V- l
  135.         lockedAmts -= rewards;3 v: |( w9 j3 `8 p6 ?$ U& h
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    0 a: a) X8 ?& G  ?9 B2 E+ @% ?
  137.         require(succeed, "claim reward failed!");) q4 R) d, h1 P

  138. & n6 j8 F0 |# ^( n2 {8 A
  139.         console.log("rewards:", rewards);' z* q' i5 E/ t* ~

  140. + W, p4 n; O, v4 ?0 f
  141.         emit ClaimReward(msg.sender, rewards);% z" Q* I. `. |$ ]* J7 d- P
  142.     }
    3 X+ n( L8 `- ?% p

  143. % N9 C0 F4 X: P
  144.     // 获取奖池金额9 D$ b2 q% {' e- r7 z9 y
  145.     function getVaultBalance() public view returns(uint256 bal) {
    ; m- q$ S) l, t0 {0 Y9 o
  146.         bal = address(this).balance;
    ! O% \5 G6 o. P% o) P! H/ P- s
  147.     }' n6 T7 O" k, U. U

  148. 5 ~! \9 J: b8 o4 d. e
  149.     // 获取当期下注当前球队的人数6 i& D3 x9 z2 U! _% N* ?9 O) E# Y
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    - }. ?- F  c. V2 J
  151.         return countryToPlayers[_round][_country].length;
    / ]% U2 i" F& c: @: L
  152.     }
    + D' @" E' g7 b8 E. M# ~& q: ]# O

  153. . L% }1 k$ _) S8 e# g% U: ^/ @# X
  154.     // 获取当前玩家当期押注份额' Z# t" c9 l$ x8 x+ `
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {4 N( k' w* u) C
  156.         return players[_round][_player].counts[_country];: G! u& L- w% U+ b9 O( \& `) q  G: R
  157.     }+ I3 e! ]  s6 E. s: u/ E$ q
  158. }
复制代码

) m2 {8 n; U% x: [; i( G' p5 s& O% ^1 b, T8 z8 |
. {8 O2 q/ q/ O1 m: ^/ A% r
5 p0 T. i: \6 F# W& F4 m

/ F, }; x. K/ m; Y2 ]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4