Sending Transactions via web3.py

Awbr...Rufb
23 May 2022
52


Get started with web3.py here!

A common reason why you want to programmatically interact with the blockchain is to automate transactions. That is based off some conditions, you will choose to automatically execute a transaction; i.e. When BTC is below 30k, you will swap all USDC in your wallet to WBTC via Uniswap.

To do this, you must find the relevant function that you are calling for a contract. As mentioned in the previous article, this can be done via the ABI - let's try to transfer some tokens using python!

To start off, let's save this ABI from pastebin into a new file. This is for a test ERC-20 Token that I deployed on the Goerli Ethereum Testnet. It can be viewed here. A testnet is basically a blockchain that is used for testing purposes where tokens have no real value.

from web3 import Web3
import json

# Create a Web3 instance connected to our RPC
w3 = Web3(Web3.HTTPProvider("https://rpc.goerli.mudit.blog/"))

with open("test_token.json", "r") as fp:
 token_abi = json.loads(fp.read())

# Contract address for our test token on Goerli Testnet
# https://goerli.etherscan.io/address/0x4F50B083e614715AB7C93dE118fBDB2c3e5696B1
BULB_TEST_TOKEN_CA = "0x4F50B083e614715AB7C93dE118fBDB2c3e5696B1"

TEST_CONTRACT = w3.eth.contract(BULB_TEST_TOKEN_CA, abi=token_abi)
print([fn for fn in dir(TEST_CONTRACT.functions) if not fn.startswith("_")])


Pretty boring boilerplate code so far; but we do get a list of functions.

['abi', 'address', 'allowance', 'approve', 'balanceOf', 'decimals', 'decreaseAllowance', 'getFreeTokens', 'increaseAllowance', 'name', 'symbol', 'totalSupply', 'transfer', 'transferFrom', 'web3']


Let's try calling this "getFreeTokens" function. To do this, we must either a) have a private node with our private key which can sign and send any transactions we send it, or b) sign our transactions in our script using our private key and then broadcast the signed transaction to any public node. You can read more about it here.

Create a new burner wallet on metamask (I would recommend creating dedicated throwaway wallets for botting) and then export the private key via Settings -> Account Details -> Export Private Key. DO NOT SHARE YOUR PRIVATE KEY WITH ANYONE - Anyone can drain your wallet if they have your private key. Let's add some more code:

from eth_account import Account

PRIVATE_KEY = "insert your private key here"
ADDRESS = Account.from_key(PRIVATE_KEY).address
print(f"You are using {ADDRESS} in your script")

def send_transaction(gas: int = 1000000):
  nonce = w3.eth.get_transaction_count(ADDRESS)
  tx = TEST_CONTRACT.functions.getFreeTokens(12345).buildTransaction(
    {
      'from': ADDRESS,
      'value': 0,
      'gasPrice': w3.toWei(5, 'gwei'),
      'gas': gas,
      'nonce': nonce
    }
  )
  signed_tx = w3.eth.account.sign_transaction(tx, PRIVATE_KEY)
  tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction).hex()
  print(f"Sent TX {tx_hash}")
  w3.eth.wait_for_transaction_receipt(tx_hash)

send_transaction()


You also need some gas for your transactions to execute. You can get some free testnet ETH for Goerli by using a faucet from the ethereum documentation. Now we can run the script!

You are using 0x56aC2F55591221DE8B00a6f45c204f47f3aAC09f in your script
Sent TX 0xc6da4bc9dec24f57eafa21372fb5702dd4ae6a795c5f2b8c2c70c78b090c7c3b


And voila, we have gotten a free 12345 test tokens using that contract!

Now for some homework / self research:

  • What is a nonce?
  • What is "gas price" and "gas"? What does increasing/decreasing "gas" and "gas price" do?
  • What is "wei"/"gwei"?
  • Once you have gotten some "BULB Demo Example Token(s)", can you adapt this code to transfer it to another wallet?
  • What happens if you don't specify the "12345" argument to getFreeTokens? What happens if you specify some other number, a wallet address, a string? Do we really know what a function will do apart from guessing what it is based off its name and ABI?
  • Print out the signed_tx variable. Then look at the transaction of a "getFreeTokens" function call in the etherscan explorer. What does the input data field in the transaction correspond to? Can you break down the input data into its separate components?
  • What is a private key? Can you give out your public key to other people? What's the difference between a private key and a seed phrase?


For some not so closely related questions which I may explain in some following blog posts:

  • How do you find the ABI for a dapp such as Uniswap? You can probably find something on google but how about the ABI for more obscure contracts?
  • How does a dapp such as Uniswap move your tokens out of your wallet? If any random app can access your USDC/WETH/WBTC/USDT balances, then surely there's a huge security issue...

Get fast shipping, movies & more with Amazon Prime

Start free trial

Enjoy this blog? Subscribe to 12Ghast

3 Comments