ChainLink的VRF体验之彩票合约

今天体验了一下ChainLink的VRF功能,用的是社区的一个模拟彩票抽奖的智能合约。下面是智能合约的主要代码:

RandomNumberGenerator.sol

pragma solidity ^0.6.2;

import "./VRFConsumerBase.sol";
import "./Lottery.sol";

contract RandomNumberGenerator is VRFConsumerBase {

    address requester;
    bytes32 keyHash;
    uint256 fee;

    constructor(address _vrfCoordinator, address _link, bytes32 _keyHash, uint256 _fee)
        VRFConsumerBase(_vrfCoordinator, _link) public {
            keyHash = _keyHash;
            fee = _fee;
    }

    function fulfillRandomness(bytes32 _requestId, uint256 _randomness) external override {
        Lottery(requester).numberDrawn(_requestId, _randomness);
    }

    function request(uint256 _seed) public returns(bytes32 requestId) {
        require(keyHash != bytes32(0), "Must have valid key hash");
        requester = msg.sender;
        return this.requestRandomness(keyHash, fee, _seed);
    }
}

Lottery.sol

pragma solidity >=0.6.2;

import "openzeppelin/contracts/access/Ownable.sol";
import "openzeppelin/contracts/utils/EnumerableSet.sol";
import "openzeppelin/contracts/utils/Address.sol";
import "openzeppelin/contracts/math/SafeMath.sol";
import "./RandomNumberGenerator.sol";

contract Lottery is Ownable{

    using EnumerableSet for EnumerableSet.AddressSet;
    using Address for address;
    using SafeMath for uint;
    
    enum LotteryState { Open, Closed, Finished }
    
    mapping(uint => EnumerableSet.AddressSet) entries;
    uint[] numbers;
    LotteryState public state;
    uint public numberOfEntries;
    uint public entryFee;
    uint public ownerCut;
    uint public winningNumber;
    address randomNumberGenerator;
    bytes32 randomNumberRequestId;
    
    event LotteryStateChanged(LotteryState newState);
    event NewEntry(address player, uint number);
    event NumberRequested(bytes32 requestId);
    event NumberDrawn(bytes32 requestId, uint winningNumber);
    
    // modifiers
    modifier isState(LotteryState _state) {
        require(state == _state, "Wrong state for this action");
        _;
    }
    
    modifier onlyRandomGenerator {
        require(msg.sender == randomNumberGenerator, "Must be correct generator");
        _;
    }
    
    //constructor
    constructor (uint _entryFee, uint _ownerCut, address _randomNumberGenerator) public Ownable() {
        require(_entryFee > 0, "Entry fee must be greater than 0");
        require(_ownerCut < _entryFee, "Entry fee must be greater than owner cut");
        require(_randomNumberGenerator != address(0), "Random number generator must be valid address");
        require(_randomNumberGenerator.isContract(), "Random number generator must be smart contract");
        entryFee = _entryFee;
        ownerCut = _ownerCut;
        randomNumberGenerator = _randomNumberGenerator;
        _changeState(LotteryState.Open);
    }
    
    //functions
    function submitNumber(uint _number) public payable isState(LotteryState.Open) {
        require(msg.value >= entryFee, "Minimum entry fee required");
        require(entries[_number].add(msg.sender), "Cannot submit the same number more than once");
        numbers.push(_number);
        numberOfEntries++;
        payable(owner()).transfer(ownerCut);
        emit NewEntry(msg.sender, _number);
    }
    
    function drawNumber(uint256 _seed) public onlyOwner isState(LotteryState.Open) {
        _changeState(LotteryState.Closed);
        randomNumberRequestId = RandomNumberGenerator(randomNumberGenerator).request(_seed);
        emit NumberRequested(randomNumberRequestId);
    }
    
    function rollover() public onlyOwner isState(LotteryState.Finished) {
    //rollover new lottery
    }
    
    function numberDrawn(bytes32 _randomNumberRequestId, uint _randomNumber) public onlyRandomGenerator isState(LotteryState.Closed) {
        if (_randomNumberRequestId == randomNumberRequestId) {
            winningNumber = _randomNumber;
            emit NumberDrawn(_randomNumberRequestId, _randomNumber);
            _payout(entries[_randomNumber]);
            _changeState(LotteryState.Finished);
        }
    }
    
    function _payout(EnumerableSet.AddressSet storage winners) private {
        uint balance = address(this).balance;
        for (uint index = 0; index < winners.length(); index++) {
            payable(winners.at(index)).transfer(balance.div(winners.length()));
        }
    }
    
    function _changeState(LotteryState _newState) private {
        state = _newState;
        emit LotteryStateChanged(state);
    }
}

部署RandomNumberGenerator合约

我打算在ropsten测试网上部署所有的合约

这四个参数均来自ChainLink官网资料。

VRF Coordinator    0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb
Key Hash    0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205
Fee    1 LINK
LINK 代币: 0x20fE562d797A42Dcb3399062AE9546cd06f63280

这里要注意的是,部署好这个合约之后一定要给这个合约转账大于1LINK的代币。因为每次抽奖都要消耗1LINK。

部署Lottery合约

这里最后一项是上面部署的RandomNumberGenerator合约的地址,_entryfee是指买彩票的费用,_ownercut是指合约拥有者要收取的佣金。

买彩票,选数字

这里要注意的是,在调用submitNumber智能合约接口的时候,一定不要忘了设置购买彩票的费用,比如我这里给的是0.2,实际上,只需要给0.001eth就行了。但因为我是测试网上的eth,管够,所以懒得敲那么多0。

开奖

这里的_seed是自由选择的,我就随便选了一个交易hash做为它的值。

执行完这个交易后,等一段时间,查询合约的状态和中奖号码。

可以看到合约状态变成1了,1表示close。

中奖号码也出来了,虽然大的离谱,但效果已经有了。

 

(全文完)

参考资料:

https://cloud.tencent.com/developer/article/1634665
https://mp.weixin.qq.com/s/vTq4aiznIMkaY9SvzEYufw

https://docs.chain.link/docs/chainlink-vrf

https://ropsten.chain.link/

https://docs.chain.link/docs/vrf-contracts#config

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值