// SPDX-License-Identifier: MIT import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; pragma solidity ^0.8.11; contract StoryRaffle is VRFConsumerBase{ using SafeMath for uint; address public owner; address payable[] public players; uint public raffleId; mapping (uint => address payable) public raffleHistory; // storing winner of each lottery bytes32 internal keyHash; // identifies which Chainlink oracle to use uint internal fee; // fee to get random number (LINK) enum RaffleState { Open, Closed, Completed } RaffleState public state; uint public randomResult; using Counters for Counters.Counter; Counters.Counter private _ticketIds; // uint[] public numbers; uint public maxEntries; // struct Ticket { // // address payable player; // uint ticketId; // string answer; // uint timestamp; // } uint[] public tickets; mapping (uint => address) public ticketToPlayer; mapping (address => uint) playerTicketCount; /* * map address to last time they entered the lottery */ mapping(address => uint) public lastEntryTime; constructor() VRFConsumerBase( 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B, // VRF Coordinator - Rinkeby 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK token address ) { keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311; fee = 0.1 * 10 ** 18; // 0.1 LINK owner = msg.sender; // owner of the deployer of the contract raffleId = 1; maxEntries = 50000; _ticketIds.increment(); } /** * Requests randomness */ function getRandomNumber() public returns (bytes32 requestId) { require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK in contract"); return requestRandomness(keyHash, fee); } /** * Callback function used by VRF Coordinator */ function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { randomResult = randomness; // payWinner(); } function getWinnerByRaffle(uint _lotteryId) public view returns (address payable) { return raffleHistory[_lotteryId]; } // get pot balance function getBalance() public view returns (uint) { return address(this).balance; } // get list of players function getPlayers() public view returns (address payable[] memory) { return players; } function getTickets() public view returns (uint[] memory) { return tickets; } // function getTicketIds() public view returns (uint[] memory) { // return _ticketIds; // } // enter Raffle function enterRaffle() public payable isState(RaffleState.Open) { // cooldown period require( lastEntryTime[msg.sender] + 5 minutes < block.timestamp, "You must wait 5 minutes before entering the raffle again" ); require(tickets.length < maxEntries, "Raffle is full"); // check if player has already entered require(playerTicketCount[msg.sender] < 3 , "You have reached your maximum entries"); require(msg.value >= .01 ether, "Minimum entry fee not met"); uint id = _ticketIds.current(); tickets.push(id); ticketToPlayer[id] = msg.sender; players.push(payable(msg.sender)); lastEntryTime[msg.sender] = block.timestamp; playerTicketCount[msg.sender]++; _ticketIds.increment(); } // generate a Pseudo random number function getPseudoRandomNumber() public returns (uint) { randomResult = uint(keccak256(abi.encodePacked(owner, block.timestamp))); return randomResult; } function pickWinnerTest() public onlyOwner { getPseudoRandomNumber(); } // select winner based on generated random number and transfer balance to their account function pickWinner() public onlyOwner { getRandomNumber(); } // number of tickets a player has?? function getPlayerTickets(address _player) public view returns (uint) { return playerTicketCount[_player]; } function getWinner() public view returns (address) { if (randomResult > 0) { uint index = (randomResult % tickets.length)+1; // return players[index]; return ticketToPlayer[index]; // index-1 ???? } } function getWinningTicketId() public view returns (uint) { if (randomResult > 0) { uint index = (randomResult % tickets.length)+1; return index; } } function payWinner(uint _amount) public onlyOwner { uint index = (randomResult % players.length)+1; // transfer balance of the current smart contract to address of winner players[index-1].transfer(_amount); // getWinner().transfer(_amount); raffleHistory[raffleId] = players[index-1]; raffleId++; // reset the state of the contract players = new address payable[](0); } // modifier to ensure only the owner can run a function modifier onlyOwner() { require(msg.sender == owner, "Only owner can run this function"); _; } modifier isState(RaffleState _state) { require(state == _state, "Raffle is not in the correct state"); _; } function _changeState(RaffleState _state) internal onlyOwner { state = _state; } }