Brownie Documentation

repository·master·Indexed 25 days ago

https://github.com/eth-brownie/brownie

A Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine (EVM). Brownie supports Solidity and Vyper, integrates with pytest and hypothesis, and provides tools for project initialization, network connection management, gas configuration, and account management including support for local keystores and hardware wallets via Clef.

Tokens
46.3K
Snippets
163
Records
290
Agent score
82%

What's inside Brownie

  1. Overview of Brownie features

    master

    Brownie is a Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine (EVM). Key features include:

    • Language Support: Full support for Solidity and Vyper.
    • Testing: Contract testing via pytest, including trace-based coverage evaluation.
    • Advanced Testing: Property-based and stateful testing via hypothesis.
    • Debugging: Python-style tracebacks and custom error strings.
    • Interaction: A built-in console for quick project interaction.

    Note: Brownie relies heavily on web3.py. Users should have a basic familiarity with web3.py to use Brownie effectively.

  2. Project directory structure

    master

    A standard Brownie project uses the following directory structure:

    • contracts/: Smart contract source files.
    • interfaces/: Interface source files.
    • scripts/: Python scripts for deployment and interaction.
    • tests/: Python scripts for testing.

    Note: The build/ and reports/ directories are managed internally by Brownie and should not be manually edited or deleted.

  3. Understand the structure of the build/ folder

    master

    The build/ folder in a Brownie project contains various data files used for debugging, deployment, and testing. Understanding this structure is useful when integrating third-party tools or modifying Brownie source code. Key subdirectories include:

    • build/contracts: Compiler artifacts for contracts.
    • build/interfaces: Compiler artifacts for project interfaces.
    • build/deployments: Deployment artifacts for specific networks.
    • build/test.json: Unit test results and coverage data.
  4. Manage Brownie projects with the Project API

    master
    The project package is used to initialize, load, and compile Brownie projects. When Brownie is loaded from within a project folder, the project is automatically loaded, and ContractContainer objects are added to the __main__ namespace. For most users, direct interaction with the Project object is unnecessary unless working with multiple projects simultaneously.
  5. Configure Alchemy connection

    master

    To use Alchemy, you must provide your project ID via the WEB3_ALCHEMY_PROJECT_ID environment variable.

    To find your ID:

    1. Log in to Alchemy and create a project.
    2. Click 'view key' to get your URL (e.g., https://eth-mainnet.alchemyapi.io/v2/1234).
    3. Use the string after the last slash (1234) as your WEB3_ALCHEMY_PROJECT_ID.
  6. Initialize a new Brownie project

    master

    To start a new project, create an empty directory and run the brownie init command.

    You can also use "Brownie mixes" to initialize a project from a template. For example, to use the token mix (a basic ERC-20 implementation), run:

    $ brownie bake token

    This creates a token/ subdirectory containing the template project.

    $ brownie init
    $ brownie bake token
  7. Check unit test coverage with brownie test --coverage

    master

    To evaluate the coverage of your unit tests, run the brownie test command with the --coverage flag. Brownie will output a percentage score for each contract method and save a detailed report to reports/coverage.json.

    $ brownie test --coverage
  8. Write property-based tests with Brownie and Hypothesis

    master

    Brownie uses the hypothesis framework to enable property-based testing. Instead of testing single scenarios, you define a range of inputs (strategies) and let the framework explore edge cases.

    To write a property-based test:

    1. Import given and strategy from brownie.test.
    2. Use the @given decorator on a test function to specify how arguments are provided.
    3. Use strategy() to define the types and constraints of the arguments.

    Important: Always import @given from brownie.test rather than directly from hypothesis to ensure proper test isolation within the Brownie environment.

    from brownie import accounts
    from brownie.test import given, strategy
    
    @given(value=strategy('uint256', max_value=10000))
    def test_transfer_amount(token, value):
        balance = token.balanceOf(accounts[0])
        token.transfer(accounts[1], value, {'from': accounts[0]})
    
        assert token.balanceOf(accounts[0]) == balance - value
  9. Debug failed transactions with revert messages and tracebacks

    master

    When a transaction reverts, Brownie still returns a TransactionReceipt object. You can use it to diagnose the failure:

    • revert_msg: Returns the error string provided by the revert (e.g., 'Insufficient Balance').
    • traceback(): Returns a Python-like traceback showing the execution path and source code highlights leading up to the revert.

    Note: Debugging functionality requires the debug_traceTransaction RPC method. This is unavailable on Infura and will raise an RPCRequestError if attempted.

    Tip: You can create temporary events in your smart contract to examine local variables during a failed transaction execution.

    >>> # Get the revert reason
    >>> tx.revert_msg
    'Insufficient Balance'
    
    >>> # Get a code-level traceback
    >>> tx.traceback()
    Traceback for '0xd31c1c8db46a5bf2d3be822778c767e1b12e0257152fcc14dcf7e4a942793cb6':
    Trace step 169, program counter 3659:
        File "contracts/SecurityToken.sol", line 156, in SecurityToken.transfer:
        _transfer(msg.sender, [msg.sender, _to], _value);
    ...
  10. Run deployment and interaction scripts

    master

    Automate tasks by writing Python scripts in the scripts/ folder. Start your script with from brownie import * to access Brownie objects. To execute the main() function within a script, use the brownie run command.

    # scripts/token.py
    from brownie import *
    
    def main():
        Token.deploy("Test Token", "TEST", 18, 1e23, {'from': accounts[0]})
    $ brownie run token
  11. Use interfaces for cross-language or multi-version compatibility

    master

    You can place interfaces in the interfaces/ subfolder. This is useful for:

    1. Vyper users: When interfaces are not directly compilable source code.
    2. Mixed projects: When using both Solidity and Vyper, or multiple Solidity versions, to avoid compatibility issues when contracts reference one another.

    Interfaces can be written in Solidity (.sol), Vyper (.vy), or as JSON-encoded ABI files (.json). Adding or modifying an interface only triggers a recompile if a contract depends on that interface.