add lottery the first half course

This commit is contained in:
han 2025-01-04 17:00:53 +07:00
parent 938ea14d44
commit b6fb56fd2c
4 changed files with 137 additions and 10 deletions

6
.gitmodules vendored
View File

@ -28,3 +28,9 @@
[submodule "lottery/lib/forge-std"] [submodule "lottery/lib/forge-std"]
path = lottery/lib/forge-std path = lottery/lib/forge-std
url = https://github.com/foundry-rs/forge-std url = https://github.com/foundry-rs/forge-std
[submodule "lottery/lib/chainlink"]
path = lottery/lib/chainlink
url = https://github.com/smartcontractkit/chainlink
[submodule "lottery/lib/chainlink-brownie-contracts"]
path = lottery/lib/chainlink-brownie-contracts
url = https://github.com/smartcontractkit/chainlink-brownie-contracts

View File

@ -2,5 +2,6 @@
src = "src" src = "src"
out = "out" out = "out"
libs = ["lib"] libs = ["lib"]
remappings = ['@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/']
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

@ -0,0 +1 @@
Subproject commit 12393bd475bd60c222ff12e75c0f68effe1bbaaf

View File

@ -22,26 +22,145 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE // SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.19; 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";
/** /**
* @title A sample Raffle contract * @title A sample Raffle contract
* @author hirugohan * @author hirugohan
* @notice This contract is for creating a sample raffle * @notice This contract is for creating a sample raffle
* @dev Implements Chainlink VRFv2.5 * @dev Implements Chainlink VRFv2.5
*/ */
contract Raffle { contract Raffle is VRFConsumerBaseV2Plus {
/* Errors */
error Raffle__SendMoreToEnterRaffle();
error Raffle__TransferFailed();
error Raffle__RaffleNotOpen();
error Raffle__UpkeepNotNeeded(uint256 balance, uint256 playersLength, uint256 raffleState);
/* Type Declarations */
enum RaffleState {
OPEN, // 0
CALCULATING // 1
}
/* State Variables */
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;
uint256 private immutable i_entranceFee; uint256 private immutable i_entranceFee;
// @dev The duration of the lottery in seconds
uint256 private immutable i_interval;
bytes32 private immutable i_keyHash;
uint256 private immutable i_subscriptionId;
uint32 private immutable i_callbackGasLimit;
address payable[] private s_players;
uint256 private s_lastTimeStamp;
address private s_recentWinner;
RaffleState private s_raffleState;
constructor (uint256 entranceFee) { /* Events */
event RaffleEntered(address indexed player);
event WinnerPicked(address indexed winner);
constructor(
uint256 entranceFee,
uint256 interval,
address vrfCoordinator,
bytes32 gasLane,
uint256 subscriptionId,
uint32 callbackGasLimit
) VRFConsumerBaseV2Plus(vrfCoordinator) {
i_entranceFee = entranceFee; i_entranceFee = entranceFee;
i_interval = interval;
i_keyHash = gasLane;
i_subscriptionId = subscriptionId;
i_callbackGasLimit = callbackGasLimit;
s_lastTimeStamp = block.timestamp;
s_raffleState = RaffleState.OPEN;
} }
function enterRaffle() public payable { function enterRaffle() external payable {
require(msg.value >= i_entranceFee, "Not enough ETH sent!"); // require(msg.value >= i_entranceFee, "Not enough ETH sent!");
if (msg.value < i_entranceFee) {
revert Raffle__SendMoreToEnterRaffle();
}
if (s_raffleState != RaffleState.OPEN) {
revert Raffle__RaffleNotOpen();
} }
function pickWinner() public {} // require(msg.value >= i_entranceFee, SendMoreToEnterRaffle());
s_players.push(payable(msg.sender));
emit RaffleEntered(msg.sender);
}
/** Getter Functions */ /**
* @dev This is a function that chainlink nodes will call to see
* if the lottery is ready to have a winner picked.
* The following should be true in order for upkeepNeeded to be true:
* 1. The time interval has passed between raffle runes
* 2. The lottery is open
* 3. The contract has ETH (has players)
* 4. Implicitly, your subscription has LINK
* @param - ignored
* @return upkeepNeeded - true if it's time to restart the lottery
* @return - ignored
*/
function checkUpkeep(bytes memory /* checkData */ )
public
view
returns (bool upkeepNeeded, bytes memory /* performData */ )
{
bool timeHasPassed = ((block.timestamp - s_lastTimeStamp) >= i_interval);
bool isOpen = s_raffleState == RaffleState.OPEN;
bool hasBalance = address(this).balance > 0;
bool hasPlayers = s_players.length > 0;
upkeepNeeded = timeHasPassed && isOpen && hasBalance && hasPlayers;
return (upkeepNeeded, "");
}
function performUpkeep(bytes calldata /* performData */) external {
(bool upkeepNeeded, ) = checkUpkeep("");
if (!upkeepNeeded) {
revert Raffle__UpkeepNotNeeded(address(this).balance, s_players.length, uint256(s_raffleState));
}
s_raffleState = RaffleState.CALCULATING;
VRFV2PlusClient.RandomWordsRequest memory request = VRFV2PlusClient.RandomWordsRequest({
keyHash: i_keyHash,
subId: i_subscriptionId,
requestConfirmations: REQUEST_CONFIRMATIONS,
callbackGasLimit: i_callbackGasLimit,
numWords: NUM_WORDS,
extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false}))
});
s_vrfCoordinator.requestRandomWords(request);
}
// CEI: Check, Effects, Interactions Pattern
function fulfillRandomWords(uint256 /* requestId */, uint256[] calldata randomWords) internal virtual override {
// Checks: check values before executing function
// Effect (Internal Contract State)
uint256 indexOfWinner = randomWords[0] % s_players.length;
address payable recentWinner = s_players[indexOfWinner];
s_recentWinner = recentWinner;
s_raffleState = RaffleState.OPEN;
s_players = new address payable[](0);
s_lastTimeStamp = block.timestamp;
emit WinnerPicked(s_recentWinner);
// Interactions (External Contract Interactions)
(bool success,) = recentWinner.call{value: address(this).balance}("");
if (!success) {
revert Raffle__TransferFailed();
}
}
/**
* Getter Functions
*/
function getEntranceFee() external view returns (uint256) { function getEntranceFee() external view returns (uint256) {
return i_entranceFee; return i_entranceFee;
} }