Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
330 0 0
业务需求
, D4 `7 X; X' |8 S: o: X( ~
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    , K0 ?( C: @& f+ g, `4 P( o% T& B% P& N
, m7 c0 z) }% C: u; o
6 h! N- D' X0 v2 [$ l" q* n

" ~+ E# p% e; a  a) p
  1. / ~0 H! d/ J% Y* B% ]" `4 ^' d# N
  2. // SPDX-License-Identifier: GPL-3.0
    + ?8 K  B- M0 M% l0 u
  3. 2 q/ T; U3 L. j. E0 _; u9 M7 }
  4. pragma solidity >=0.7.0 <0.9.0;" m2 d3 ]( W4 J6 r( U
  5. 1 z$ H- v& C5 z! g# `- v
  6. import "hardhat/console.sol";8 J' C$ D7 S$ I3 |* W; o3 h
  7.   V, L; h2 @1 o' J3 g) i
  8. contract WorldCup {/ j) j  Q" X/ E% e' G
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队
    4 V3 _% Q, n2 S0 Z
  10.     // 2. 核心方法:下注、开奖、兑现
    2 O( w5 k0 g& y" z+ c) d( ]( `: P
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    + ^' f" ?5 J' b% \! ?
  12. 3 x8 v$ f/ B' M
  13.     // 管理员4 g' ?  I. u& r
  14.     address public admin;
    6 Z; W1 t  o/ a9 L+ {  }, K
  15.     // 第几期" e7 o5 Z- n5 s' E* U
  16.     uint8 public currRound;0 f2 o# z6 @) b$ L! }/ J
  17. & H' N! ?4 d: N7 F2 c
  18.     // 参赛球队, E( \/ W7 R, Z, m6 l3 e3 }4 n8 o
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    5 @" q$ n$ W" s: A6 S4 R" U1 x) l  q
  20.     // 期数 => 玩家2 k/ f% k* U" H7 Z9 ?
  21.     mapping(uint8 => mapping(address => Player)) players;9 X& U- G' F: Y0 N
  22.     // 期数 => 投注各球队的玩家
    / L& d: x' E  h0 c6 h
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;+ x: {( g) s- X" J$ c$ P7 c
  24.     // 玩家对应赢取的奖金
    " E- d) Z' c6 V& a( _+ [
  25.     mapping(address => uint256) public winnerVaults;
    6 l( y* k0 k4 s% ^; l2 H4 I
  26. 0 V3 }: U+ x# ^, I% E5 m2 k
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变5 [/ r$ d$ m. ~
  28.     uint256 public immutable deadline;
    1 U3 z" |/ j0 E; P" r. U
  29.     // 所有玩家待兑现的奖金8 _/ F! v  h! ^2 N
  30.     uint256 public lockedAmts;
    8 ~# l& L- ]  }. M* Z5 A

  31. 3 @" M/ X: e! o8 J4 T; `2 s8 u
  32.     enum Country {
    / C* t. m( q% G% O
  33.         GERMANY,
    2 y& U# A- h% B0 B2 U. Q. g
  34.         FRANCH,
    9 _: H# x6 T; R1 D- q* U
  35.         CHINA,
    9 u' m( `5 D) v
  36.         BRAZIL,
    4 t1 Q% y8 n9 D
  37.         KOREA
    " N: `/ P; @: O& J: R4 X: p
  38.     }7 A3 i2 M4 G" l. L
  39. $ k7 e# c: O$ U+ ?
  40.     event Play(uint8 _currRound, address _player, Country _country);8 g# s0 g# R  E. d! S3 C# C" p* Q
  41.     event Finialize(uint8 _currRound, uint256 _country);
    4 E6 {: |( k* t( K1 p" h& h
  42.     event ClaimReward(address _claimer, uint256 _amt);/ w+ g6 A; |4 e! \

  43. 9 _2 F8 p! ^/ @$ |1 W# `
  44.     // 验证管理员身份8 e" c3 I+ G! @9 m
  45.     modifier onlyAdmin {# h% d* a- s: u
  46.         require(msg.sender == admin, "not authorized!");
    4 V; M/ y$ c( a" U3 g- L$ @5 [8 w
  47.         _;$ P4 @% o& e0 E7 b% ]" _
  48.     }
    ; a5 q; v; _1 c9 C
  49. / F0 u& F2 J; G" [5 c
  50.     // 玩家投注信息3 w/ W' z: k: f$ p8 y. M! C
  51.     struct Player {
    " d/ w) U7 ^+ T5 l
  52.         // 是否开奖* r1 Z# ^" S( Z+ i* J+ `6 Z6 T9 |
  53.         bool isSet;
    , Y- G" P7 ~5 }- T) k
  54.         // 投注的球队份额; ~+ m6 P4 g1 K0 W* r
  55.         mapping(Country => uint256) counts;
    5 ^( j2 r4 Z: s1 k+ Z
  56.     }  U; i4 H! D, W- c8 s& H
  57. / @* m1 U* Q. k, H* h9 D9 K
  58.     constructor(uint256 _deadline) {  c* x& t0 S4 ]# P4 ?  J3 |
  59.         admin = msg.sender;/ o' U# Y- U$ c% X3 u/ c
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");* C2 o. I9 F. m$ r
  61.         deadline = _deadline;  i& F5 g1 t& j, L
  62.     }
    1 E# \5 z1 O. t

  63. ; i  j* K: l. E, Z% n
  64.     // 下注过程
    7 @0 V7 G. D9 l! X  @% B( p$ I
  65.     function play(Country _selected) payable external {
    6 \3 k( p5 v, @* e" x/ G: z
  66.         // 参数校验
    - O6 @$ a0 C: Q% @
  67.         require(msg.value == 1 gwei, "invalid funds provided!");
    " `) s* ]4 o5 G# f4 Q) {( m
  68. + i2 l, G7 F+ a" q
  69.         require(block.timestamp < deadline, "it's all over!");/ {7 u" B. R. V% W

  70. ) w, ]. v& J2 b7 R% F) v$ n
  71.         // 更新 countryToPlayers- j) }& ?- W' Z5 E. z; G
  72.         countryToPlayers[currRound][_selected].push(msg.sender);# R6 s6 T0 G: ^- q
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    ( I0 @- c5 z+ K" P9 u0 z+ W
  74.         Player storage player = players[currRound][msg.sender];2 X3 y) i6 R1 n( H# l4 ?' }" i
  75.         // player.isSet = false;
    / k+ \8 [6 }3 b
  76.         player.counts[_selected] += 1;7 o* U1 @4 @: P8 [+ W$ i

  77. - J8 R" p) x" b. p3 I8 V
  78.         emit Play(currRound, msg.sender, _selected);+ U3 ^" O* V+ z& G
  79.     }/ I) p8 W% c3 q+ J

  80. 1 g* e! p7 e4 T1 g" n
  81.     // 开奖过程- A& {* p4 c7 O4 f& w0 e' c; S
  82.     function finialize(Country _country) onlyAdmin external {
    , c. j6 h( ]& r" T% _5 C0 R
  83.         // 找到 winners- p% P. v0 g# R# J* Z" z& b' X# S8 Q
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    / U9 H7 T0 v9 X
  85.         // 分发给所有压中玩家的实际奖金
    $ A8 a* E$ o( Y4 k
  86.         uint256 distributeAmt;3 J/ y- i$ s) _+ A- R4 \
  87. 4 B) M4 J; E( Q% u: }
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)0 v; j1 E" j* t+ N  p2 m
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;
    . `* V( @: E9 G. W
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);
    4 z3 ~, ]6 R) L3 j8 b

  91. # J0 O# Q$ P- q4 @& o/ w
  92.         for (uint i = 0; i < winners.length; i++) {
    7 b! J9 ~; \5 ~+ Q  i: h1 p9 D
  93.             address currWinner = winners[i];$ Y+ H5 \: D9 z$ i/ w4 f

  94. 4 B$ N: X, Z1 F9 ?- }+ h
  95.             // 获取每个地址应该得到的份额
    : r6 ^4 x( ^# y# W; C
  96.             Player storage winner = players[currRound][currWinner];  F" s) `1 J4 G8 g: K. `
  97.             if (winner.isSet) {
    6 `, \+ L2 {4 L  v, D4 C
  98.                 console.log("this winner has been set already, will be skipped!");
    * C4 D0 M3 Y6 n) A7 N
  99.                 continue;
    & y& N# a# ~; S+ u8 v1 d9 j6 }
  100.             }" ?- B+ f; r4 W* F7 _
  101. # }+ o; ^# T" y3 ^/ X. b  A& m: G: v
  102.             winner.isSet = true;
    3 r4 c( _) {1 @: L* ~
  103.             // 玩家购买的份额
    ) D$ k" K8 P5 }3 }0 a
  104.             uint currCounts = winner.counts[_country];1 g; N- G4 u4 k" |0 Q! u5 E
  105. 2 E( s4 _; f# ^' {$ e& D+ E0 H
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    - t. ^& B+ @* w$ A- M- f3 d9 g' a
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;, U! p1 N7 n0 p% C* h
  108.             // 玩家对应赢取的奖金
    6 i+ T+ s5 U! Z- c4 g8 B
  109.             winnerVaults[currWinner] += amt;
    ) Y7 q, G' r$ N
  110.             distributeAmt += amt;' W0 ~+ ~5 `7 X0 D1 @7 k/ j0 T
  111.             // 放入待兑现的奖金池8 x8 _. D& |/ F. T$ x  O2 N
  112.             lockedAmts += amt;
    % ^, R% r: r$ |# P

  113. 1 e8 d( s, W7 J7 H4 J5 D6 y: B9 `
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);) f  t: d6 j8 j8 k
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    9 ^8 b, X/ G( o  r& u0 t6 S
  116.         }
    % o5 o( m& Y6 N, }
  117. # |6 S, n- P! e
  118.         // 未分完的奖励即为平台收益2 o4 L8 `) g8 O
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    - G& m2 E, @5 Q- k, e
  120.         if (giftAmt > 0) {: h9 j  S" a( L$ t
  121.             winnerVaults[admin] += giftAmt;1 h# X5 }4 B2 S
  122.         }
    $ P1 q, W( r* a5 T9 ?

  123. 7 x6 l7 F2 W! ?- C1 c
  124.         emit Finialize(currRound++, uint256(_country));
    & x+ ~; F( N/ }' m
  125.     }
    6 z# N; p; ^2 }; X

  126. , n! E0 b! K. d
  127.     // 奖金兑现- P+ Z  j! j; u( y6 i+ f
  128.     function claimReward() external {
    8 v, `$ E) U) I3 R+ L* n' }
  129.         uint256 rewards = winnerVaults[msg.sender];
    : D2 H# R# ~# ~; c' `
  130.         require(rewards > 0, "nothing to claim!");5 }% q5 [/ j0 j* A2 c& Q0 d1 ?

  131. " z+ n1 V8 f7 l" N3 x
  132.         // 玩家领取完奖金置为 0
    7 W7 Y5 }; F! }$ z
  133.         winnerVaults[msg.sender] = 0;
    ( D$ F- o& M9 o7 K$ f3 Q
  134.         // 从待兑现奖金池中移除该玩家份额3 {5 Y# y0 E  O0 F' H+ Z% G
  135.         lockedAmts -= rewards;) u% y; Z# C. f: M3 G7 K/ l) g3 q  P/ c
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");! x  R% y7 S# ?. Q
  137.         require(succeed, "claim reward failed!");3 E5 X4 k# B+ }: U# c) d
  138. , J. t4 M7 L; Q# e" b; L  |
  139.         console.log("rewards:", rewards);
    ' \. p' m. j/ D) `+ Q+ U5 \
  140. 3 e$ m+ B+ u0 m1 {4 x( ^7 v
  141.         emit ClaimReward(msg.sender, rewards);8 D+ [/ f  z6 R/ `
  142.     }5 J$ d# A! g) Z) t1 O4 s% W  |, B3 B

  143. 3 ?- q: m1 M) p' C& F- M
  144.     // 获取奖池金额
    - k. U, a6 Y4 Z5 c, H8 ^4 A
  145.     function getVaultBalance() public view returns(uint256 bal) {
    3 v, p  ^0 D* `/ L! [
  146.         bal = address(this).balance;
    ! E9 Y6 J3 u3 Y4 h3 f. L
  147.     }1 D3 N  y+ S* ^* ^- ~" B4 t% E

  148. + y9 d5 S7 T+ \
  149.     // 获取当期下注当前球队的人数7 D2 U  E: \! A1 w- S  ~* a# t
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
      ~. `; A9 s4 j  P
  151.         return countryToPlayers[_round][_country].length;* F: Q5 v  L/ F: v. t
  152.     }  g) ]6 A( ?9 k/ q- M8 p% R
  153. 5 l% C1 e( [0 T# \) r% B
  154.     // 获取当前玩家当期押注份额7 d; z  I' Y; P2 X# N' h
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {  j" y6 b# Z) w$ a3 g
  156.         return players[_round][_player].counts[_country];
    2 w* t+ [$ s5 M1 S7 l/ r
  157.     }
    . T- y, y$ c) w1 `3 v
  158. }
复制代码

) C' _2 O" g- K& g6 M' u6 E. ]. ^+ B$ _$ F. y1 e0 z
9 f( E4 h7 P6 B- s( p5 y! k
; L1 {9 I8 {! i, P2 x
- f/ b; Y- J0 F/ @3 A+ Y
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4