21 Comments
Dec 16, 2021Liked by BowTiedDevil

Really loving the pace that you’re posting. Can get a new chunk done every night which had been really cool! Thanks BT Devil!

Expand full comment
May 25, 2022Liked by BowTiedDevil

awesome tutorial! I stumbled upon this last night. learning python as I go and smart contract hacking. fun and profitable. thanks Devil <3

Expand full comment
Jan 17, 2022Liked by BowTiedDevil

There's an easier way to deal with the decimals if you want the 'readable' balance, supported directly by web3.py: just call .fromWei(number, desired_denomination)

Example, you want the wavax_contract balance in AVAX?

This code:

web3.fromWei(wavax_contract.balance(), 'ether')

Output:

Decimal('17022497.831716268309025274')

Expand full comment
author

Excellent! The decimals are a pain to manage by hand and I'm mostly going through the trouble to demonstrate what's going on "under the hood"

The fromWei method works perfectly for any gas or ERC-20 token with 18 decimal places, but falls apart when we have a token with a different decimal place value (like USDT/USDC).

Since I wrote this post, I've converted a lot of this stuff to be represented by classes instead of dictionaries. One advantage is that I've written a token helper method to output the "human readable" number instead of messing around with powers of 10 all the time.

Expand full comment

Hi Jeff, note for you and for future users that .fromWei method (camel case) is deprecated from v6 and so .from_wei is required with this version. Hope this saves someone half a morning's work in future like it cost me!!

Expand full comment
Dec 16, 2021Liked by BowTiedDevil

Yeah want to repeat what Alex mentions, these small articles are easy to consume and follow. This is a lot of fun. Keep the pace up!

Expand full comment

I have read all your articles in here, and wohoo your teaching method is easily to understand. I got all the preparation thanks to internet and jump straight to your tutorial. I just want to post in here to thank you. Since the complexity is getting bigger, i hope that we can discuss more in future post. Thanks BowTiedDevil!!!!

Expand full comment
author

My pleasure! Future lessons will bring a lot of these small chunks together in a satisfying way.

Expand full comment
Jun 30, 2022Liked by BowTiedDevil

Great tutorial. I have a small problem: I cannot copy and paste once I am running python within Powershell (Windows 10). Also, some signs remain invisible although they seem to be taken into account, don't know if it's related. Dots and equal sign for example. Anyone else have this issue?

Expand full comment
author

Oh boy, character encoding issues are really tough to debug.

My usual workaround is to copy paste into a non-formatting editor like notepad, then re-copy from there before pasting it into the console.

Expand full comment

Thanks, I tried this, but no characters still. Not a big deal though, I'll post the solution if I figure it out.

Expand full comment

"A smart contract blockchain has to function predictably on all nodes running it, and as such any data structures that are not perfectly reproducible on all hardware cannot be used"

This sentence is a sleeper hit for me. Says so much about blockchain design. I intend to remember it.

Would be cool to crowdsource some more lessons.

Also, I try to add various avax network wallets to Brownie, and I get:

"ValueError: Failed to retrieve data from API: {'status': '0', 'message': 'NOTOK', 'result': 'Contract source code not verified'}"

Anyone know what's up with that? What qualifies for loading into Brownie? Ctrl + F on Avalanche docs and brownie docs yields nothing.

Expand full comment
author

Some contracts on snowtrace have not been verified by their authors, so they will display the error when attempting to load using the from_contract() method. The way around this is to load the contract from an ABI, which we will learn soon, but that puts you at risk since the true blockchain contract source code is unknown.

Expand full comment
Dec 16, 2021Liked by BowTiedDevil

yes same for me. Enjoy to read and try it out by myself. :)

Expand full comment

BowTiedDevil just capturing the Discord note in case people come here to look through for the issue I encountered and you solved for me.

Following the tutorial the following line:

wavax_contract = Contract.from_explorer('0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7')

was causing the following error:

CompilerError: solc returned the following errors:

Invalid EVM version requested.

