When deploying to local blockchain environments that are not forks (ganache-cli, ganacheUI), we need to deploy mock contracts of external contracts we import .
When deploying to Forked environments, no need for mocks. We will refer to existing deployments via their addresses on the respective chain we are forking.
Iteration 1
from brownie import FundMefrom brownie import network, configfrom scripts.helpful_scripts import*from scripts.helpful_scripts import LOCAL_BLOCKCHAIN_ENVdefdeploy_fund_me(): account =get_account()print(f"Deploying on ....{network.show_active()}")if network.show_active()notin LOCAL_BLOCKCHAIN_ENV: price_feed_address = config["networks"][network.show_active()]["eth_usd_price_feed"]else:#deploy mock of price feed on internal chain: developmentdeploy_mocks() price_feed_address = MockV3Aggregator[-1].address
Here the external contract we need is the chainlink ETH/USD price feed contract to pass into AggregatorV3Interface.
from brownie import MockV3AggregatorDECIMAL_PLACES =8#to resemble eth/usd price feed on mainnet aggregatorSTARTING_PRICE = (2000*10**8)defdeploy_mocks():print(f"The active network is {network.show_active()}")print("Deploying.....")iflen(MockV3Aggregator)<=0: MockV3Aggregator.deploy(DECIMAL_PLACES,STARTING_PRICE,{"from":get_account()})#contract object print(f"Mocks Deployed at: {MockV3Aggregator[-1].address}")
networks:default:development#default is development, un;ess we specify here.rinkeby:eth_usd_price_feed:'0x8A753747A1Fa494EC906cE90E9f37563A8AF630e'verify:Truemainnet-fork-dev:eth_usd_price_feed:'0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'#mainnet address (for forking reference) - https://docs.chain.link/docs/ethereum-addresses/verify:Falsedevelopment:verify:Falseganache-local:verify:False
If deploying to live chain (mainnet, rinkeby), price_feed_address will reference the chainlink ethusd contract address on the corresponding deployed.
We store chainlink's pricefeed contract's corresponding address for each live chain in brownie-config.yaml, under the variable: eth_usd_price_feed.
If we are deploying to rinkeby, price_feed_address == eth_usd_price_feed == 0x8A753747A1Fa494EC906cE90E9f37563A8AF630e
If deploying to internal chain, like development
deploymocks() is called -> stored in helpful_scripts.py
checks if a prior instance exists
if there are not prior deployments, it will deploy a fresh mock contract.
if a prior deployment exists, nothing is done within deploy_mocks(),
execution goes back deploy.py line15:
price_feed_address = MockV3Aggregator[-1].address
Iteration 2: get_contract() + deploy_mocks()
from brownie import Lotteryfrom scripts.helpful_scripts import get_account,get_contract()defdeploy(): account =get_account() Lottery.deploy(get_contract("ethusd_pricefeed").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))# get verify key, if it doesnt exist - default to false.print(".....Deployed lottery!.....")defmain():deploy()
from brownie import network, accounts,config,from brownie import interfacefrom brownie import MockV3Aggregator,VRFCoordinatorMock,LinkToken, ContractLOCAL_BLOCKCHAIN_ENV = ["development","ganache-local"]FORKED_LOCAL_ENV = ["mainnet-fork","mainnet-fork-dev"]#dictionary#our reference_name: Contract Name as per importcontract_to_mock ={"ethusd_pricefeed": MockV3Aggregator,"link_token": LinkToken,"vrf_coordinator": VRFCoordinatorMock}defget_contract(contract_name):""" function will grab the mainnet/testnet contract addresses from the brownie config if defined. Otherwise, it will deploy a mock version of that contract, and return that mock contract address. Args: contract_name (string) Return: brownie.network.contract.ProjectContract: Most recently deployed version of this contract """ contract_type = contract_to_mock[contract_name]if network.show_active()in LOCAL_BLOCKCHAIN_ENV:#forks wont need mocksiflen(contract_type)<0:# check if got prior deploymentdeploy_mocks() contract = contract_type[-1]#grab most recentelse:# get address from config# need abi of deployed contract so we can interact. contract_address = config["networks"][network.show_active()][contract_name] contract = Contract.from_abi(contract_type.name, contract_address, contract_type.abi)# creating Contract object from abi# contract_type.abi pulls abi from build/dependencies folder: AggregatorV3Interface.jsonreturn contractDECIMALS =8#to resemble eth/usd price feed on mainnet aggregatorSTARTING_PRICE = (2000*10**8)defdeploy_mocks(decimals= DECIMALS,start_price= STARTING_PRICE): account =get_account()print(f"The active network is {network.show_active()}")print("Deploying.....") MockV3Aggregator.deploy(decimals,start_price,{"from":account})#contract object link_token = LinkToken.deploy({"from":account}) VRFCoordinatorMock.deploy(link_token.address,{"from":account})#print(f"Mocks Deployed at: {MockV3Aggregator[-1].address}")print(".....All Mocks Deployed!.....")
The ABI is accessed via contract_type.abi -> MockV3Aggregator.abi
The ABI is generated and stored in build/contracts/dependencies as part of our import statement setup.
Once we setup our import statements with the correct references and compile the project, brownie automatically downloads the necessary contracts as part of our dependencies and generates their ABI.