0

i have my simple contract for a lottery system

/**
 * @title Lottery
 * @notice Enter lottery by paying some amount
 * @notice pick a random number( verifiably random)
 * @notice winner be selected every xtimes
 */

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/interfaces/KeeperCompatibleInterface.sol";

// ============= Errors ====================
error Lottery__NotEnoughFunds();
error Lottery__TransferFailed();
error Lottery__NotOpen();
error Raffle__UpkeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 raffleState);

/**
 * @title A sample Lottery Contract
 * @author 
 * @notice This contract is for creating a decentralised lottery smart contract
 * @dev This implements Chainlink VRF V@ and Cahinlink Keepers
 */
contract Lottery is VRFConsumerBaseV2, KeeperCompatibleInterface {
    //  ============= Type declaration ===========
    enum LotteryState {
        OPEN, 
        CALCULATING
    }
    // ======== state variables ============
    uint256 private immutable i_entranceFee;
    address payable[] private s_players;
    bytes32 private immutable i_gasLane;
    uint64 private immutable i_subscriptionId;
    uint32 private immutable i_callbackGasLimit;
    uint16 private constant REQUEST_CONFIRMATION = 3;
    uint32 private constant NUM_WORDS = 1;
    VRFCoordinatorV2Interface private immutable i_vrfCoordinator;

    address private s_recentwinner;
    LotteryState private s_lotteryState;
    uint256 private s_lastTimeStamp;
    uint256 private immutable i_interval;
   

    // ========== Events ==================
    event LotteryEnter(address indexed player);
    event RandomwinnerRequest(uint256 indexed requestId);
    event WinnerPicked(address indexed winner);


    // ========= constructor ============
    constructor(
        address vrfCoordinatorV2,
        uint256 entranceFee,
        uint32 callbackGasLimit,
        uint256 interval,
        bytes32 gasLane,
        uint64 subscriptionId
    ) VRFConsumerBaseV2(vrfCoordinatorV2) {
        i_entranceFee = entranceFee;
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
        i_gasLane = gasLane;
        i_subscriptionId = subscriptionId;
        i_callbackGasLimit = callbackGasLimit;
        s_lotteryState = LotteryState.OPEN;
        i_interval = interval;
        s_lastTimeStamp = block.timestamp;
    }

    //   ========== functions ============
    function enterLottery() public payable {
        if (msg.value < i_entranceFee) {
            revert Lottery__NotEnoughFunds();
        }
        if (s_lotteryState != LotteryState.OPEN ) {
            revert Lottery__NotOpen();
        }

        s_players.push(payable(msg.sender));
        emit LotteryEnter(msg.sender);
    }

   
    function checkUpkeep(
        bytes memory /* checkData */
    )
        public
        view
        override
        returns (
            bool upkeepNeeded,
            bytes memory /* performData */
        )
    {
        bool isOpen = LotteryState.OPEN == s_lotteryState;
        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?
    }

    function performUpkeep( bytes calldata /* performData */) external override {

        ( bool upKeepNeeded, ) = checkUpkeep("");

        if(!upKeepNeeded){
             revert Raffle__UpkeepNotNeeded(
                address(this).balance,
                s_players.length,
                uint256(s_lotteryState)
            );
        }
        //  Request a random number
        // Once we get it , do something with it
        s_lotteryState = LotteryState.CALCULATING;
        uint256 requestId = i_vrfCoordinator.requestRandomWords(
            i_gasLane,
            i_subscriptionId,
            REQUEST_CONFIRMATION,
            i_callbackGasLimit,
            NUM_WORDS
        );
        emit RandomwinnerRequest(requestId);
    }

    function fulfillRandomWords(uint256 /*requestId*/, uint256[] memory randomWords) internal override {
        // Modulo function
        uint256 winnerIndex = randomWords[0] % s_players.length;
        address payable recentWinner = s_players[winnerIndex];
        s_recentwinner = recentWinner;
        s_lotteryState = LotteryState.OPEN;
        s_players = new address payable[](0);
        s_lastTimeStamp = block.timestamp;
        (bool success, ) = recentWinner.call{value: address(this).balance}("");
        if (!success) {
            revert Lottery__TransferFailed();
        }
        emit WinnerPicked(recentWinner);
    }

    // =============== View /Pure functions =============
    function getEntraceFee() public view returns (uint256) {
        return i_entranceFee;
    }

    function getPlayers(uint256 index) public view returns (address) {
        return s_players[index];
    }

    function getRecentWinner() public view returns (address) {
        return s_recentwinner;
    }
     function getRaffleState() public view returns (LotteryState) {
        return s_lotteryState;
    }

    function getNumWords() public pure returns (uint256) {
        return NUM_WORDS;
    }

    function getRequestConfirmations() public pure returns (uint256) {
        return REQUEST_CONFIRMATION;
    }
    function getLastTimeStamp() public view returns (uint256) {
        return s_lastTimeStamp;
    }

    function getInterval() public view returns (uint256) {
        return i_interval;
    }
    function getNumberOfPlayers() public view returns (uint256) {
        return s_players.length;
    }
}

