PatrickAlphaC / smartcontract-lottery

MIT License
79 stars 113 forks source link

0x0000000000000000000000000000000000000000 is the new winner (ganache & rinkeby) #69

Closed Aviksaikat closed 2 years ago

Aviksaikat commented 2 years ago

@PatrickAlphaC sorry for the ping but have you added new examples? Yesterday I was following the video & added the waiting time of 60 sec & the tests ran successfully. Funny thing when I'm trying to run the script today it's giving me the winner is 0x0000000000000000000000000000000000000000 both in ganache & in rinkeby. This time I increased the waiting time to 180 & added some extra fees still the same. I checked the returned random value & it's 0. So the chainlink node is not returning a random value maybe. here is my Lottery.sol

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

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";

contract Lottery is VRFConsumerBase, Ownable {
    address payable[] public players;
    address payable public recentWinner;
    uint256 public usdEntryFee;
    uint256 public randomness;
    AggregatorV3Interface internal ethUsdPriceFeed;
    enum LOTTERY_STATE {
        OPEN, //? 0
        CLOSED, //? 1
        CALCULATING_WINNER //? 2
    }
    LOTTERY_STATE public lottery_state;
    uint256 public fee;
    bytes32 public keyHash;
    event RequestedRandomness(bytes32 requestId);

    /** from documentation
        https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/VRFConsumerBase.sol
    */
    constructor(
        address _priceFeedAddress,
        address _vrfCoordinator,
        address _link,
        uint256 _fee,
        bytes32 _keyhash
    ) public VRFConsumerBase(_vrfCoordinator, _link) {
        //? convert the usd to Gewi
        usdEntryFee = 50 * (10**18);
        ethUsdPriceFeed = AggregatorV3Interface(_priceFeedAddress);

        //* same as lottery_state = 1;
        lottery_state = LOTTERY_STATE.CLOSED;
        fee = _fee;
        keyHash = _keyhash;
    }

    function enter() public payable {
        require(lottery_state == LOTTERY_STATE.OPEN);
        //? $50 min
        require(msg.value >= getEntranceFee(), "Not Enough ETH");
        players.push(msg.sender);
    }

    function getEntranceFee() public view returns (uint256) {
        // https://docs.chain.link/docs/get-the-latest-price/
        (, int256 price, , , ) = ethUsdPriceFeed.latestRoundData();
        //? as EHT/USD price feed is 8 decimals
        uint256 adjustedPrice = uint256(price) * 10**10;
        //? for setting the pice & 50$
        //* $50, $2,000 / ETH
        //* 50/2,000
        //* 50 * 100000 / 20000
        uint256 costToEnter = (usdEntryFee * 10**18) / adjustedPrice;
        return costToEnter;
    }

    function startLottery() public onlyOwner {
        require(
            lottery_state == LOTTERY_STATE.CLOSED,
            "Can't start a new lottery yet!"
        );
        lottery_state = LOTTERY_STATE.OPEN;
    }

    function endLottery() public onlyOwner {
        lottery_state = LOTTERY_STATE.CALCULATING_WINNER;

        //? request the data from chainlink oracle
        bytes32 requestId = requestRandomness(keyHash, fee);
        emit RequestedRandomness(requestId);
    }

    //? override to over write the fulfillRandomness fn.
    function fulfillRandomness(bytes32 _requestId, uint256 _randomness)
        internal
        override
    {
        require(
            lottery_state == LOTTERY_STATE.CALCULATING_WINNER,
            "You aren't there yet!!"
        );
        require(_randomness > 0, "randomness not found!!");
        uint256 indexOfWinner = _randomness % players.length;
        recentWinner = players[indexOfWinner];

        //? pay all the money collected from the entry fee to the winner
        recentWinner.transfer(address(this).balance);
        //? Reset
        players = new address payable[](0);
        lottery_state = LOTTERY_STATE.CLOSED;
        //? keeping track of the randomness variable value
        randomness = _randomness;
    }
}

#!C:\Users\avik\AppData\Local\Programs\Python\Python39\python.exe
from scripts.helpful_scripts import get_account, get_contract, fund_with_link
from brownie import Lottery, config, network
from time import sleep

def deploy_lottrey():
    account = get_account()
    """ 
        have to pass these parameter to deploy the lottery
        constructor(
        address _priceFeedAddress,
        address _vrfCoordinator,
        address _link,
        uint256 _fee,
        bytes32 _keyhash
    )
    """
    lottery = Lottery.deploy(
        get_contract("eth_usd_price_feed").address,
        get_contract("vrf_coordinator").address,
        get_contract("link_token").address,
        config["networks"][network.show_active()]["fee"],
        config["networks"][network.show_active()]["keyhash"],
        {"from": account},
        # ? get the verify key from config, else default to false
        publish_source=config["networks"][network.show_active()].get("verify", False),
    )
    print("Yah!! Lottery Deployed!!")
    return lottery

#! just my own helper fn. Don't want to do the same thing over & over again
def get_lottery():
    """
    account = get_account()
    lottery = Lottery[-1]
    """
    return Lottery[-1], get_account()

def start_lottery():
    lottery, account = get_lottery()
    starting_tx = lottery.startLottery({"from": account})
    starting_tx.wait(1)
    print("The lottery has started!!")

def enter_lottery():
    lottery, account = get_lottery()
    value = lottery.getEntranceFee() + 100000000
    # try:
    #     tx = lottery.enter({"from": account, "value": value})
    #     tx.wait(1)
    #     print("You entered the lottery!")
    # except ValueError as err:
    #     print(f"Unexpected {err=}, {type(err)=}")
    tx = lottery.enter({"from": account, "value": value})
    tx.wait(1)
    print("You entered the lottery!")

def end_lottery():
    lottery, account = get_lottery()

    # ? first fund the contract then end the lottery
    tx = fund_with_link(lottery.address)
    tx.wait(1)
    ending_tx = lottery.endLottery({"from": account})
    ending_tx.wait(1)
    # * wait for the ChainLink node to return the random number
    sleep(180)
    print(f"{lottery.recentWinner()} is the new winner")

def main():
    deploy_lottrey()
    start_lottery()
    enter_lottery()
    end_lottery()
DavBE commented 2 years ago

Hi,

I ran into the same issue, turned out the chainlink node takes quite some time to return the random number.

Maybe you could try to wait longer in :

sleep(180)

Aviksaikat commented 2 years ago

yah I'm waiting 180 secs

achimstruve commented 2 years ago

I changed the sleep time to 240 and then it worked. 60 seconds is too less.

PatrickAlphaC commented 2 years ago

Awesome!!