Error implementing chainlink VRF in Raffle contract. [course : Foundry Fundamentals , Section : 4 Smart contract lottery ] #3632
-
Hey, i really need you guys' help. This error has been troubling me for a while now, i tried to fix it but couldn't , AI tried to fix it but is stuck without a solution. HELP ME! THE ERROR THE PART OF Raffle.sol WHERE THE ERROR IS SHOWN uint256 requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: i_keyHash, //gas limit
subId: i_subscriptionId,
requestConfirmations: REQUEST_CONFIRMATIONS,
callbackGasLimit: i_callbackGasLimit, // gas limit
numWords: NUM_WORDS,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
); Raffle.sol //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/dev/vrf/libraries/VRFV2PlusClient.sol";
/**
* @title A smart contract lottery raffle system.
* @author Avinesh
* @notice This contract is for creating a raffle.
* @dev Implements Chainlink VRF.
*/
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,
CALCULATING
}
/* State variables */
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;
uint256 private immutable i_entranceFee;
bytes32 private immutable i_keyHash;
uint256 private immutable i_subscriptionId;
uint32 private immutable i_callbackGasLimit;
uint256 private immutable i_interval;
address payable[] private s_players;
uint256 private s_lastTimeStamp;
address private s_recentWinner;
RaffleState private s_rafflestate;
/*Events*/
event RaffleEntered(address indexed player);
event WinnerPicked(address indexed winner);
constructor(
uint256 entranceFee,
uint256 interval,
address vrfCoordinator,
bytes32 gasLane,
uint256 subscriptionId,
uint16 requestconfirmations,
uint32 callbackGasLimit
) VRFConsumerBaseV2Plus(vrfCoordinator) {
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() external payable {
if (msg.value < i_entranceFee) {
revert Raffle__SendMoretoEnterRaffle();
}
if (s_rafflestate != RaffleState.OPEN) {
revert Raffle__RaffleNotOpen();
}
s_players.push(payable(msg.sender));
emit RaffleEntered(msg.sender);
}
//when shoud the winner be picked ?
/**
* @dev this is the function that the chainlink nodes will call to see,
* if the lottery is ready to be picked.
* the following should be true for upkeepNeeded to be true:
* 1. the time interval has passed between raffle runs,
* 2. the lottery is open.
* 3. contract has balance.
* 4. implicitly, your subscription should have ETH.
* @param -ignored
* @return upkeepNeeded - true if its time to start 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;
uint256 requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: i_keyHash, //gas limit
subId: i_subscriptionId,
requestConfirmations: REQUEST_CONFIRMATIONS,
callbackGasLimit: i_callbackGasLimit, // gas limit
numWords: NUM_WORDS,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
);
}
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
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);
(bool success, ) = recentWinner.call{value: address(this).balance}("");
if (!success) {
revert Raffle__TransferFailed();
}
}
//getter functions
function getEntranceFee() external view returns (uint256) {
return i_entranceFee;
}
} other connected contracts, libraries and interface // SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {IVRFCoordinatorV2Plus} from "./interfaces/IVRFCoordinatorV2Plus.sol";
import {IVRFMigratableConsumerV2Plus} from "./interfaces/IVRFMigratableConsumerV2Plus.sol";
import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, ConfirmedOwner {
error OnlyCoordinatorCanFulfill(address have, address want);
error OnlyOwnerOrCoordinator(address have, address owner, address coordinator);
error ZeroAddress();
// s_vrfCoordinator should be used by consumers to make requests to vrfCoordinator
// so that coordinator reference is updated after migration
IVRFCoordinatorV2Plus public s_vrfCoordinator;
/**
* @param _vrfCoordinator address of VRFCoordinator contract
*/
constructor(address _vrfCoordinator) ConfirmedOwner(msg.sender) {
if (_vrfCoordinator == address(0)) {
revert ZeroAddress();
}
s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator);
}
/**
* @notice fulfillRandomness handles the VRF response. Your contract must
* @notice implement it. See "SECURITY CONSIDERATIONS" above for important
* @notice principles to keep in mind when implementing your fulfillRandomness
* @notice method.
*
* @dev VRFConsumerBaseV2Plus expects its subcontracts to have a method with this
* @dev signature, and will call it once it has verified the proof
* @dev associated with the randomness. (It is triggered via a call to
* @dev rawFulfillRandomness, below.)
*
* @param requestId The Id initially returned by requestRandomness
* @param randomWords the VRF output expanded to the requested number of words
*/
// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal virtual;
// rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
// proof. rawFulfillRandomness then calls fulfillRandomness, after validating
// the origin of the call
function rawFulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external {
if (msg.sender != address(s_vrfCoordinator)) {
revert OnlyCoordinatorCanFulfill(msg.sender, address(s_vrfCoordinator));
}
fulfillRandomWords(requestId, randomWords);
}
/**
* @inheritdoc IVRFMigratableConsumerV2Plus
*/
function setCoordinator(address _vrfCoordinator) external override onlyOwnerOrCoordinator {
if (_vrfCoordinator == address(0)) {
revert ZeroAddress();
}
s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator);
emit CoordinatorSet(_vrfCoordinator);
}
modifier onlyOwnerOrCoordinator() {
if (msg.sender != owner() && msg.sender != address(s_vrfCoordinator)) {
revert OnlyOwnerOrCoordinator(msg.sender, owner(), address(s_vrfCoordinator));
}
_;
}
} IVRFCoordinatorV2Plus.sol // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { VRFV2PlusClient } from "../libraries/VRFV2PlusClient.sol";
import { IVRFSubscriptionV2Plus } from "./IVRFSubscriptionV2Plus.sol";
// Interface that enables consumers of VRFCoordinatorV2Plus to be future-proof for upgrades
// This interface is supported by subsequent versions of VRFCoordinatorV2Plus
interface IVRFCoordinatorV2Plus is IVRFSubscriptionV2Plus {
function requestRandomWords(VRFV2PlusClient.RandomWordsRequest calldata req) external returns (uint256 requestId);
} VRFV2PlusClient.sol: // SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
// End consumer library.
library VRFV2PlusClient {
// extraArgs will evolve to support new features
bytes4 public constant EXTRA_ARGS_V1_TAG = bytes4(keccak256("VRF ExtraArgsV1"));
struct ExtraArgsV1 {
bool nativePayment;
}
struct RandomWordsRequest {
bytes32 keyHash;
uint256 subId;
uint16 requestConfirmations;
uint32 callbackGasLimit;
uint32 numWords;
bytes extraArgs;
}
function _argsToBytes(ExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EXTRA_ARGS_V1_TAG, extraArgs);
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
Hello @Avinesh-Git, Let's try to resolve this. Use this import |
Beta Was this translation helpful? Give feedback.
I want to remind you that you need to properly point to the location of
VRFV2PlusClient
inside of yourRaffle
file. For me instead of the path to be this "../libraries/VRFV2PlusClient.sol"; it is insteadlib/chainlink-brownie-contracts/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol
.