// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; /** * * @notice Interface for contracts using VRF randomness through the VRF V2 wrapper * ******************************************************************************** * @dev PURPOSE * * @dev Create VRF V2+ requests without the need for subscription management. Rather than creating * @dev and funding a VRF V2+ subscription, a user can use this wrapper to create one off requests, * @dev paying up front rather than at fulfillment. * * @dev Since the price is determined using the gas price of the request transaction rather than * @dev the fulfillment transaction, the wrapper charges an additional premium on callback gas * @dev usage, in addition to some extra overhead costs associated with the VRFV2Wrapper contract. * ***************************************************************************** * @dev USAGE * * @dev Calling contracts must inherit from VRFV2PlusWrapperConsumerBase. The consumer must be funded * @dev with enough LINK or ether to make the request, otherwise requests will revert. To request randomness, * @dev call the 'requestRandomWords' function with the desired VRF parameters. This function handles * @dev paying for the request based on the current pricing. * * @dev Consumers must implement the fullfillRandomWords function, which will be called during * @dev fulfillment with the randomness result. */ abstract contract VRFV2PlusWrapperConsumerBase { error OnlyVRFWrapperCanFulfill(address have, address want); LinkTokenInterface internal immutable i_linkToken; IVRFV2PlusWrapper public immutable i_vrfV2PlusWrapper; /** * @param _vrfV2PlusWrapper is the address of the VRFV2Wrapper contract */ constructor(address _vrfV2PlusWrapper) { IVRFV2PlusWrapper vrfV2PlusWrapper = IVRFV2PlusWrapper(_vrfV2PlusWrapper); i_linkToken = LinkTokenInterface(vrfV2PlusWrapper.link()); i_vrfV2PlusWrapper = vrfV2PlusWrapper; } /** * @dev Requests randomness from the VRF V2+ wrapper. * * @param _callbackGasLimit is the gas limit that should be used when calling the consumer's * fulfillRandomWords function. * @param _requestConfirmations is the number of confirmations to wait before fulfilling the * request. A higher number of confirmations increases security by reducing the likelihood * that a chain re-org changes a published randomness outcome. * @param _numWords is the number of random words to request. * * @return requestId is the VRF V2+ request ID of the newly created randomness request. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomness( uint32 _callbackGasLimit, uint16 _requestConfirmations, uint32 _numWords, bytes memory extraArgs ) internal returns (uint256 requestId, uint256 reqPrice) { reqPrice = i_vrfV2PlusWrapper.calculateRequestPrice(_callbackGasLimit, _numWords); i_linkToken.transferAndCall( address(i_vrfV2PlusWrapper), reqPrice, abi.encode(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs) ); return (i_vrfV2PlusWrapper.lastRequestId(), reqPrice); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomnessPayInNative( uint32 _callbackGasLimit, uint16 _requestConfirmations, uint32 _numWords, bytes memory extraArgs ) internal returns (uint256 requestId, uint256 requestPrice) { requestPrice = i_vrfV2PlusWrapper.calculateRequestPriceNative(_callbackGasLimit, _numWords); return ( i_vrfV2PlusWrapper.requestRandomWordsInNative{value: requestPrice}( _callbackGasLimit, _requestConfirmations, _numWords, extraArgs ), requestPrice ); } /** * @notice fulfillRandomWords handles the VRF V2 wrapper response. The consuming contract must * @notice implement it. * * @param _requestId is the VRF V2 request ID. * @param _randomWords is the randomness result. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal virtual; function rawFulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) external { address vrfWrapperAddr = address(i_vrfV2PlusWrapper); if (msg.sender != vrfWrapperAddr) { revert OnlyVRFWrapperCanFulfill(msg.sender, vrfWrapperAddr); } fulfillRandomWords(_requestId, _randomWords); } /// @notice getBalance returns the native balance of the consumer contract function getBalance() public view returns (uint256) { return address(this).balance; } /// @notice getLinkToken returns the link token contract function getLinkToken() public view returns (LinkTokenInterface) { return i_linkToken; } }