At the time of writing Snowtrace has been retired and this "switcheroo" causes the error due to Snowtrace API returning unexpected values. It sounds scary but the solution you suggested is the edit the Brownie source code. But for users freaking at this it's as easy as editing your own .py files.

In the codeblock in ../brownie/network/contracts.py around line 1081 there is the following code:

evm_version = data["result"][0].get("EVMVersion", "Default")

if evm_version == "Default":

evm_version = None

Simply changing the second line (1082 in Brownie 1.20) to:

if evm_version in ["Default", ""]:

provides a fix and allows one to proceed with the tutorial. Thanks!

Expand full comment

SolcInstallationError: Downloaded binary would not execute, or returned unexpected output. If this issue persists, you can try to compile from source code using `solcx.compile_solc('0.5.17')`.

I am getting the above error when trying to load the wavax_contract on mac

Expand full comment
author

I don't have a Mac and can't offer much help, but I've seen this issue from others. The issue is the ARM-based Macs do not run x86/amd64 solc binaries, which Brownie attempts to install. Here's a link discussing it and some possible solutions: https://ethereum.stackexchange.com/questions/84125/brownie-cannot-install-solc-on-osx

Expand full comment

Ok this was a little trickier to understand. A short recap for myself and to review if I may.

So, you helped us load a smart contract address into an object. This happens to be the native token wrapper contract, which also somehow monitors/records the distribution of the wrapped native token at different addresses (joe?aave?etc) AND it has it's own balance with multiple tokens. A bit confusing but... accepte.

So to summarise one can among other things:

Query the contract for the total amount of native token AVAX in the contract, and converted into wAVAX (via balance)... as of now about 12.7 mln AVAX

Query the amount of WAVAX in the contract (via balanceOf(itsself), ie the amount of WAVAX moving through(?) the WAVAX smartcontract?) or some how on it, perhaps a fee? Sorta lost me here.

Query the amount of WAVAX per "other" address (balanceOf(x-address)).

So this contract records numerous things on the blockchain/ledger for us. Some how it can record the changes and update the figures for difference addresses including its own address.

Expand full comment
author

You've mostly understood it correctly. The WAVAX smart contract lives on the Avalanche blockchain, simple enough. Brownie allows us a way to create an object to represent this contract within our console or a running program. We load it and store it in memory with a variable labeled 'wavax_contract'

The actual smart contract is executing on the blockchain all the time, and we use our contract object to get updates. One of the things we can ask is "how much WAVAX does address XYZ hold?" using the balanceOf() method. The address we feed into balanceOf() can be anything, and the result of that call depends on what the WAVAX smart contract has recorded inside it.

A smart contract can have native token balances as well as other token balances, hence the difference we found when comparing the AVAX balance and WAVAX balance at that address.

The weirdness you note (WAVAX tokens stored at the WAVAX contract address) is likely due to someone sending tokens to it by mistake. Currently I see roughly 176 WAVAX stored there. It's likely lost forever.

When a user wraps AVAX, they do it with the deposit() function. When that executes, new WAVAX tokens are minted and sent to the user address equal to the amount of AVAX deposited.

If everybody did it right, the WAVAX contract would have zero WAVAX and an amount of AVAX equal to the number of WAVAX tokens created in total.

Expand full comment
Jun 13, 2022·edited Jun 13, 2022Liked by BowTiedDevil

Thanks for running through my thoughts! Extensive reply too.

I guess it was just weird to me that a smart contract address can also be a kind of "wallet" of some sort at the same time. You'd think they would separate the two, contract address and a contract wallet address...

But I guess this sort of saves space in a way. If you send AVAX tokens to this address with the right variables along with it, or what ever data is necessary, to execute the contract, it does so. Adding a few extra wallet addresses on the side to pass through would only take up more space and computation? Something like that.

In any case, thanks so far!

Expand full comment
author

You're welcome sir 🤝

I agree, it's unintuitive that a smart contract and a regular externally owned account would behave the same way from the perspective of sending/receiving assets.

It's simple enough once you've wrapped your thinking around the arrangement, but takes running through the examples a few times before it makes sense.

Expand full comment