【实战篇 二】开发一个预测市场和投注的合约

最近英雄联盟全球总决赛落下帷幕,同时下一届的世界杯预选赛也已经开打,结合这些热点,我们可以开发一个投注预测比赛结果的DApp。

整个项目的架构分为:智能合约、前端界面、后端管理

这里需要讲一下,虽然DApp是一个去中心化应用,但是在实际运营的时候要配合UI界面,以及比赛的信息、结果等都需要一些额外的资源去支持,例如(图片、文字、甚至视频)这些额外的资源是不便存在链上的,所以我们通过智能合约完成核心的功能,保存交易记录及转账

项目需求

首先,我们要编写一个投注的智能合约,合约包含创建投注、开始、结束、下注、分配奖金的功能。同时,我们在用户下注后将下注信息保存在服务端,以便在分配奖金阶段可以准确的找到用户的下注结果,同时降低GAS费。

合约编写

按照上面的项目需求,我们先来完成合约

拥有者与手续费

  • 合约的拥有者由 owner 变量表示,拥有者具备管理权限。
  • FEE_PERCENTAGE 常量定义了合约拥有者提取的手续费百分比,这可用于维护合约和服务。
// SPDX-License-Identifier: MIT
// 智能合约的许可证,表示该合约采用MIT许可证
pragma solidity ^0.8.0;

contract BettingContract {
    // 合约拥有者的地址
    address public owner;

    //...
}

结构体定义

Bet 结构体
  • Bet 结构体用于表示用户的一次下注,包含下注金额、下注结果(0 表示“赢”,1 表示“输”)以及相关状态标记。
 // 表示一个下注的结构体
    struct Bet {
        uint amount;         // 下注金额
        uint8 outcome;       // 0表示“赢”,1表示“输”
        bool exists;         // 标记是否存在该下注
        bool isWinner;       // 是否为赢家
        bool isPaid;         // 奖金是否已支付
    }
Match 结构体
  • Match 结构体表示一场比赛,包含唯一标识符、开始和结束时间、下注开启状态、总下注金额、不同结果的总下注金额数组以及用户下注的映射。
    // 表示一场比赛的结构体
    struct Match {
        uint id;                       // 比赛的唯一标识符
        uint startTime;                // 比赛开始时间
        uint endTime;                  // 比赛结束时间
        bool isBettingOpen;            // 标记是否允许下注
        uint totalBetAmount;           // 总下注金额
        uint[2] totalBetAmountByOutcome; // 索引0为“赢”,索引1为“输”
        mapping(address => Bet) bets;  // 存储地址到对应的下注信息
    }

合约状态

  • matches 映射将比赛 ID 与 Match 结构体关联,用于存储和检索比赛信息。
  • nextMatchId 记录下一个比赛的唯一标识符。
  • 各种事件
    // 存储比赛ID到比赛结构体的映射
    mapping(uint => Match) public matches;
    // 下一个比赛的ID
    uint public nextMatchId;

    // 事件,用于通知外部系统发生的关键操作
    event BetPlaced(uint matchId, address bettor, uint amount, uint8 outcome);
    event MatchCreated(uint matchId, uint startTime, uint endTime);
    event MatchBettingOpened(uint matchId);
    event MatchBettingClosed(uint matchId);
    event WinningsDistributed(uint matchId);

在部署合约的时候设置合约拥有者:

    // 修饰符,限制只有拥有者可以调用的函数
    modifier onlyOwner() {
        require(msg.sender == owner, "只有拥有者可以调用此函数");
        _;
    }

关键功能

当然可以。以下是对给定代码的书面报告:


智能合约报告:体育比赛投注系统

摘要

本智能合约实现了一个简单而功能强大的体育比赛投注系统。该系统允许用户在不同比赛的各种结果上下注,同时提供了管理比赛、开启/关闭下注以及分发奖金的功能。此合约采用了MIT许可证。

合约结构

拥有者与手续费

  • 合约的拥有者由 owner 变量表示,拥有者具备管理权限。
  • FEE_PERCENTAGE 常量定义了合约拥有者提取的手续费百分比,这可用于维护合约和服务。

结构体定义

Bet 结构体
  • Bet 结构体用于表示用户的一次下注,包含下注金额、下注结果(0 表示“赢”,1 表示“输”)以及相关状态标记。
