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 FundMe
from brownie import network, config
from scripts.helpful_scripts import *
from scripts.helpful_scripts import LOCAL_BLOCKCHAIN_ENV
def deploy_fund_me():
account = get_account()
print(f"Deploying on ....{network.show_active()}")
if network.show_active() not in LOCAL_BLOCKCHAIN_ENV:
price_feed_address = config["networks"][network.show_active()]["eth_usd_price_feed"]
else: #deploy mock of price feed on internal chain: development
deploy_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 MockV3Aggregator
DECIMAL_PLACES = 8 #to resemble eth/usd price feed on mainnet aggregator
STARTING_PRICE = (2000*10**8)
def deploy_mocks():
print(f"The active network is {network.show_active()}")
print("Deploying.....")
if len(MockV3Aggregator) <= 0:
MockV3Aggregator.deploy(DECIMAL_PLACES,STARTING_PRICE,{"from":get_account()}) #contract object
print(f"Mocks Deployed at: {MockV3Aggregator[-1].address}")
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 Lottery
from scripts.helpful_scripts import get_account, get_contract()
def deploy():
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!.....")
def main():
deploy()
from brownie import network, accounts,config,
from brownie import interface
from brownie import MockV3Aggregator,VRFCoordinatorMock,LinkToken, Contract
LOCAL_BLOCKCHAIN_ENV = ["development", "ganache-local"]
FORKED_LOCAL_ENV = ["mainnet-fork", "mainnet-fork-dev"]
#dictionary
#our reference_name: Contract Name as per import
contract_to_mock = {
"ethusd_pricefeed": MockV3Aggregator,
"link_token": LinkToken,
"vrf_coordinator": VRFCoordinatorMock
}
def get_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 mocks
if len(contract_type) <0: # check if got prior deployment
deploy_mocks()
contract = contract_type[-1] #grab most recent
else:
# 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.json
return contract
DECIMALS = 8 #to resemble eth/usd price feed on mainnet aggregator
STARTING_PRICE = (2000*10**8)
def deploy_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.