full-blockchain-solidity-course-py
full-blockchain-solidity-course-py copied to clipboard
Lesson 7: 'NoneType' object has no attribute 'address' (eth_usd_price_feed/vrf_coordinator related)
Hey folks,
I've been stuck on this for the last day and have checked all of my code against Patrick's code. The only other ticket I found for this issue, someone realized they spelled something wrong so if that's the case and someone finds it that would be very much appreciated and I would be stoked it was something that dumb on my end.
Here is the error:
File "brownie/_cli/run.py", line 49, in main
return_value, frame = run(
File "brownie/project/scripts.py", line 103, in run
return_value = f_locals[method_name](*args, **kwargs)
File "./scripts/deploy_lottery.py", line 20, in main
deploy_lottery()
File "./scripts/deploy_lottery.py", line 8, in deploy_lottery
get_contract("eth_usd_price_feed").address,
AttributeError: 'NoneType' object has no attribute 'address'
Terminating local RPC client...
liams-Air:smartcontract-lottery liambaynes$ ```
And my code:
```//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 randomness;
uint256 public usdEntryFee;
AggregatorV3Interface internal ethUsdPriceFeed;
enum LOTTERY_STATE {
OPEN,
CLOSED,
CALCULATING_WINNER
}
LOTTERY_STATE public lottery_state;
uint256 public fee;
bytes32 public keyhash;
constructor(
address _priceFeedAddress,
address _vrfCoordinator,
address _link,
uint256 _fee,
bytes32 _keyhash
) public VRFConsumerBase(_vrfCoordinator, _link) {
usdEntryFee = 50 * (10**18);
ethUsdPriceFeed = AggregatorV3Interface(_priceFeedAddress);
lottery_state = LOTTERY_STATE.CLOSED;
fee = _fee;
keyhash = _keyhash;
}
function enter() public payable {
require(lottery_state == LOTTERY_STATE.OPEN);
require(msg.value >= getEntranceFee(), "Not enough ETH!");
players.push(msg.sender);
}
function getEntranceFee() public view returns (uint256) {
(, int256 price, , , ) = ethUsdPriceFeed.latestRoundData();
uint256 adjustedPrice = uint256(price) * 10**10;
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 {
// uint256(
// keccack256(
// abi.encodePacked(
// nonce,
// msg.sender,
// block.difficulty,
// block.timestamp
// )
// )
// ) % players.length;
lottery_state = LOTTERY_STATE.CALCULATING_WINNER;
bytes32 requestId = requestRandomness(keyhash, fee);
}
function fulfillRandomness(bytes32 _requestId, uint256 _randomness)
internal
override
{
require(
lottery_state == LOTTERY_STATE.CALCULATING_WINNER,
"You aren't there yet!"
);
require(_randomness > 0, "random-not-found");
uint256 indexOfWinner = _randomness % players.length;
recentWinner = players[indexOfWinner];
recentWinner.transfer(address(this).balance);
players = new address payable[](0);
lottery_state = LOTTERY_STATE.CLOSED;
randomness = _randomness;
}
}```
```from scripts.helpful_scripts import get_account, get_contract
from brownie import Lottery, network, config
def deploy_lottery():
account = get_account()
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},
publish_source=config["networks"][network.show_active()].get("verify", False),
)
print("Deployed lottery!")
def main():
deploy_lottery()```
```from brownie import (
accounts,
network,
config,
MockV3Aggregator,
VRFCoordinatorMock,
LinkToken,
Contract,
)
FORKED_LOCAL_ENVIRONMENTS = ["mainnet-fork", "mainnet-fork-dev"]
LOCAL_BLOCKCHAIN_ENVIRONMENTS = ["development", "ganache-local"]
def get_account(index=None, id=None):
if index:
return accounts[index]
if id:
return accounts.load(id)
if (
network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS
or network.show_active() in FORKED_LOCAL_ENVIRONMENTS
):
return accounts[0]
return accounts.add(config["wallets"]["from_key"])
contract_to_mock = {
"eth_usd_price_feed": MockV3Aggregator,
"vrf_coordinator": VRFCoordinatorMock,
"link_token": LinkToken,
}
def get_contract(contract_name):
"""This function will grab the contract addresses from the brownie config
if defined, otherwise, it will deploy a mock version of that contract and
return that mock contract.
Args:
contract_name (string)
Returns:
brownie.network.contract.ProjectContract: The most recently deployed
version of this contract.
"""
contract_type = contract_to_mock[contract_name]
if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
if len(contract_type) <= 0:
# MockV3Aggregator.length
deploy_mocks()
contract = contract_type[-1]
else:
contract_address = config["networks"][network.show_active()]
[contract_name]
contract = Contract.from_abi(
contract_type._name, contract_address, contract_type.abi
)
return contract
DECIMALS = 8
INITIAL_VALUE = 200000000000
def deploy_mocks(decimals=DECIMALS, initial_value=INITIAL_VALUE):
account = get_account()
MockV3Aggregator.deploy(decimals, initial_value, {"from": account})
link_token = LinkToken.deploy({"from": account})
VRFCoordinatorMock.deploy(link_token.address, {"from": account})
print("Deployed!")```
```# 0.016
# 0.017
from brownie import Lottery, accounts, config, network
from web3 import Web3
def test_get_entrance_fee():
account = accounts[0]
lottery = Lottery.deploy(
config["networks"][network.show_active()]["eth_usd_price_feed"],
{"from": account},
)
# assert lottery.getEntranceFee() > Web3.toWei(0.016, "ether")
# assert lottery.getEntranceFee() < Web3.toWei(0.017, "ether")```
```dependencies:
- smartcontractkit/[email protected]
- OpenZeppelin/[email protected]
compiler:
solc:
remappings:
- '@chainlink=smartcontractkit/[email protected]'
- '@openzeppelin=OpenZeppelin/[email protected]'
dotenv: .env
networks:
default: development
development:
keyhash: '0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311'
fee: 100000000000000000
rinkeby:
vrf_coordinator: '0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B'
eth_usd_price_feed: '0x8A753747A1Fa494EC906cE90E9f37563A8AF630e'
link_token: '0x01BE23585060835E02B77ef475b0Cc51aA1e0709'
keyhash: '0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311'
fee: 100000000000000000
verify: True
mainnet-fork:
eth_usd_price_feed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'
wallets:
from_key: ${PRIVATE_KEY} ```
I saw that you added another tab space(by mistake probably) before the return contract
statement in get_contract()
which is probably resulting in errors since it returns the contract only if the else statement runs. Try remove that extra tab and make sure it is just below if and else, not within one of those. I hope this helps :)