// 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";
/**
* @title SecureLottery
* @notice A lottery contract using Chainlink VRF V2.5 for verifiable randomness
* @dev This is an example contract and should not be used in production without proper auditing
*/
contract SecureLottery is VRFConsumerBaseV2Plus {
// Chainlink VRF configuration
uint256 public s_subscriptionId;
bytes32 public keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; // Sepolia gas lane
uint32 public callbackGasLimit = 100000;
uint16 public requestConfirmations = 3;
uint32 public numWords = 1;
// Lottery state variables
uint256 public randomNumber;
address public winner;
mapping(uint256 => bool) public requestIds;
uint256 public lastRequestId;
// Events
event RandomnessRequested(uint256 requestId);
event WinnerSelected(address winner, uint256 randomNumber);
/**
* @param subscriptionId Chainlink VRF subscription ID
* @param vrfCoordinator Address of the VRF Coordinator contract
*/
constructor(
uint256 subscriptionId,
address vrfCoordinator
) VRFConsumerBaseV2Plus(vrfCoordinator) {
s_subscriptionId = subscriptionId;
}
/**
* @notice Request random number from Chainlink VRF
* @param useNativePayment Whether to pay in native tokens (true) or LINK (false)
* @return requestId The ID of the randomness request
*/
function requestRandomWinner(bool useNativePayment) external returns (uint256 requestId) {
// Request randomness from Chainlink VRF
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: keyHash,
subId: s_subscriptionId,
requestConfirmations: requestConfirmations,
callbackGasLimit: callbackGasLimit,
numWords: numWords,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({
nativePayment: useNativePayment
})
)
})
);
requestIds[requestId] = true;
lastRequestId = requestId;
emit RandomnessRequested(requestId);
return requestId;
}
/**
* @notice Callback function called by VRF Coordinator when randomness is fulfilled
* @param requestId The ID of the randomness request
* @param randomWords The random words generated by Chainlink VRF
*/
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
require(requestIds[requestId], "Request not found");
require(randomWords.length > 0, "Random words array is empty");
// Process the random value
randomNumber = randomWords[0] % 100; // Example: limit to 0-99 range
// Lottery winner selection logic would go here
// For example, if you have participants in an array:
// winner = participants[randomNumber % participants.length];
emit WinnerSelected(winner, randomNumber);
}
/**
* @notice Get the status of a VRF request
* @param requestId The ID of the randomness request
* @return exists Whether the request exists
*/
function getRequestStatus(uint256 requestId) external view returns (bool exists) {
return requestIds[requestId];
}
}
Post #1471
525