Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
464 0 0
业务需求5 J* Z' D5 L) V; \% J6 {
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    + g8 x# x3 }" N. w* R9 h0 M

$ |# A9 c9 e  `' U" g, Z: U8 k
( J- N5 Q7 [) y$ k; w# _' f! _( e
  1. 0 ?0 r4 [& B% D# Y9 w% ]
  2. // SPDX-License-Identifier: GPL-3.07 o4 r6 D8 X+ e; B, {, @  s: a
  3. ; H- P: C! B$ Y) }- B- @8 D2 }# C
  4. pragma solidity >=0.7.0 <0.9.0;+ g% \4 a0 E8 |" f3 k: Y
  5. " A. o& l9 C: B6 X2 y6 t
  6. import "hardhat/console.sol";; v" I1 Y  G; Q; I. j9 |% i/ J

  7. , L* m/ [9 H. f
  8. contract WorldCup {* Y; h- C; ?' X
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队  |$ I  ]7 ?! N& r* B- B6 G" v0 r
  10.     // 2. 核心方法:下注、开奖、兑现
    1 X; u, y6 v  t. W) N2 i+ q
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    0 R- {0 A3 A) p( ?" l" r+ c1 u

  12. 0 J2 f2 b0 K; L
  13.     // 管理员- P4 K) i. q9 p9 A! T9 u( x
  14.     address public admin;, o+ D( b9 w+ q  \. Y
  15.     // 第几期
    5 }( X5 F: r: M( B
  16.     uint8 public currRound;
    7 h1 t1 F- w- p& A- y
  17. / V$ @5 T$ b) d& Q# P, Y
  18.     // 参赛球队7 S( q: A! c% J( _) i- O! U& e
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];
    8 W  {5 i9 P' p( _) ^3 I9 d5 Y
  20.     // 期数 => 玩家
    ' @6 Q, o$ S: |* A
  21.     mapping(uint8 => mapping(address => Player)) players;
    ' H6 n9 S2 L, X
  22.     // 期数 => 投注各球队的玩家
    ) B- F& }$ m; ]. ]: E
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
    1 K) ]' z2 N  Q- `: e) {
  24.     // 玩家对应赢取的奖金
    3 O) ?! d, v& G# _
  25.     mapping(address => uint256) public winnerVaults;7 ?7 n8 O, d9 P2 X  v
  26. 3 s9 U6 _, Y4 }. D7 k5 l0 x/ T" H
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变% F1 }, g$ U0 B& m1 o
  28.     uint256 public immutable deadline;
    : K7 o% {$ f4 v+ d
  29.     // 所有玩家待兑现的奖金/ s6 N) C# ?2 K% r, c5 S$ J9 D
  30.     uint256 public lockedAmts;5 N) i) M7 P$ `" I: }
  31. : R1 g$ }& N; f; k/ T) L
  32.     enum Country {
      U! j! Z9 ~" W
  33.         GERMANY,
    ; Q) \/ n- H* s7 q4 T7 O  ~, b
  34.         FRANCH,% g% l. v* _4 m) _/ i
  35.         CHINA,
    % f; I$ ^" |! L6 C5 V3 p
  36.         BRAZIL,
    ' z  ^( L1 n3 J: v7 j9 Y$ p! r
  37.         KOREA8 [1 g. M0 W, S
  38.     }7 u$ o- D8 c7 S9 j/ m" @

  39. 8 h( b: \2 f' E9 N
  40.     event Play(uint8 _currRound, address _player, Country _country);, x& J4 z# P$ M
  41.     event Finialize(uint8 _currRound, uint256 _country);# W7 N# W) E9 G& W1 P
  42.     event ClaimReward(address _claimer, uint256 _amt);5 q8 ^/ l6 y; u, m5 d' S

  43. ; t0 u& \; v  g" g
  44.     // 验证管理员身份# m0 @$ W, [& d" a0 R& L7 Q! o
  45.     modifier onlyAdmin {
    " Y$ z( |: w8 l, s6 B! e' T
  46.         require(msg.sender == admin, "not authorized!");9 E6 c: I7 _0 X2 X0 c" n) s* R3 }+ n4 w
  47.         _;1 X9 k1 L+ e! P) v5 p
  48.     }
    6 o# p1 z% d1 @" I  \9 X, E
  49. # X/ A+ J' k( c. q' X' c7 A) t" [
  50.     // 玩家投注信息
    8 Y9 G* M  K! j) a
  51.     struct Player {
    ! y. Q5 V- F, Z1 x4 ~
  52.         // 是否开奖( t7 S4 O, i$ m1 L0 O% ?$ j9 [
  53.         bool isSet;
    % c$ W# I. Q0 n2 H' _4 c; n
  54.         // 投注的球队份额
    # ~2 B2 y' q4 t) s
  55.         mapping(Country => uint256) counts;) W/ {; r$ u+ [9 M
  56.     }1 g- K/ w0 U4 @% ~8 M
  57. 2 [% `0 s% R9 G& V
  58.     constructor(uint256 _deadline) {4 P7 r! w# y/ m4 T' D
  59.         admin = msg.sender;
    / ^, B2 A" t, Z9 B- w2 |2 _# g8 s
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");0 w, V5 c7 ]. Z: b; A
  61.         deadline = _deadline;
    " f5 \2 F& t# `
  62.     }
    : I, p( l# U3 c

  63. & H- b9 i6 ?5 E5 c
  64.     // 下注过程
    % w) b& ?: R6 g& I) F* Z
  65.     function play(Country _selected) payable external {
    , A0 W9 D7 D0 A' Z
  66.         // 参数校验
    ! o" |- W# ~& j8 f
  67.         require(msg.value == 1 gwei, "invalid funds provided!");) }# R2 f; u8 `8 L9 _: U
  68. 1 w! C: D; Z0 l* Y: ^; \& L
  69.         require(block.timestamp < deadline, "it's all over!");9 p' A% \2 r; q4 S0 K. M
  70. * [  m2 N6 e- [" B5 x# l0 R
  71.         // 更新 countryToPlayers/ ^* Y! m$ @% R: J
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
    0 `, |0 |/ k8 J* l* A
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)! V) K/ j1 S4 l' ]2 M3 ~7 z0 F- m
  74.         Player storage player = players[currRound][msg.sender];
    5 u( \& R7 y0 D3 x; ?6 T5 H1 h
  75.         // player.isSet = false;; v/ \/ J# L' v9 ~( c: k0 S
  76.         player.counts[_selected] += 1;
    ! l4 `5 E+ z& f2 \6 S
  77. 2 L! b4 c/ @1 s& B; \1 Y& Q
  78.         emit Play(currRound, msg.sender, _selected);
    3 k. ]1 A! A2 I8 p# K% o" k
  79.     }& n/ h1 F8 m0 m& U* F" S
  80. ; I5 Q: ?: V3 e$ X8 {5 V: {& `6 k
  81.     // 开奖过程8 y7 i  k; ^# A' m+ m# \+ q
  82.     function finialize(Country _country) onlyAdmin external {  }* J! K6 H% k' a4 F& m9 Q
  83.         // 找到 winners4 M' B) }1 V) Q. e& T% Q/ T- w* h
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    9 W8 N" t/ h" G4 O# B) ^
  85.         // 分发给所有压中玩家的实际奖金
    ; V% _' p* v. Y3 E; H8 Z5 T9 }
  86.         uint256 distributeAmt;5 N+ Y. {0 V5 ?6 S) ?. Z6 f
  87. ) y/ F* z0 [  s* y* V, C
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金); j3 Z1 l, O: q0 G7 G7 u, s
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;9 T2 R0 y: P6 }1 U
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);1 G9 v/ d/ x! P

  91.   X7 f* w6 o3 ^/ P' D+ z
  92.         for (uint i = 0; i < winners.length; i++) {& y. B' Q9 r  ]3 n2 U% f- V. o
  93.             address currWinner = winners[i];
    3 Z2 H0 D6 x& p& d4 R2 `

  94. 3 |" A5 e5 x' B: i- `. t
  95.             // 获取每个地址应该得到的份额
    1 t/ V. e/ k/ h8 }: s
  96.             Player storage winner = players[currRound][currWinner];
    * p" y. L0 ^8 d' \( D- B
  97.             if (winner.isSet) {
    $ X( I* u  [  N7 H
  98.                 console.log("this winner has been set already, will be skipped!");% {5 U% N+ Y1 V
  99.                 continue;- |( k# o" `  `& m. U1 u5 a
  100.             }; ~2 M) N" J3 k$ M

  101. # e6 W% G4 K0 ^# ^: @
  102.             winner.isSet = true;
      b( ~5 e9 W: @) _) {# n
  103.             // 玩家购买的份额8 P+ o* ]) O( i# s8 }
  104.             uint currCounts = winner.counts[_country];+ d2 b2 i$ a. B* @

  105. , m. s' K) G  n2 |
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    2 l& R/ }8 R, F1 ~5 F8 F' f
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;0 A/ t" i5 l4 a
  108.             // 玩家对应赢取的奖金* ?7 q9 y! y! j1 C9 O
  109.             winnerVaults[currWinner] += amt;
    & S% n  p2 d: s# K
  110.             distributeAmt += amt;
    4 V$ k9 T: ^' A6 }) }7 z
  111.             // 放入待兑现的奖金池" ?! S, q- u3 ~7 C
  112.             lockedAmts += amt;
    3 d8 q& l$ P+ K- c" a4 N
  113. % X+ [* C8 N. Y1 I2 t
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    6 v4 H2 R5 j' I8 Z2 M; i! @
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    4 B. Z( C/ G6 S+ d7 W
  116.         }
    ! s, M2 x1 u( B, s

  117.   b3 e% W- h2 n5 i+ x) y' l
  118.         // 未分完的奖励即为平台收益
    , R4 H# [3 I, m+ L# s8 M
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    6 v$ C: q5 W& H. Y- ?5 l1 W7 z
  120.         if (giftAmt > 0) {
    . [. e7 w! l2 f5 `# r  H3 K
  121.             winnerVaults[admin] += giftAmt;5 e  a5 N' H7 D4 \  b! j
  122.         }
    $ x: m) r6 F+ q+ }& j

  123. 2 ?# G" I9 s0 ?1 f
  124.         emit Finialize(currRound++, uint256(_country));
    3 f9 T" k3 g- R$ ^6 G2 K
  125.     }
    8 O% }1 u' d5 G# R2 O$ Z

  126. ! [& u7 s6 a, ], W" w/ t% q) [
  127.     // 奖金兑现
    7 t" L8 n3 Z5 G. f" o6 [+ E
  128.     function claimReward() external {
    / p/ ~  S  i6 Q- ?0 C& S
  129.         uint256 rewards = winnerVaults[msg.sender];
    # D. M! B/ J/ G4 q
  130.         require(rewards > 0, "nothing to claim!");$ N  Q0 Q& t' F/ D

  131. , r' _0 |9 a: l9 E. y4 p5 s
  132.         // 玩家领取完奖金置为 0' T' l1 c* J1 |0 k  x
  133.         winnerVaults[msg.sender] = 0;
    3 f8 j" b9 P1 |  a
  134.         // 从待兑现奖金池中移除该玩家份额3 x; f/ \7 X" d
  135.         lockedAmts -= rewards;9 q3 ^; V+ L" j1 a; J( J
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    $ L5 Y& M4 ~& q# e$ c
  137.         require(succeed, "claim reward failed!");% v: \) w5 ?4 }2 G

  138.   b3 B. {! |( P- i3 o
  139.         console.log("rewards:", rewards);
    2 o: _! y8 M/ _4 k4 i4 y2 }
  140. 1 S# x2 P2 o  H! V6 @. L. n
  141.         emit ClaimReward(msg.sender, rewards);
    0 k, _* h7 R7 D/ \- f4 a
  142.     }3 t$ g% d$ P7 a4 K
  143. + V. e6 R% |; ]! \$ z
  144.     // 获取奖池金额
    ; R0 Q0 Z) Z  t7 d5 z& T) c5 V
  145.     function getVaultBalance() public view returns(uint256 bal) {/ K  k& L: j+ R5 n9 O
  146.         bal = address(this).balance;
    6 b, c$ U0 i# E% c8 [1 H) y
  147.     }
    $ y2 f$ O. O' v# T  d! K: _7 x5 @5 n
  148. . v- l' J3 e7 X6 l. Z9 e" M# n
  149.     // 获取当期下注当前球队的人数
    " |) W3 m% |3 n9 ?. i% y
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    9 i5 l' @( Y  }$ w8 F
  151.         return countryToPlayers[_round][_country].length;
    2 ~% D9 }& c  T9 G
  152.     }6 `& i- e+ X8 ^0 a; }
  153. 3 j- ~4 i* e1 Q# x
  154.     // 获取当前玩家当期押注份额. S0 U9 z5 ?6 c: r1 M* k8 G, U
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {
    & H1 A. k1 y. Z, ^4 F
  156.         return players[_round][_player].counts[_country];
    * D* G( Q  o' V0 Z. R# {* f/ U
  157.     }" l7 H1 K- O, i7 g/ [
  158. }
复制代码

" C- t0 ^7 D2 j) @0 M& ?* z$ E. r! u, ~" v- [9 ^: U) d

  c& c9 E2 I7 G$ r
7 y- u% m" T2 u9 D9 q
! e5 B$ A% t* J1 E" p
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4