Degen Code

Degen Code

Share this post

Degen Code
Degen Code
Updates for Web3.py v6
Copy link
Facebook
Email
Notes
More

Updates for Web3.py v6

Handling Some Backwards-Incompatible Changes

Sep 23, 2023
∙ Paid
3

Share this post

Degen Code
Degen Code
Updates for Web3.py v6
Copy link
Facebook
Email
Notes
More
Share

I’ve been working this week to replace the Brownie-specific sections of the degenbot code base. This commit was the first big set of changes, and I’ve made several refinements since then.

I’ve learned a few things about web3.py along the way. First, I highly recommend reading the official documentation Migrating your code from v5 to v6 page.

It is mostly straightforward, but there are some subtle differences that you should be aware of.

get_transaction Return Values

A subtle difference to be sure, but version v5 and v6 have differing output from the get_transaction method.

In v5, the input and data fields are returned as a hex-formatted string. In v6, they are HexBytes, which is a wrapped bytes object that displays as hex by default. Be careful when directly comparing a hex string with a HexBytes object, since they don’t behave like you’d expect!

If you need to do string comparisons or provide a string input to a function, but you have a HexBytes object, convert it with the hex() method.

>>> HexBytes('0x069420')=='0x069420'
False
>>> HexBytes('0x069420').hex()=='0x069420'
True

Type and Chain ID

In v5, the transactio fields 'type' and 'chainID' are presented as hex-formatted strings. In v6, they are converted to integers. If you’re doing a check like this:

if transaction["type"] == '0x0':
    do_something()

Please update it to:

if transaction["type"] == 0:
    do_something()

Or make it compatible with both versions by accepting both types:

if transaction["type"] in (0, '0x0'):
    do_something()

Or doing an inline conversion in the comparison:

if int(transaction["type"]) == 0:
    do_something()

Function Naming

Web3.py version 5 used a mixture of snake_case and camelCase for function names. The most commonly used camel case functions in degenbot were isConnected and toChecksumAddress.

Checksum Addresses

After reading the code behind web3.py’s toChecksumAddress and to_checksum_address, it became clear that web3.py is just wrapping a function provided by the eth-utils module. It’s quite simple to just replace the use of Web3.toChecksumAddress with eth_utils.to_checksum_address, and I’ve done this throughout the code base.

If you are checksumming addresses inside your scripts, be sure to make this change.

Brownie handles both lower-case and checksummed addresses automatically, but web3.py will throw warnings and exceptions if you attempt to use a lower-case address without special arguments. Addresses within degenbot functions and methods are checksummed before use, but you may run into issues if you do comparisons in your client code without considering this.

Workaround

My goal is to support web3.py v5 until the transition away from Brownie can be made complete. To do this effectively, I need to handle both versions of web3.py by default.

Python allows you to retrieve an attribute of a particular object with the getattr function. Since everything in Python is an object, I can quickly identify which version of web3.py the script has loaded by calling getattr on the module name.

For example, if I want to use the isConnected (or is_connected) method on a Web3 object, I can check for both attributes:

for method_name in ("is_connected", "isConnected"):
    try:
        connected_method = getattr(w3, method_name)
    except AttributeError:
        pass
    else:
        break

And now I have a reference to the method that I can use directly:

if connected_method() == False:
    raise ValueError("Web3 object is not connected.")

I use this technique in a few places in the code base. I’ve ordered the method names so that the v6 method appears first, since this the preferred condition.

Which Functions Are Affected?

This may not be an exhaustive list, but I’ve identified these:

  • createFilter → create_filter

  • fromWeb3 → from_web3

  • getLogs → getlogs

  • isConnected → is_connected

  • isChecksumAddress → is_checksum_address

  • processReceipt → process_receipt

  • processLog → process_log

  • solidityKeccak → solidity_keccak

  • toAddress → to_address

  • toBytes → to_bytes

  • toChecksumAddress → to_checksum_address

  • toHex → to_hex

  • toInt → to_int

  • toJSON → to_json

  • toText → to_text

Here are some Github links that include more detail on these changes:

  • PR 2709 — Snakecase contract event methods

  • PR 2686 — Snakecase clientVersion

  • PR 2702 — Snakecase solidityKeccak

  • PR 2703 — Snakecase fromWeb3

  • PR 2707 — Snakecase encoding decoding helpers

  • PR 2708 — Snakecase address helpers

Changes to decode_function_input

This one tripped me up for a while. The documentation for v5 says that decode_function_input returns a dictionary of values for the function parameters, however I’ve confirmed that sometimes it returns a tuple instead.

Here’s an example of a nested multicall, decoded from a transaction I wrote about in Part IV of the Transaction Prediction series. Skipping some steps required to unwrap the multiple encodings, I decode the final payload with web3.py v5:

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 BowTiedDevil
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More