Smart Contract Development
  • Introduction
    • What is a Transaction
    • Accounts and Signing
    • What is a smart contract
  • Learning Solidity
    • Introduction
    • Module 1
      • Variable Types
      • Variable Scope: State & Local variables
      • Global variables
      • Functions
        • View and Pure
        • Shadowing in Fuctions
      • Mapping
      • Require
      • Events
    • Project #1: Simple Registry
    • Module 2
      • Constructor
      • Data Location: Value & Reference
      • Interface
      • Import
        • Importing in Foundry
      • Inheritance
      • ERC-20
      • Checks-effect-interaction pattern
    • Project #2: Basic Vault
    • Module 3
      • Payable
      • Receive
      • Fallback
      • Returns
    • Project #3: ERC20+ETH Wrapper
    • Module 4
      • Immutable and Constant
      • Fixed-point Math
      • Abstract contracts
      • ERC-4626
      • Modifier + Inheritance +Ownable
      • Type
    • Project #4: Fractional Wrapper
    • Module 5
      • If-else
      • Libraries
        • TransferHelper
      • Chainlink Oracle
    • Project #5: Collateralized Vault
  • Compendium
    • Solidity Basics
      • Variable Types
      • Value Types
        • address
        • enum
      • Reference Types
        • strings
        • mappings
        • struct
        • Arrays
        • Multi-Dimensional arrays
      • Global Objects
      • Functions
        • Function types
        • Constructor Function
        • Transaction vs Call
        • Require, Revert, Assert
      • Function signature + selectors
      • Payable
        • Payable + withdraw
        • msg.value & payable functions
      • Receive
      • Fallback function (sol v 0.8)
        • Fallback function (sol v 0.6)
      • call, staticcall, delegatecall
    • Return & Events
    • Control Variable Visibility
    • Local Variables (Storage v Memory)
    • Data Location and Assignment Behaviors
    • Modifiers & Inheritance & Import
      • import styles
    • Interface & Abstract Contracts
    • ABI & Debugging
    • Libraries
    • Conditional(ternary) operators
    • Smart Contract Life-cycle
      • Pausing Smart Contracts
      • Destroying Smart Contracts
    • Merkle Trie and MPT
    • Merkle Tree Airdrop
  • Try & catch
  • Ethereum Signatures
  • EVM, Storage, Opcodes
    • EVM
    • Wei, Ether, Gas
    • Storage
    • ByteCode and Opcodes
    • Transaction costs & Execution costs
  • Reading txn input data
  • Data Representation
  • Yul
    • Yul
      • Intro
      • Basic operations
      • Storage Slots
      • Storage of Arrays and Mappings
      • Memory Operations
      • Memory: how solidity uses memory
      • Memory: Return, Require, Tuples and Keccak256
      • Memory: Logs and Events
      • Inter-contract calls
      • calldata
      • free memory pointer
    • Yul Exercises
      • read state variable
      • read mapping
      • iterate Array, Return Sum
    • memory-safe
  • Upgradable Contracts
    • Upgradability & Proxies
    • UUPS Example
    • Minimal Proxy Example
    • TPP Example
    • 🚧Diamond
      • On Storage
  • Gas Opt
    • Block Limit
    • gasLimit & min cost
    • Solidity Optimiser
    • Memory v calldata
    • Memory caching vs direct storage vs pointers
    • < vs <=
    • reverting early
    • X && Y, ||
    • constant and immutable
    • caching sload into mload
    • Syntactic Sugar
    • using unchecked w/o require
    • Compact Strings
    • Calling a view function
    • Custom errors over require
    • usage of this.
      • multiple address(this)
  • ERCs & EIPs
    • ERC-20.sol
      • Core functions
      • transfer()
      • transferFrom()
      • TLDR transfer vs transferFrom
    • Landing
      • ERC721.sol
      • EIP-721
        • LooksRare
        • Page 1
      • ERC-1271
      • EIP-2981
      • ERC-165
      • EIP-1167: Minimal Proxy Contract
    • VRFConsumerBase
    • UniswapV2Library
  • Yield Mentorship 2022
    • Projects
      • #1 Simple Registry
      • #2 Basic Vault
      • #3 ERC20+ETH Wrapper
        • setFailTransferTrue
      • #4 Fractional Wrapper
      • #5 Collateralized Vault
        • Process
        • Vault.sol
        • Testing
        • Chainlink Oracles
        • Pricing + Decimal scaling
        • Refactor for Simplicity
      • #9 Flash Loan Vault
        • Implementing ERC3156
        • Full code for lender
        • Ex-rate calculation
    • State Inheritance Testing
    • Testing w/ Mocks
    • Yield Style Guide
    • Github Actions
    • TransferHelper.sol
    • math logic + internal fn
    • Interfaces: IERC20
  • Foundry
    • Overview
    • Importing Contracts
    • Testing
      • stdError.arithmeticError
      • assume vs bound
      • Traces
      • label & console2
      • std-storage
  • Smart Contract Security
    • Damn Vulnerable Defi
      • 1. Unstoppable
      • 2. Naive receiver
      • 3. Truster
      • 4. Side Entrance
      • 5. The Rewarder
      • 6. Selfie
      • 7. Compromised
      • 8. Puppet
      • 9. Puppet V2
      • 10 - Free Rider
    • Merkle Tree: shortened proof attack
  • Fixed-Point Math
    • AMM Math
  • Solidity Patterns
    • checks-effects-interactions pattern
    • Router // batch
    • claimDelegate: stack unique owners
    • claimDelegate: cache previous user
  • Array: dup/ascending check
  • Deployment
    • Behind the Scenes
    • Interacting with External Contracts
    • Logging, Events, Solidity, Bloom Filter
  • Misc
    • Mnemonic Phrases
    • Bidul Ideas
  • Archive
    • Brownie Framework
      • Brownie basics
        • storing wallets in .env
        • Deployment to ganache
        • Interacting with contract
        • Unit Testing
        • Testnet deployment
        • Interacting w/ deployed contract
        • Brownie console
      • Brownie Advanced
        • Dependencies: import contracts
        • helpful_scripts.py
        • verify and publish
        • Forking and Mocking
        • Mocking
        • Forking
      • Testing
      • Scripts Framework
        • deploy.py
        • get_accounts
        • deploy_mocks()
        • fund_with_<token>()
      • Brownie Networks
    • Brownie Projects
      • SharedWallet
        • Multiple Beneficiaries
        • Common Code Contract
        • Adding Events
        • Renounce Ownership
        • Separate Files
      • Supply Chain
        • ItemManager()
        • Adding Events
        • Adding unique address to each item
      • Lottery
      • Aave - Lending and Borrowing
        • Approve & Deposit
        • Borrow
      • NFT
      • Advanced Collectible
        • adv_deploy() + Testing
        • Create Metadata
        • Setting the TokenURI
    • node npm
    • Ganache
    • Truffle
    • Remix
    • Installing Env