the deploy script

const { network, ethers } = require("hardhat");
const {
  developmentChains,
  networkConfig,
  VERIFICATION_BLOCK_CONFIRMATIONS,
} = require("../helper-hardhat-config");
const { verify } = require("../utils/verify");

const VR_FUND_AMOUNT = ethers.utils.parseEther("4");

module.exports = async function ({ getNamedAccounts, deployments }) {
  const { deploy, log } = deployments;
  const { deployer } = await getNamedAccounts();
  const chainId = network.config.chainId;
  let vrfCoordinatorV2Address, subscriptionId;

  if (developmentChains.includes(network.name)) {
    const vrfCoordinatorV2Mock = await ethers.getContract(
      "VRFCoordinatorV2Mock"
    );
    vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address;
    const transactionResponse = await vrfCoordinatorV2Mock.createSubscription();
    const transactionReceipt = await transactionResponse.wait(1);
    subscriptionId = transactionReceipt.events[0].args.subId;
    // fund the subscription
    await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, VR_FUND_AMOUNT);
  } else {
    vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinatorV2"];
    subscriptionId = networkConfig[chainId]["subscriptionId"];
  }

  const entranceFee = networkConfig[chainId]["entranceFee"];
  const gasLane = networkConfig[chainId]["gasLane"];
  const callbackGasLimit = networkConfig[chainId]["callbackGasLimit"];
  const interval = networkConfig[chainId]["interval"];
  const args = [
    vrfCoordinatorV2Address,
    entranceFee,
    gasLane,
    subscriptionId,
    callbackGasLimit,
    interval,
  ];
  const lottery = await deploy("Lottery", {
    from: deployer,
    args: args,
    log: true,
    waitConfirmations: network.config.blockConfirmations || 1,
  });

  if (
    !developmentChains.includes(network.name) &&
    process.env.ETHERSCAN_API_KEY
  ) {
    log("Verifying.....");
    await verify(lottery.address, args);
  }
  log("-----------------------------------");
};

module.exports.tags = ["all", "lottery"];

the mock deploy script

const { network } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")


const BASE_FEE = ethers.utils.parseEther("0.25") // 0.25 is this the premium in LINK?
const GAS_PRICE_LINK = 1e9 // link per gas, is this the gas lane? // 0.000000001 LINK per gas

module.exports = async function ({ getNamedAccounts, deployments })  {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId
    const args =[BASE_FEE, GAS_PRICE_LINK]
    // If we are on a local development network, we need to deploy mocks!

    if(developmentChains.includes(network.name)){
        log("Local Network Detected! Deploying mocks...")
        // deploy a mock vrfCoordinator
        await deploy("VRFCoordinatorV2Mock",{
            from:deployer,
            log:true,
            args:args,
        })
        log("Mocks Deployed!")
        log("------------------------------------------")
    }
    
}
module.exports.tags = ["all", "mocks"]

