Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

足球竞猜智能合约源代码

仙翁童子子os
448 0 0
业务需求; B8 ^6 i/ D7 I/ D/ P, `
  • 参赛球队一经设定不可改变,整个活动结束后无法投票;
  • 全⺠均可参与,无权限控制;
  • 每次投票为 1 ether,且只能选择一支球队;
  • 每个人可以投注多次;
  • 仅管理员公布最终结果,完成奖金分配,开奖后逻辑:
  • winner 共享整个奖金池(一部分是自己的本金,一部分是利润);
  • winner 需自行领取奖金(因为有手续费);
  • 下一期自行开始
    1 S' ]7 g7 {; z0 R
) T* B3 J# Z+ G% H: o

  t7 a7 E2 R  z; N; m. ~9 ?# [0 b  |5 U6 k/ I0 f, B

  1. 4 P; s. v9 _( Y8 W, F& s
  2. // SPDX-License-Identifier: GPL-3.0
    8 ?3 O! b' Z. i6 M

  3. 7 x# _4 |) f+ c) D% i
  4. pragma solidity >=0.7.0 <0.9.0;5 J$ [0 w* A; H. f: \9 [: \
  5. 1 J! a; v  t. J, m' J+ O( ?/ H6 l2 u
  6. import "hardhat/console.sol";. d% b. T) o2 L  p9 |$ A

  7. * k9 u9 U: n7 i( t) G5 M( J
  8. contract WorldCup {
    ) {. n4 w  _# g3 H
  9.     // 1. 状态变量:管理员、所有玩家、获奖者地址、第几期、参赛球队1 p; _+ {# B' m
  10.     // 2. 核心方法:下注、开奖、兑现
    ( Q% v( {* N; S% h- ?
  11.     // 3. 辅助方法:获取奖金池金额、管理员地址、当前期数、参与人数、所有玩家、参赛球队
    . G# B; h5 e9 @1 Y! X7 Z9 p: S- D
  12. . g8 @; Z) Z5 A! f2 E1 [: t
  13.     // 管理员
    ) N$ b- `0 e% e' J3 v
  14.     address public admin;7 c' U, O% c, w
  15.     // 第几期
    ! r% g5 [% I+ y5 P! Z) \3 J: E
  16.     uint8 public currRound;! z1 I0 g5 a' r. Q( M0 f) j! B
  17. 7 u$ V- _% [4 k5 J- b5 X& b
  18.     // 参赛球队- R* L1 H: T0 p1 k# V6 l' I
  19.     string[] public countries = ["GERMANY", "FRANCH", "CHINA", "BRIZAL", "KOREA"];+ H6 k3 U8 x. K! `7 ?
  20.     // 期数 => 玩家
    $ z6 U- n( r- I, y+ d
  21.     mapping(uint8 => mapping(address => Player)) players;
    : ?) j, M" Y1 X5 ?5 k+ K! x* A8 S
  22.     // 期数 => 投注各球队的玩家
    % q' D. t8 b: E! G) C
  23.     mapping(uint8 => mapping(Country => address[])) public countryToPlayers;
    / k; x2 Z$ P- ]" w
  24.     // 玩家对应赢取的奖金
    % Y* W* n4 M  r9 ~% p" }& t! Z
  25.     mapping(address => uint256) public winnerVaults;3 S3 w( b4 |( T! v+ j: E5 `8 w
  26. 7 A  N9 F% m2 x$ ^9 P* P, O1 d9 e
  27.     // 投注截止时间-使用不可变量,可通过构造函数传值,部署后无法改变0 S3 G! P6 U% h" M6 T& i) g
  28.     uint256 public immutable deadline;; g% h" T, G9 c! }
  29.     // 所有玩家待兑现的奖金
    6 a. g1 H4 k6 Y/ n- r  z
  30.     uint256 public lockedAmts;& T3 H: w% o0 c/ `2 Z- l; {

  31. . ~9 m. D9 c3 v
  32.     enum Country {
    0 g- \  J0 F5 B; _- @, i) r0 B
  33.         GERMANY,
    + p0 Y4 l. [0 u- J
  34.         FRANCH,/ r$ Y: {' N' C! A: g
  35.         CHINA,
    5 p8 F; M1 i" g! Y& r
  36.         BRAZIL,
    " @* C6 j0 N/ N- n
  37.         KOREA* j9 ^+ u( F! S
  38.     }" C4 G! ^6 G, a/ J9 y6 R
  39. , e$ Y# B% ^$ R/ f
  40.     event Play(uint8 _currRound, address _player, Country _country);" V& g$ u/ y. @$ c
  41.     event Finialize(uint8 _currRound, uint256 _country);: A8 G8 t% g: T* X- O
  42.     event ClaimReward(address _claimer, uint256 _amt);/ x$ l7 ]: r8 f( ^1 r+ e% V4 d  X

  43.   ^! ]3 X1 K5 r' q& F# T/ o
  44.     // 验证管理员身份& A* B' ?0 o3 C8 O9 F5 v
  45.     modifier onlyAdmin {4 l  E: O- g+ h+ K: S; X
  46.         require(msg.sender == admin, "not authorized!");
    5 ~+ u* b3 m- w0 [: n+ y' v! B
  47.         _;
    3 Z. j- P; f8 h% |6 G5 Z% v( f/ m
  48.     }
    3 `0 }, k" j* h" B' K

  49. 2 u9 |. G0 c, P! G
  50.     // 玩家投注信息# J; L+ y; m9 B! V, a9 a/ g1 }$ k" c
  51.     struct Player {7 D# L0 q2 c0 ?" X5 l6 p  v5 u
  52.         // 是否开奖
    . L0 [7 G* _4 F* s# T4 D+ e4 ?6 R
  53.         bool isSet;
      \4 _6 U  n: e5 g! o+ r, v6 J
  54.         // 投注的球队份额
    * r  k* _& i% b8 _) k/ x- ~
  55.         mapping(Country => uint256) counts;2 f; V6 V9 W6 }* J
  56.     }
    ( s% U$ V1 k# @3 x- P
  57. : C# F4 k+ J' E: M& E
  58.     constructor(uint256 _deadline) {
    + x7 R; `( f6 c" I/ a
  59.         admin = msg.sender;) w+ d! k, I2 |0 e6 g$ I
  60.         require(_deadline > block.timestamp, "WorldCupLottery: invalid deadline!");
    / D3 V. y& N8 b' S9 H% Q
  61.         deadline = _deadline;) _2 L1 P( M% I) f5 T0 L
  62.     }
    5 b* j- Q8 [/ c% b( g/ L- k/ T. |

  63. 0 Q4 G- H  s* Q+ E8 ~& _& W8 C: g+ B. k
  64.     // 下注过程2 l6 _( \8 R. A
  65.     function play(Country _selected) payable external {
    ; I6 {! M# d. ?0 {7 d
  66.         // 参数校验
    0 c' q! y: J1 X
  67.         require(msg.value == 1 gwei, "invalid funds provided!");- v  a" Q. Y/ ?+ S- m

  68. 5 ?/ t/ ~( Y& r) E9 O% w$ _' Q5 S
  69.         require(block.timestamp < deadline, "it's all over!");7 c' e! K3 y0 M3 N; R
  70. 1 _2 v( b6 G+ T5 U$ a$ j
  71.         // 更新 countryToPlayers0 J3 h, P- k5 L; {; {  n
  72.         countryToPlayers[currRound][_selected].push(msg.sender);
    3 W  y6 D! K) T3 k6 t" n
  73.         // 更新 players(storage 是引用传值,修改会同步修改原变量)
    5 e& t! l; x) d+ q2 ~
  74.         Player storage player = players[currRound][msg.sender];
    & a. }0 i8 ?+ M% u: k( j- ^# U
  75.         // player.isSet = false;! }7 Z1 |. i4 Q4 q$ c
  76.         player.counts[_selected] += 1;
    % f, m" Z4 T9 ^& e8 ]
  77. 2 P+ H9 f  e5 Q( v# ?( }: C
  78.         emit Play(currRound, msg.sender, _selected);9 O. s2 ~, t1 N/ P( ^
  79.     }
    ) Z7 e3 W' i0 S7 o+ B+ C2 J

  80. " V9 N# J! M+ t8 F9 X
  81.     // 开奖过程
      W# p4 B+ z% K  c
  82.     function finialize(Country _country) onlyAdmin external {! O" A& r6 Z* a: l
  83.         // 找到 winners
    6 i1 g2 |: S; Y' k
  84.         address[] memory winners = countryToPlayers[currRound][_country];
    5 e1 y; B) T' g- l0 K% N) P
  85.         // 分发给所有压中玩家的实际奖金- a' J1 L0 U$ U
  86.         uint256 distributeAmt;' q7 U8 O6 c. M, @

  87. 2 \: j$ K7 z2 @, ?
  88.         // 本期总奖励金额(奖池金额 - 所有玩家待兑现的奖金)
    7 ?9 U) t9 u2 `! {1 r
  89.         uint currAvalBalance = getVaultBalance() - lockedAmts;3 z( a" `4 Y: m2 Z$ p1 v
  90.         console.log("currAvalBalance:", currAvalBalance, "winners count:", winners.length);6 a7 A1 G1 W7 {1 Z% N. Y  R# F
  91. 0 E# u. R  s% [! d
  92.         for (uint i = 0; i < winners.length; i++) {. U9 J9 {, U* M! G6 f3 ~
  93.             address currWinner = winners[i];
    0 \4 C( K6 X) l( n
  94. & L9 F6 J; y1 n! Q
  95.             // 获取每个地址应该得到的份额
    * x+ d& r4 L3 M! E3 p
  96.             Player storage winner = players[currRound][currWinner];
    % y: g, Q$ L" V6 ~
  97.             if (winner.isSet) {
    % w* ~: Q6 s2 W1 w* x: }) Y
  98.                 console.log("this winner has been set already, will be skipped!");# U: o8 l  Q* t% O
  99.                 continue;
    ' S8 b5 S( E/ x$ n2 N
  100.             }3 d" M" G; B( i: b
  101. 0 `0 X4 M5 x4 a" y
  102.             winner.isSet = true;
    3 O2 o& ?2 t- G5 c4 H
  103.             // 玩家购买的份额
    & _. G! Y' |7 y/ r& ~
  104.             uint currCounts = winner.counts[_country];
    " V* \& c5 K, [

  105. ( l+ Z/ Z; b7 H. t
  106.             // (本期总奖励 / 总获奖人数)* 当前地址持有份额
    * I4 e# J; e8 ~3 g8 y6 ^- ^5 r( h8 H
  107.             uint amt = (currAvalBalance / countryToPlayers[currRound][_country].length) * currCounts;
    9 W( {% m* q: S6 _* m/ I
  108.             // 玩家对应赢取的奖金. W/ Q. b) V( l1 C  K6 x1 v/ Y
  109.             winnerVaults[currWinner] += amt;
    & x  ^; l" e* M9 q
  110.             distributeAmt += amt;7 s* v' j- E; |0 z( K
  111.             // 放入待兑现的奖金池- Z2 e# h- X+ _2 w9 f
  112.             lockedAmts += amt;' }% r# G7 m7 @- A9 x& D) h

  113. / w9 b& |; J- @# x" c4 Q7 s+ a
  114.             console.log("winner:", currWinner, "currCounts:", currCounts);
    : F/ P8 @3 [& M% w$ K- i
  115.             console.log("reward amt curr:", amt, "total:", winnerVaults[currWinner]);
    & n& g8 L$ X( X& ]5 P
  116.         }  M" J+ k$ a5 T

  117. ' H& ]/ ~3 A- T
  118.         // 未分完的奖励即为平台收益
    ( F% }3 T5 [* M3 ~3 u& r0 v7 K& L. v
  119.         uint giftAmt = currAvalBalance - distributeAmt;
    ; P# _# d0 X- m# g* T3 p$ n+ r
  120.         if (giftAmt > 0) {
    $ C2 j- s! ?. V
  121.             winnerVaults[admin] += giftAmt;* j8 w" L* ^( D9 Z
  122.         }
    4 R9 Q9 f; ?4 \* ^% S! C5 x, l* w

  123. ' c5 p) X& I9 u3 T
  124.         emit Finialize(currRound++, uint256(_country));
    ! d+ N/ W; D- V* E
  125.     }
    , U$ j3 y, w* J3 m

  126. " @. E* ^1 v; H4 R( T* t9 t
  127.     // 奖金兑现, w8 @' I; O0 {% p0 \; p
  128.     function claimReward() external {$ E: a. ^& I  D2 M# t
  129.         uint256 rewards = winnerVaults[msg.sender];) v- {, o' {( z8 g0 w  e% A2 v
  130.         require(rewards > 0, "nothing to claim!");/ F; Y: ^/ n2 X9 \, F, v
  131. 2 O, G$ j+ ?0 F) n
  132.         // 玩家领取完奖金置为 0
    9 S& Z; O4 K* {! W0 G
  133.         winnerVaults[msg.sender] = 0;& C4 y- O- w8 m6 G
  134.         // 从待兑现奖金池中移除该玩家份额
    8 C$ B9 n$ D- l6 k2 B; W  U
  135.         lockedAmts -= rewards;3 E+ o/ G! `( I% u5 P+ V
  136.         (bool succeed,) = msg.sender.call{value: rewards}("");
    4 l; L& q% {) X9 e
  137.         require(succeed, "claim reward failed!");
    8 E" \* p, T& L+ M7 e! Q5 ?

  138. 3 f1 e; z0 e' N# w- V5 I6 ]  F
  139.         console.log("rewards:", rewards);  b5 U' l" C. k9 l

  140. 5 j& \0 a; [) o; n1 n% r
  141.         emit ClaimReward(msg.sender, rewards);
    6 i& @0 U: T% h; @2 t5 G
  142.     }+ S# Y$ p1 Z( f* F+ w

  143. % P$ }$ z0 k  Y8 t4 E1 K
  144.     // 获取奖池金额. y" d2 Q1 J* F. i/ O2 g! ^7 |
  145.     function getVaultBalance() public view returns(uint256 bal) {- i, r- X; P) f1 v$ ?6 t
  146.         bal = address(this).balance;( l4 w, ?  J4 z6 m
  147.     }0 j  ?4 F9 G/ C+ h

  148.   }: f  R3 ^$ s: N" `) `3 c
  149.     // 获取当期下注当前球队的人数. ^% R( q0 {7 A; u. U/ H
  150.     function getCountryPlayers(uint8 _round, Country _country) external view returns(uint256) {
    - l$ P, {9 n4 M: m9 i
  151.         return countryToPlayers[_round][_country].length;/ O8 [8 t& w& e# k3 |  z$ G
  152.     }; U+ x' z( A+ W$ s9 T5 X! T

  153. ' g/ F. p% b5 s9 l% h/ c$ p2 a# N
  154.     // 获取当前玩家当期押注份额
    1 u  ]8 D. J" Y( \4 o
  155.     function getPlayerInfo(uint8 _round, address _player, Country _country) external view returns(uint256 _counts) {7 ^# X* J( O+ m7 d
  156.         return players[_round][_player].counts[_country];
    / y7 ]2 L! t4 p% i8 o9 R# o# l) ~5 W/ W
  157.     }+ D+ }; e, a& L4 j: V
  158. }
复制代码

4 z! T7 _3 j8 f/ o( x, S- x( ^' S& \) h; }+ E

# L4 j5 M# y" s9 w& E. W$ K1 p
6 F! K9 N  h  {" U* F0 x0 d' A$ O' y+ `0 h( t4 j
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    4