Hello, I'm in the deploy Lottery part of @PatrickAlphaC 's video and after giving the constructor all the parameters such as fee, keyhash and link token, when I'm trying to run my deploy_lottery.py contract I get this error:
ImportError: cannot import name 'LinkToken' from 'brownie'
which I think the problem is from the LinkToken.sol solidity version, but i couldn't solve it even when I changed my python version or solidity global version
I even checked the directory and replaced the file with the file I downloaded from the github repository.
could anyone tell what seems to be the problem?
LinkToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.4.11;
import "@chainlink/contracts/src/v0.4/ERC677Token.sol";
import {StandardToken as linkStandardToken} from "@chainlink/contracts/src/v0.4/vendor/StandardToken.sol";
contract LinkToken is linkStandardToken, ERC677Token {
uint256 public constant totalSupply = 10**27;
string public constant name = "ChainLink Token";
uint8 public constant decimals = 18;
string public constant symbol = "LINK";
function LinkToken() public {
balances[msg.sender] = totalSupply;
}
/**
* @dev transfer token to a specified address with additional data if the recipient is a contract.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
* @param _data The extra data to be passed to the receiving contract.
*/
function transferAndCall(
address _to,
uint256 _value,
bytes _data
) public validRecipient(_to) returns (bool success) {
return super.transferAndCall(_to, _value, _data);
}
/**
* @dev transfer token to a specified address.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value)
public
validRecipient(_to)
returns (bool success)
{
return super.transfer(_to, _value);
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value)
public
validRecipient(_spender)
returns (bool)
{
return super.approve(_spender, _value);
}
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _value
) public validRecipient(_to) returns (bool) {
return super.transferFrom(_from, _to, _value);
}
// MODIFIERS
modifier validRecipient(address _recipient) {
require(_recipient != address(0) && _recipient != address(this));
_;
}
}
Footer
helpful_scripts.py
from unicodedata import decimal
from brownie import (
Contract,
accounts,
network,
config,
MockV3Aggregator,
VRFCoordinatorMock,
LinkToken,
)
FORKED_LOCAL_ENVIRONMENTS = ["mainnet-fork-dev", "mainnet-fork"]
LOCAL_BLOCKCHAIN_INVINRONMENTS = ["development", "ganache-local"]
# INDEX = if pass an index get_account() will use accounts[index]
# ID = if we pass an id get_account() will use accounts.load("account_id")
def get_account(index=None, id=None):
# accounts[0]
# accounts.add("env")
# acconts.load("id")
if index:
return accounts[index]
if id:
return accounts.load(id)
if (
network.show_active() in LOCAL_BLOCKCHAIN_INVINRONMENTS
or network.show_active() in FORKED_LOCAL_ENVIRONMENTS
):
return accounts[0]
return accounts.add(config["wallets"])["from_key"]
# In this mapping we are sayng for example if you saw "eth_usd_price_feed"
# you know it's type is MockV3Aggregator if we need to deploy a mock
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 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]
# we check if we're on a local blockchain
if network.show_active() in LOCAL_BLOCKCHAIN_INVINRONMENTS:
# and we'll check if mocks have been deployed or not
if len(contract_type) <= 0:
# MockV3aggregator.length
deploy_mocks()
contract = contract_type[-1]
# MockV3Aggregator[-1]
else:
# Adrres:
contract_address = config["networks"][network.show_active()][contract_name]
# ABI: With the Contract package we can get the contract from it's ABI and it's Address:
contract = Contract.from_abi(
contract_type._name, contract_address, contract_type.abi
)
# MockV3Aggregator.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!")
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 randomness;
uint256 public usdEntryFee;
AggregatorV3Interface internal ethUsdPriceFeed;
// ENUM is a way to create user-defined types in solidity
// We use unum to declare the steps of our lottery process in the ORDER they have to pass
enum LOTTERY_STATE {
OPEN,
CLOSED,
CALCULATING_WINNER
}
LOTTERY_STATE public lottery_state;
uint256 public fee;
bytes32 public keyhash;
// OPEN = 0
//CLOSED = 1
//CALCULATIN_WINNER = 2
//We can add a inherited constructor varibales into our constructor:
constructor(
address _priceFeedAddress,
address _vrfCoordinator,
address _link,
uint256 _fee,
bytes32 _keyhash
) public VRFConsumerBase(_vrfCoordinator, _link) {
usdEntryFee = 50 * (10**18);
ethUsdPriceFeed = AggregatorV3Interface(_priceFeedAddress);
// When we initialize our contract we want our lottery state to be closed so:
lottery_state = LOTTERY_STATE.CLOSED;
// we can also say this: lottery_state = 1;
fee = _fee;
keyhash = _keyhash;
}
function enter() public payable {
// We can only enter if somebody starts the lottery
require(lottery_state == LOTTERY_STATE.OPEN);
// This needs a require for minimum entry fee 50$
require(msg.value >= getEntranceFee(), "Not enough ETH!");
players.push(msg.sender);
}
function getEntranceFee() public view returns (uint256) {
// first we're gonna store whats the minimum fee is
(, int256 price, , , ) = ethUsdPriceFeed.latestRoundData();
uint256 adjustedPrice = uint256(price) * 10**10; //18 decimals
//50 * 1000bignumber / 2000
uint256 costToEnter = (usdEntryFee * 10**18) / adjustedPrice;
return costToEnter;
}
//we could declare a modifier ourselves for the owner only to start the lottery but instead we import openzeplin library
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 {
// !ALERT! THIS IS AN UNACCEPTABLE WAY TO GENERATE RANDOM NUMBERS.
// uint256(
// keccack256(
// abi.encodePacked(
// nonce, //nonce is predictable (aka, transaction number or transaction count)
// msg.sender, //msg.sender is predictable
// block.difficulty, //difficulty can actually be manipulated by miners!
// block.timestamp // timestamp is predictable
// ) // So basically the random is not actually random!
// )
// ) % players.length;
lottery_state = LOTTERY_STATE.CALCULATING_WINNER;
bytes32 requestId = requestRandomness(keyhash, fee); //this will return a bytes32 called request ID
}
// intrenal: because we dont want any one outside of our contract to be able to call thiss function to manipulate it.
// override: this function is in VRFConsumerBase contract but it doesnt do anything and it has beed made for us
// to override it and give it parameters
//??? HOW DO WE GET _RANDOMNESS AND WHERE FROM (i know from vrf but how does it come from vrf contract to our lottery contract) ???
function fulfillRandomness(bytes32 _requestId, uint256 _randomness)
internal
override
{
require(
lottery_state == LOTTERY_STATE.CALCULATING_WINNER,
"You are not ther yet!"
);
require(_randomness > 0, "random-not-found");
//???
uint256 indexOfWinner = _randomness % players.length;
recentWinner = players[indexOfWinner];
//paying the winner
recentWinner.transfer(address(this).balance);
// reset the lottery
players = new address payable[](0);
lottery_state = LOTTERY_STATE.CLOSED;
// keeping track of the random number
randomness = _randomness;
}
}
deploy_lottery.py
from brownie import Lottery, network, config
from scripts.helpful_scripts import get_account, get_contract
def deploy_lottery():
account = get_account()
# Lottery.deloy(get_contract("eth_usd_price_feed")) : thsi will return the contract but we only need the address
lottery = Lottery.deloy(
get_contract("eth_usd_price_feed").address,
get_contract("vrf_coordinator").address,
get_contract("link_token").address,
config["network"][network.show_active()]["fee"],
config["network"][network.show_active()]["keyhash"],
{"from": account},
publish_source=config["networks"][network.show_active()].get("verify", False),
)
# here False means if there is no verify set it to False
print("Deployed Lottery!")
def main():
deploy_lottery()
`
### brownie-config.yaml
`dependencies:
- smartcontractkit/chainlink-brownie-contracts@1.1.0
- OpenZeppelin/openzeppelin-contracts@3.4.0
compiler:
solc:
remappings:
- "@chainlink=smartcontractkit/chainlink-brownie-contracts@1.1.0"
- "@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0"
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}
Hello, I'm in the deploy Lottery part of @PatrickAlphaC 's video and after giving the constructor all the parameters such as fee, keyhash and link token, when I'm trying to run my deploy_lottery.py contract I get this error: ImportError: cannot import name 'LinkToken' from 'brownie' which I think the problem is from the LinkToken.sol solidity version, but i couldn't solve it even when I changed my python version or solidity global version I even checked the directory and replaced the file with the file I downloaded from the github repository. could anyone tell what seems to be the problem?
LinkToken.sol
helpful_scripts.py
Lottery.sol
deploy_lottery.py