helper config

const { ethers } = require("hardhat")

const networkConfig = {
    5:{
        name:"goerli",
        vrfCoordinatorV2:"0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D",
        entranceFee: ethers.utils.parseEther("0.01"),
        gasLane:"0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
        subscriptionId:"0",
        callbackGasLimit:"500000",
        interval:"30"
    },
    31337:{
        name:"hardhat",
        entranceFee: ethers.utils.parseEther("0.01"),
        callbackGasLimit:"500000",
        gasLane:"0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
        interval:"30"
    }
}

const developmentChains = ["hardhat", "localhost"]
module.exports = {
    networkConfig,
    developmentChains
}

when i run yarn hardhat deploy i experience an error

Local Network Detected! Deploying mocks...
deploying "VRFCoordinatorV2Mock" (tx: 0x12925340c9bd03dbda39b85b0c207149c2bc46f19e3a0c825e92642eb0713167)...: deployed at 0x5FbDB2315678afecb367f032d93F642f64180aa3 with 2539340 gas
Mocks Deployed!
------------------------------------------
An unexpected error occurred:

Error: ERROR processing C:\Users\amoko\Desktop\blockchain\lottery\deploy\01-deploy-lottery.js:
Error: value out-of-bounds (argument="callbackGasLimit", value="0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15", code=INVALID_ARGUMENT, version=abi/5.7.0)
    at Logger.makeError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\logger\src.ts\index.ts:269:28)
    at Logger.throwError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\logger\src.ts\index.ts:281:20)
    at Logger.throwArgumentError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\logger\src.ts\index.ts:285:21)
    at NumberCoder.Coder._throwError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\coders\abstract-coder.ts:68:16)
    at NumberCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\coders\number.ts:35:18)
    at C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\coders\array.ts:71:19
    at Array.forEach (<anonymous>)
    at pack (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\coders\array.ts:54:12)
    at TupleCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\coders\tuple.ts:54:20)
    at AbiCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\@ethersproject\abi\src.ts\abi-coder.ts:111:15)
    at DeploymentsManager.executeDeployScripts (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\DeploymentsManager.ts:1222:19)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at runNextTicks (node:internal/process/task_queues:65:3)
    at listOnTimeout (node:internal/timers:528:9)
    at processTimers (node:internal/timers:502:7)
    at DeploymentsManager.runDeploy (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\DeploymentsManager.ts:1052:5)
    at SimpleTaskDefinition.action (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\index.ts:438:5)
    at Environment._runTaskDefinition (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat\src\internal\core\runtime-environment.ts:308:14)
    at Environment.run (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat\src\internal\core\runtime-environment.ts:156:14)
    at SimpleTaskDefinition.action (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\index.ts:584:32)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.```
i need help on this
0

2 Answers 2

1

This answer relates to Patrick Collins' Freecodecamp course on Solidity, as I believe the question also relates to this course.

For me, the issue was having the gasLimit variable be a uint32. Instead, I had to change it to a uint256.

However, this creates a different error in the function i_vrfCoordinator.requestRandomWords. To alleviate that error, you cast the i_callbackGasLimit as a uint32 as follows:

uint256 requestId = i_vrfCoordinator.requestRandomWords(
  i_gasLane,
  i_subscriptionId,
  REQUEST_CONFIRMATIONS,
  uint32(i_callbackGasLimit),
  NUM_WORDS
);

I don't know if this is the most elegant solution, but this should silence any errors and allow you to deploy your contracts.

0

Scott's answer is correct - it worked for me as well - kudos to him!

However, you don't have to use uint256. You use uint64 and it will still work.

uint64 private immutable i_callbackGasLimit;

And you can still downcast it to uint32:

uint256 requestId = i_vrfCoordinator.requestRandomWords(
  i_gasLane,
  i_subscriptionId,
  REQUEST_CONFIRMATIONS,
  uint32(i_callbackGasLimit),
  NUM_WORDS
);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.