Match 结构体
  • Match 结构体表示一场比赛,包含唯一标识符、开始和结束时间、下注开启状态、总下注金额、不同结果的总下注金额数组以及用户下注的映射。

合约状态

  • matches 映射将比赛 ID 与 Match 结构体关联,用于存储和检索比赛信息。
  • nextMatchId 记录下一个比赛的唯一标识符。

关键功能

创建新比赛

  • createMatch 函数由合约拥有者调用,用于创建新的比赛。指定比赛的开始时间,系统会自动生成唯一的比赛 ID。
    function createMatch(uint startTime) public onlyOwner {
        // 为新比赛分配唯一ID
        uint matchId = nextMatchId++;
        // 获取新比赛的引用
        Match storage newMatch = matches[matchId];
        // 设置新比赛的属性
        newMatch.id = matchId;
        newMatch.startTime = startTime;
        newMatch.isBettingOpen = true;

        // 发出比赛创建事件通知
        emit MatchCreated(matchId, startTime, 0);
    } 

开启/关闭下注

  • openBetting 函数用于在比赛开始前24小时内开启下注,并在比赛开始后关闭下注。
  • closeBetting 函数由拥有者调用,用于在比赛开始后关闭下注。
    // 开启某场比赛的下注功能
    function openBetting(uint matchId) public {
        // 获取比赛的引用
        Match storage match_ = matches[matchId];
        // 要求只能在比赛开始前24小时内开启下注
        require(block.timestamp <= match_.startTime - 24 hours, "只有在比赛开始前24小时内才能开启下注");
        // 要求不能在比赛开始后开启下注
        require(block.timestamp >= match_.startTime, "比赛开始后不能开启下注");
        // 标记该比赛下注功能已开启
        match_.isBettingOpen = true;
        // 记录下注功能开启的时间
        match_.endTime = block.timestamp; 
        // 发出比赛下注开启事件通知
        emit MatchBettingOpened(matchId); 
    }
    // 关闭某场比赛的下注功能
    function closeBetting(uint matchId) public onlyOwner {
        // 获取比赛的引用
        Match storage match_ = matches[matchId];
        // 要求只能在比赛开始后关闭下注
        require(block.timestamp >= match_.startTime, "只有在比赛开始后才能关闭下注");
        // 标记该比赛下注功能已关闭
        match_.isBettingOpen = false;
        // 发出比赛下注关闭事件通知
        emit MatchBettingClosed(matchId);
    }

用户下注

  • placeBet 函数允许用户在比赛开始前24小时内对不同结果下注。下注金额被累加到总下注金额和不同结果的总下注金额中。
    // 用户下注的函数
    function placeBet(uint matchId, uint8 outcome) public payable {
        // 获取比赛的引用
        Match storage match_ = matches[matchId];
        // 要求只能在比赛开始前24小时内下注
        require(block.timestamp >= match_.startTime - 24 hours, "还不能下注");
        // 要求不能在比赛开始后下注
        require(block.timestamp < match_.startTime, "下注已关闭");
        // 要求该比赛下注功能已开启
        require(match_.isBettingOpen, "该比赛下注已关闭");
        // 要求下注金额大于0
        require(msg.value > 0, "下注金额必须大于0");
        // 要求下注结果为0或1
        require(outcome <= 1, "无效的下注结果");
 
        // 获取用户下注的引用
        Bet storage userBet_ = match_.bets[msg.sender];
        // 如果用户之前没有下注,则初始化下注信息
        if (!userBet_.exists) {
            userBet_.exists = true;
            userBet_.amount = msg.value;
            userBet_.outcome = outcome;
        } else {
            // 如果用户已经下注过,则累加下注金额
            userBet_.amount += msg.value;
        }

        // 更新比赛的总下注金额和各结果的总下注金额
        match_.totalBetAmount += msg.value;
        match_.totalBetAmountByOutcome[outcome] += msg.value;
        
        // 发出下注成功的事件通知
        emit BetPlaced(matchId, msg.sender, msg.value, outcome);
    }

分发奖金

  • distributeWinnings 函数由拥有者调用,用于在比赛结束后向赢家分发奖金。计算奖金时考虑手续费,并确保奖金未分发过。
    // 分发奖金给赢家的函数
    function distributeWinnings(uint matchId, address winnerAddress) public onlyOwner {
        //待定 ...
    }

至此我们完成了一个预测赛事的智能合约,需要注意的事,此合约只是示例功能,并不能用于生产环境

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中关村老李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值