在区块链上部署彩票Dapp的优点:
1)代码公开透明,接收所有人的监督;
2)没有暗箱操作,不存在跑路的风险;
彩票规则:
1)全民参与;
2)每人可以多次投注,但每次只投一注(一注就是1个 eth);
3)只有管理员才能够执行开奖和退奖的操作,其他账户只有投注功能;
奖金池用于保存投注的金额,彩民池保存了参与投注的彩民。
当投注后,奖金池的金额会发生变化,同样投注的帐号也会添加到彩民池中。
由管理员负责开奖,开奖后会把奖金池的金额转给中奖的账户,然后奖金池和彩民池的数据都会被清空。
由管理员负责退款。执行退款后,系统会把奖金池中的金额退还给每一个参与的账户,然后奖金池和彩民池的数据被清空。
(1)合约分析
(2)核心方法
(3)辅助方法
(1)定义合约:定义合约属性、构造函数,设置管理员。
contract Lottery {
address manager; // 管理员
address[] players; // 投了注的彩民
address winner; // 上期彩票的胜出者
uint256 round = 1; // 第几期
constructor() public {
manager = msg.sender;
}
}
(2)参与投注:把参与者的地址添加到players中。
// 投注
function play() public payable {
// 限定投足金额为1eth
require(msg.value == 1 ether);
players.push(msg.sender);
}
(3)开奖
问题:如何确定中奖者?
解决办法:生成players的随机索引值。这里使用难度值,当前时间,参与人数作为种子生成一个大的数字,然后在对参与人数进行求余操作。使用余数作为随机索引值。
// 开奖
function kaiJIang() public {
// 1.设置Winner
// 生成随机下标
bytes memory v1 = abi.encodePacked(block.difficulty, now, players.length);
bytes32 v2 = keccak256(v1);
uint v3 = uint256(v2) % players.length;
winner = players[v3];
// 2.把奖池的金额转账给winner
winner.transfer(address(this).balance);
// 3.清空plays
delete players;
// 4.期数加1
round++;
}
(4)退奖:遍历players,逐一转账,并清除players。
// 退奖
function tuiJiang() public {
require(players.length != 0);
// 1.把奖池的金额退还给每一个玩
for (uint i = 0; i < players.length; i++) {
players[i].transfer(1 ether);
}
// 2.清空plays
delete players;
// 3.期数加1
round++;
}
(5)定义辅助函数
// 获取奖金池的金额
function getAmount() public view returns(uint256) {
return address(this).balance;
}
// 获取管理员地址
function getManagerAddress() public view returns(address) {
return manager;
}
// 返回当前期数
function getRound() public view returns(uint256) {
return round;
}
// 返回中奖者地址
function getWinner() public view returns(address) {
return winner;
}
// 返回参与彩民的地址
function getPlays() public view returns(address[]) {
return players;
}
(6)定义修饰器:非管理员不允许调用被修饰的函数
// 修饰器,限定只有管理员才有权操作
modifier onlyManager() {
require(manager == msg.sender);
_;
}
(7)在kaiJiang和tuiJiang方法定义中添加修饰器
// 开奖
function kaiJIang() public onlyManager {...}
// 退奖
function tuiJiang() public onlyManager {...}
最后,在remix上测试合约。