Powered by GitBook
On this page
  • Iteration 1
  • Iteration 2: get_contract() + deploy_mocks()
  • Explanation
  1. Archive
  2. Brownie Framework
  3. Scripts Framework

deploy_mocks()

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}")
networks:
  default: development  #default is development, un;ess we specify here.
  rinkeby: 
    eth_usd_price_feed: '0x8A753747A1Fa494EC906cE90E9f37563A8AF630e'
    verify: True
  mainnet-fork-dev: 
    eth_usd_price_feed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'  #mainnet address (for forking reference) - https://docs.chain.link/docs/ethereum-addresses/
    verify: False
  development:
    verify: False
  ganache-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 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!.....")
  
dependencies:
  - smartcontractkit/chainlink-brownie-contracts@1.1.1
  - OpenZeppelin/openzeppelin-contracts@3.4.0
  
compiler:
  solc:
    remappings:
      - '@chainlink=smartcontractkit/chainlink-brownie-contracts@1.1.1'
      - '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'

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'
    verify: False

wallets:
  from_key: ${PRIVATE_KEY}

deploy_mocks() -> deploys mocks of each type every time its called within get_contracts()

when calling get_contacts(ethusd_pricefeed), in deploy.py

if len(contract_type) < 0: deploy_mocks() contract = contract_type[-1]

ALL mocks are deployed. and again each time we call get_contracts.

Explanation

Create a dictionary contract_to_mock, which stores the actual contract names as values, and our reference names as keys.

  • "eth_usd_price_feed": MockV3Aggregator

  • contract_type = MockV3Aggregator

getcontract takes a parameter, contract_name, which is passed into the dictionary to obtain the true name of the contract.

if deploying to LOCAL_BLOCKCHAIN_ENV

mocks will be required. check if prior mock exists, if it does not, deploy_mocks() is ran.

contract = contract_type[-1] -> contract = MockV3Aggregator[-1]

This creates a Contract container called contract which holds the mock contracts. To access their address: contract.address

Else: no mocks needed

Access deployed contracts via their livenet addresses and abi.

contract address is obtained from brownie-config.yaml contract_address = config["networks"][network.show_active()][contract_name]

Beyond the address, we will need the contract's ABI to know how to interact with it.

Together, we will create a brownie Contract container object:

contract = Contract.from_abi(contract_type.name, contract_address, contract_type.abi)

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.

Previousget_accountsNextfund_with_<token>()

Last updated 3 years ago