add lottery smart contract from updraft
This commit is contained in:
224
foundry-smart-contract-lottery-cu/src/Raffle.sol
Normal file
224
foundry-smart-contract-lottery-cu/src/Raffle.sol
Normal file
@@ -0,0 +1,224 @@
|
||||
// Layout of Contract:
|
||||
// version
|
||||
// imports
|
||||
// errors
|
||||
// interfaces, libraries, contracts
|
||||
// Type declarations
|
||||
// State variables
|
||||
// Events
|
||||
// Modifiers
|
||||
// Functions
|
||||
|
||||
// Layout of Functions:
|
||||
// constructor
|
||||
// receive function (if exists)
|
||||
// fallback function (if exists)
|
||||
// external
|
||||
// public
|
||||
// internal
|
||||
// private
|
||||
// view & pure functions
|
||||
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity 0.8.19;
|
||||
|
||||
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
|
||||
import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
|
||||
import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/interfaces/AutomationCompatibleInterface.sol";
|
||||
|
||||
/**
|
||||
* @title A sample Raffle Contract
|
||||
* @author Patrick Collins
|
||||
* @notice This contract is for creating a sample raffle contract
|
||||
* @dev This implements the Chainlink VRF Version 2
|
||||
*/
|
||||
contract Raffle is VRFConsumerBaseV2Plus, AutomationCompatibleInterface {
|
||||
/* Errors */
|
||||
error Raffle__UpkeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 raffleState);
|
||||
error Raffle__TransferFailed();
|
||||
error Raffle__SendMoreToEnterRaffle();
|
||||
error Raffle__RaffleNotOpen();
|
||||
|
||||
/* Type declarations */
|
||||
enum RaffleState {
|
||||
OPEN,
|
||||
CALCULATING
|
||||
}
|
||||
|
||||
/* State variables */
|
||||
// Chainlink VRF Variables
|
||||
uint256 private immutable i_subscriptionId;
|
||||
bytes32 private immutable i_gasLane;
|
||||
uint32 private immutable i_callbackGasLimit;
|
||||
uint16 private constant REQUEST_CONFIRMATIONS = 3;
|
||||
uint32 private constant NUM_WORDS = 1;
|
||||
|
||||
// Lottery Variables
|
||||
uint256 private immutable i_interval;
|
||||
uint256 private immutable i_entranceFee;
|
||||
uint256 private s_lastTimeStamp;
|
||||
address private s_recentWinner;
|
||||
address payable[] private s_players;
|
||||
RaffleState private s_raffleState;
|
||||
|
||||
/* Events */
|
||||
event RequestedRaffleWinner(uint256 indexed requestId);
|
||||
event RaffleEnter(address indexed player);
|
||||
event WinnerPicked(address indexed player);
|
||||
|
||||
/* Functions */
|
||||
constructor(
|
||||
uint256 subscriptionId,
|
||||
bytes32 gasLane, // keyHash
|
||||
uint256 interval,
|
||||
uint256 entranceFee,
|
||||
uint32 callbackGasLimit,
|
||||
address vrfCoordinatorV2
|
||||
) VRFConsumerBaseV2Plus(vrfCoordinatorV2) {
|
||||
i_gasLane = gasLane;
|
||||
i_interval = interval;
|
||||
i_subscriptionId = subscriptionId;
|
||||
i_entranceFee = entranceFee;
|
||||
s_raffleState = RaffleState.OPEN;
|
||||
s_lastTimeStamp = block.timestamp;
|
||||
i_callbackGasLimit = callbackGasLimit;
|
||||
// uint256 balance = address(this).balance;
|
||||
// if (balance > 0) {
|
||||
// payable(msg.sender).transfer(balance);
|
||||
// }
|
||||
}
|
||||
|
||||
function enterRaffle() public payable {
|
||||
// require(msg.value >= i_entranceFee, "Not enough value sent");
|
||||
// require(s_raffleState == RaffleState.OPEN, "Raffle is not open");
|
||||
if (msg.value < i_entranceFee) {
|
||||
revert Raffle__SendMoreToEnterRaffle();
|
||||
}
|
||||
if (s_raffleState != RaffleState.OPEN) {
|
||||
revert Raffle__RaffleNotOpen();
|
||||
}
|
||||
s_players.push(payable(msg.sender));
|
||||
// Emit an event when we update a dynamic array or mapping
|
||||
// Named events with the function name reversed
|
||||
emit RaffleEnter(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev This is the function that the Chainlink Keeper nodes call
|
||||
* they look for `upkeepNeeded` to return True.
|
||||
* the following should be true for this to return true:
|
||||
* 1. The time interval has passed between raffle runs.
|
||||
* 2. The lottery is open.
|
||||
* 3. The contract has ETH.
|
||||
* 4. Implicity, your subscription is funded with LINK.
|
||||
*/
|
||||
function checkUpkeep(bytes memory /* checkData */ )
|
||||
public
|
||||
view
|
||||
override
|
||||
returns (bool upkeepNeeded, bytes memory /* performData */ )
|
||||
{
|
||||
bool isOpen = RaffleState.OPEN == s_raffleState;
|
||||
bool timePassed = ((block.timestamp - s_lastTimeStamp) > i_interval);
|
||||
bool hasPlayers = s_players.length > 0;
|
||||
bool hasBalance = address(this).balance > 0;
|
||||
upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers);
|
||||
return (upkeepNeeded, "0x0"); // can we comment this out?
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Once `checkUpkeep` is returning `true`, this function is called
|
||||
* and it kicks off a Chainlink VRF call to get a random winner.
|
||||
*/
|
||||
function performUpkeep(bytes calldata /* performData */ ) external override {
|
||||
(bool upkeepNeeded,) = checkUpkeep("");
|
||||
// require(upkeepNeeded, "Upkeep not needed");
|
||||
if (!upkeepNeeded) {
|
||||
revert Raffle__UpkeepNotNeeded(address(this).balance, s_players.length, uint256(s_raffleState));
|
||||
}
|
||||
|
||||
s_raffleState = RaffleState.CALCULATING;
|
||||
|
||||
// Will revert if subscription is not set and funded.
|
||||
uint256 requestId = s_vrfCoordinator.requestRandomWords(
|
||||
VRFV2PlusClient.RandomWordsRequest({
|
||||
keyHash: i_gasLane,
|
||||
subId: i_subscriptionId,
|
||||
requestConfirmations: REQUEST_CONFIRMATIONS,
|
||||
callbackGasLimit: i_callbackGasLimit,
|
||||
numWords: NUM_WORDS,
|
||||
extraArgs: VRFV2PlusClient._argsToBytes(
|
||||
// Set nativePayment to true to pay for VRF requests with Sepolia ETH instead of LINK
|
||||
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
|
||||
)
|
||||
})
|
||||
);
|
||||
// Quiz... is this redundant?
|
||||
emit RequestedRaffleWinner(requestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev This is the function that Chainlink VRF node
|
||||
* calls to send the money to the random winner.
|
||||
*/
|
||||
function fulfillRandomWords(uint256, /* requestId */ uint256[] calldata randomWords) internal override {
|
||||
// s_players size 10
|
||||
// randomNumber 202
|
||||
// 202 % 10 ? what's doesn't divide evenly into 202?
|
||||
// 20 * 10 = 200
|
||||
// 2
|
||||
// 202 % 10 = 2
|
||||
uint256 indexOfWinner = randomWords[0] % s_players.length;
|
||||
address payable recentWinner = s_players[indexOfWinner];
|
||||
s_recentWinner = recentWinner;
|
||||
s_players = new address payable[](0);
|
||||
s_raffleState = RaffleState.OPEN;
|
||||
s_lastTimeStamp = block.timestamp;
|
||||
emit WinnerPicked(recentWinner);
|
||||
(bool success,) = recentWinner.call{value: address(this).balance}("");
|
||||
// require(success, "Transfer failed");
|
||||
if (!success) {
|
||||
revert Raffle__TransferFailed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter Functions
|
||||
*/
|
||||
function getRaffleState() public view returns (RaffleState) {
|
||||
return s_raffleState;
|
||||
}
|
||||
|
||||
function getNumWords() public pure returns (uint256) {
|
||||
return NUM_WORDS;
|
||||
}
|
||||
|
||||
function getRequestConfirmations() public pure returns (uint256) {
|
||||
return REQUEST_CONFIRMATIONS;
|
||||
}
|
||||
|
||||
function getRecentWinner() public view returns (address) {
|
||||
return s_recentWinner;
|
||||
}
|
||||
|
||||
function getPlayer(uint256 index) public view returns (address) {
|
||||
return s_players[index];
|
||||
}
|
||||
|
||||
function getLastTimeStamp() public view returns (uint256) {
|
||||
return s_lastTimeStamp;
|
||||
}
|
||||
|
||||
function getInterval() public view returns (uint256) {
|
||||
return i_interval;
|
||||
}
|
||||
|
||||
function getEntranceFee() public view returns (uint256) {
|
||||
return i_entranceFee;
|
||||
}
|
||||
|
||||
function getNumberOfPlayers() public view returns (uint256) {
|
||||
return s_players.length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract ExampleEvents {
|
||||
uint256 favoriteNumber;
|
||||
|
||||
event storedNumber(uint256 indexed oldNumber, uint256 indexed newNumber, uint256 addedNumber, address sender);
|
||||
|
||||
function store(uint256 _favoriteNumber) public {
|
||||
emit storedNumber(favoriteNumber, _favoriteNumber, _favoriteNumber + favoriteNumber, msg.sender);
|
||||
favoriteNumber = _favoriteNumber;
|
||||
}
|
||||
|
||||
function retrieve() public view returns (uint256) {
|
||||
return favoriteNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract ExampleModulo {
|
||||
function getModTen(uint256 number) external pure returns (uint256) {
|
||||
// 10 % 10 = 0
|
||||
// 10 % 9 = 1 (10 / 9 = 1.??)
|
||||
// 2 % 2 = 0. 3 % 2 = 1. 6 % 2 = 0. 7 % 2 = 1
|
||||
return number % 10;
|
||||
}
|
||||
|
||||
function getModTwo(uint256 number) external pure returns (uint256) {
|
||||
return number % 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract ExampleRevert {
|
||||
error ExampleRevert__Error();
|
||||
|
||||
function revertWithError() public pure {
|
||||
if (false) {
|
||||
revert ExampleRevert__Error();
|
||||
}
|
||||
}
|
||||
|
||||
function revertWithRequire() public pure {
|
||||
require(true, "ExampleRevert__Error");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user