合约项目地址 github
数据逻辑结构分离,基本数据结构固定,外层逻辑更新不影响数据合约。
struct LotteryRule {
uint startTime; // 抽奖活动起始时间戳
uint endTime; // 抽奖活动结束时间戳
uint daysStartTime; // 每天抽奖起始时间,0 为不限制
uint daysEndTime; // 每天抽奖结束时间,0 为不限制
uint participateCnt; // 抽奖活动总次数限制, 0 为不限制
uint perAddressPartCnt; // 每个地址能参与的抽奖次数,0为不限制
}
新建抽奖活动时的参数根据需求自定义抽奖规则
在管理员启动抽奖时,合约方法计算此次抽奖的所有奖品的中奖概率倒数的最小公倍数,然后使用最小公倍数除以每个奖品的中奖概率,得出每个奖品的中奖数组。
例:
抽奖 TestLottery 的奖品信息及中奖数组
奖品名称 | 中奖概率 | 概率倒数 | 中奖数组 |
---|---|---|---|
奖品A | 1% | 100 | [0] |
奖品B | 2% | 50 | [1, 2] |
奖品C | 5% | 20 | [3, 4, 5, 6, 7] |
如上:三种奖品的中奖概率倒数的最小公倍数为100,以100除以每个奖品的概率倒数,得到的结果做中奖数组的长度,所有结果的值依次递增。
用户抽奖时,以抽奖时的uint(keccak256(拼接字符串 (上一块的blockhash + msg.sender + 全局自增index)))
的uint值做随机数,对上面计算的最小公倍数取模,得到随机值。如果随机值结果在以上奖品的中奖数组里,即表示抽得对应的奖品。
hash的产生依赖的是产生随机数的交易时的上一块的hash,迅雷链对外的交易确认是秒级确认,但并不会立即同步对外的交易记录,以此保证上一块交易hash不会被用来作恶。
合约项目地址 github
该合约实现了抽奖活动奖池模型主要功能,共包含两个合约,LotteryControl控制合约与LotteryData数据合约,控制合约提供开发者访问合约的入口,数据合约处理、保存相关数据。
部署LotteryData合约
部署LotteryControl合约
调用LotteryData合约 setLotteryControl方法,设置LotteryControl合约地址
开发者或用户通过调用LotteryControl合约方法进行合约交互
开发者调用newLottery方法创建抽奖活动,该方法返回活动ID,开发者需保存活动ID,后续调用合约方法要求传入该活动ID;
创建后再调用setLotteryConfig进行活动规则设置,开发者可根据需求传入参数进行规则配置,配置参数说明如下。
// 设置抽奖配置
function setLotteryConfig (
uint lotteryID, //抽奖活动ID
uint startTime, //活动开始时间, Unix时间戳
uint endTime, //活动结束时间, Unix时间戳
bool dayLimit, //是否限制每天抽奖时间
uint dayStartTime, //每天抽奖开始时间
uint dayEndTime, //每天抽奖结束时间
int timesPerItem, //参与者抽奖次数限制
uint amountPerAction, //每次抽奖的token金额
uint openCondition, //开奖条件, 抽奖模式为 0:奖池模式,奖池金额达到指定数量开奖 1:开奖时间模式,达到指定时间开奖(Unix时间戳) 2:地址模式,参与用户账户地址达到指定数量开奖
uint copies //奖品平分成几份发放
)
调用setLotteryConfig后,抽奖活动自动生效。
用户调用joinLottery方法参与抽奖,若满足抽奖规则,则成功参与,用户可在抽奖开启后查看抽奖结果;
奖池金额、参与用户数量固定模式
抽奖活动满足开奖条件时,合约内部会触发OpenLottery事件,开发者可通过监听该事件判断可以已开启抽奖,然后调用调用openLottery开启抽奖。若抽奖活动结束,仍未监听事件发生,开发者直接调用openLottery开启抽奖。
开奖时间固定模式
开发者在开奖时间到达后调用openLottery开启抽奖。
开启抽奖后抽奖活动最终有以下两种状态,开发者或用户可通过调用queryLotteryResult方法查看结果
奖池内全部token平分成N份(开发者可修改合约参数配置), 依次将每份奖励随机分配给抽奖参与用户,一个用户可能获得多份奖励。