Examples

Here are some common things you might want to do with web3.

Looking up blocks

Blocks can be looked up by either their number or hash using the web3.eth.getBlock API. Block hashes should be in their hexadecimal representation. Block numbers

# get a block by number
>>> web3.eth.getBlock(12345)
{
    'author': '0xad5C1768e5974C231b2148169da064e61910f31a',
    'difficulty': 735512610763,
    'extraData': '0x476574682f76312e302e302f6c696e75782f676f312e342e32',
    'gasLimit': 5000,
    'gasUsed': 0,
    'hash': '0x767c2bfb3bdee3f78676c1285cd757bcd5d8c272cef2eb30d9733800a78c0b6d',
    'logsBloom': '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    'miner': '0xad5c1768e5974c231b2148169da064e61910f31a',
    'mixHash': '0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
    'nonce': '0x549f882c5f356f85',
    'number': 12345,
    'parentHash': '0x4b3c1d7e65a507b62734feca1ee9f27a5379e318bd52ae62de7ba67dbeac66a3',
    'receiptsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
    'sealFields': ['0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
    '0x549f882c5f356f85'],
    'sha3Uncles': '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
    'size': 539,
    'stateRoot': '0xca495e22ed6b88c61714d129dbc8c94f5bf966ac581c09a57c0a72d0e55e7286',
    'timestamp': 1438367030,
    'totalDifficulty': 3862140487204603,
    'transactions': [],
    'transactionsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
    'uncles': [],
}

# get a block by it's hash
>>> web3.eth.getBlock('0x767c2bfb3bdee3f78676c1285cd757bcd5d8c272cef2eb30d9733800a78c0b6d')
{...}

Getting the latest block

You can also retrieve the latest block using the string 'latest' in the web3.eth.getBlock API.

>>> web3.eth.getBlock('latest')
{...}

If you want to know the latest block number you can use the web3.eth.blockNumber property.

>>> web3.eth.blockNumber
4194803

Checking the balance of an account

To find the amount of ether owned by an account, use the getBalance() method. At the time of writing, the account with the most ether has a public address of 0x742d35Cc6634C0532925a3b844Bc454e4438f44e.

>>> web3.eth.getBalance('0x742d35Cc6634C0532925a3b844Bc454e4438f44e')
3841357360894980500000001

Note that this number is not denominated in ether, but instead in the smallest unit of value in Ethereum, wei. Read on to learn how to convert that number to ether.

Converting currency denominations

Web3 can help you convert between denominations. The following denominations are supported.

denomination

amount in wei

wei

1

kwei

1000

babbage

1000

femtoether

1000

mwei

1000000

lovelace

1000000

picoether

1000000

gwei

1000000000

shannon

1000000000

nanoether

1000000000

nano

1000000000

szabo

1000000000000

microether

1000000000000

micro

1000000000000

finney

1000000000000000

milliether

1000000000000000

milli

1000000000000000

ether

1000000000000000000

kether

1000000000000000000000

grand

1000000000000000000000

mether

1000000000000000000000000

gether

1000000000000000000000000000

tether

1000000000000000000000000000000

Picking up from the previous example, the largest account contained 3841357360894980500000001 wei. You can use the fromWei() method to convert that balance to ether (or another denomination).

>>> web3.fromWei(3841357360894980500000001, 'ether')
Decimal('3841357.360894980500000001')

To convert back to wei, you can use the inverse function, toWei(). Note that Python’s default floating point precision is insufficient for this use case, so it’s necessary to cast the value to a Decimal if it isn’t already.

>>> from decimal import Decimal
>>> web3.toWei(Decimal('3841357.360894980500000001'), 'ether')
3841357360894980500000001

Best practice: If you need to work with multiple currency denominations, default to wei. A typical workflow may require a conversion from some denomination to wei, then from wei to whatever you need.

>>> web3.toWei(Decimal('0.000000005'), 'ether')
5000000000
>>> web3.fromWei(5000000000, 'gwei')
Decimal('5')

Making transactions

There are a few options for making transactions:

  • sendTransaction()

    Use this method if:
    • you want to send ether from one account to another.

  • sendRawTransaction()

    Use this method if:
    • you want to sign the transaction elsewhere, e.g., a hardware wallet.

    • you want to broadcast a transaction through another provider, e.g., Infura.

    • you have some other advanced use case that requires more flexibility.

  • Contract Functions

    Use these methods if:
    • you want to interact with a contract. Web3.py parses the contract ABI and makes those functions available via the functions property.

  • construct_sign_and_send_raw_middleware()

    Use this middleware if:
    • you want to automate signing when using w3.eth.sendTransaction or ContractFunctions.

Note

The location of your keys (e.g., local or hosted) will have implications on these methods. Read about the differences here.

Looking up transactions

You can look up transactions using the web3.eth.getTransaction function.

>>> web3.eth.getTransaction('0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060')
{
    'blockHash': '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd',
    'blockNumber': 46147,
    'condition': None,
    'creates': None,
    'from': '0xA1E4380A3B1f749673E270229993eE55F35663b4',
    'gas': 21000,
    'gasPrice': 50000000000000,
    'hash': '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
    'input': '0x',
    'networkId': None,
    'nonce': 0,
    'publicKey': '0x376fc429acc35e610f75b14bc96242b13623833569a5bb3d72c17be7e51da0bb58e48e2462a59897cead8ab88e78709f9d24fd6ec24d1456f43aae407a8970e4',
    'r': '0x88ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d0',
    'raw': '0xf86780862d79883d2000825208945df9b87991262f6ba471f09758cde1c0fc1de734827a69801ca088ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d0a045e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a',
    's': '0x45e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a',
    'standardV': '0x1',
    'to': '0x5DF9B87991262F6BA471F09758CDE1c0FC1De734',
    'transactionIndex': 0,
    'v': '0x1c',
    'value': 31337,
}

If no transaction for the given hash can be found, then this function will instead return None.

Looking up receipts

Transaction receipts can be retrieved using the web3.eth.getTransactionReceipt API.

>>> web3.eth.getTransactionReceipt('0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060')
{
    'blockHash': '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd',
    'blockNumber': 46147,
    'contractAddress': None,
    'cumulativeGasUsed': 21000,
    'gasUsed': 21000,
    'logs': [],
    'logsBloom': '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    'root': '0x96a8e009d2b88b1483e6941e6812e32263b05683fac202abc622a3e31aed1957',
    'transactionHash': '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
    'transactionIndex': 0,
}

If the transaction has not yet been mined then this method will return None.

Working with Contracts

Given the following solidity source file stored at contract.sol.

contract StoreVar {

    uint8 public _myVar;
    event MyEvent(uint indexed _var);

    function setVar(uint8 _var) public {
        _myVar = _var;
        emit MyEvent(_var);
    }

    function getVar() public view returns (uint8) {
        return _myVar;
    }

}

The following example demonstrates a few things:

  • Compiling a contract from a sol file.

  • Estimating gas costs of a transaction.

  • Transacting with a contract function.

  • Waiting for a transaction receipt to be mined.

import sys
import time
import pprint

from web3.providers.eth_tester import EthereumTesterProvider
from web3 import Web3
from eth_tester import PyEVMBackend
from solcx import compile_source


def compile_source_file(file_path):
   with open(file_path, 'r') as f:
      source = f.read()

   return compile_source(source)


def deploy_contract(w3, contract_interface):
    tx_hash = w3.eth.contract(
        abi=contract_interface['abi'],
        bytecode=contract_interface['bin']).constructor().transact()

    address = w3.eth.getTransactionReceipt(tx_hash)['contractAddress']
    return address


w3 = Web3(EthereumTesterProvider(PyEVMBackend()))

contract_source_path = 'contract.sol'
compiled_sol = compile_source_file('contract.sol')

contract_id, contract_interface = compiled_sol.popitem()

address = deploy_contract(w3, contract_interface)
print(f'Deployed {contract_id} to: {address}\n')

store_var_contract = w3.eth.contract(address=address, abi=contract_interface["abi"])

gas_estimate = store_var_contract.functions.setVar(255).estimateGas()
print(f'Gas estimate to transact with setVar: {gas_estimate}')

if gas_estimate < 100000:
     print("Sending transaction to setVar(255)\n")
     tx_hash = store_var_contract.functions.setVar(255).transact()
     receipt = w3.eth.waitForTransactionReceipt(tx_hash)
     print("Transaction receipt mined:")
     pprint.pprint(dict(receipt))
     print("\nWas transaction successful?")
     pprint.pprint(receipt["status"])
else:
     print("Gas cost exceeds 100000")

Output:

Deployed <stdin>:StoreVar to: 0xF2E246BB76DF876Cef8b38ae84130F4F55De395b

Gas estimate to transact with setVar: 45535

Sending transaction to setVar(255)

Transaction receipt mined:
{'blockHash': HexBytes('0x837609ad0a404718c131ac5157373662944b778250a507783349d4e78bd8ac84'),
 'blockNumber': 2,
 'contractAddress': None,
 'cumulativeGasUsed': 43488,
 'gasUsed': 43488,
 'logs': [AttributeDict({'type': 'mined', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('0x50aa3ba0673243f1e60f546a12ab364fc2f6603b1654052ebec2b83d4524c6d0'), 'blockHash': HexBytes('0x837609ad0a404718c131ac5157373662944b778250a507783349d4e78bd8ac84'), 'blockNumber': 2, 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'data': '0x', 'topics': [HexBytes('0x6c2b4666ba8da5a95717621d879a77de725f3d816709b9cbe9f059b8f875e284'), HexBytes('0x00000000000000000000000000000000000000000000000000000000000000ff')]})],
 'status': 1,
 'transactionHash': HexBytes('0x50aa3ba0673243f1e60f546a12ab364fc2f6603b1654052ebec2b83d4524c6d0'),
 'transactionIndex': 0}

 Was transaction successful?
 1

Working with Contracts via ethPM

ethPM packages contain configured contracts ready for use. Web3’s ethpm module (web3.pm) extends Web3’s native Contract module, with a few modifications for how you instantiate Contract factories and instances.

All you need is the package name, version and ethPM registry address for the package you wish to use. An ethPM registry is an on-chain datastore for the release data associated with an ethPM package. You can find some sample registries to explore in the ethPM registry. Remember, you should only use packages from registries whose maintainer you trust not to inject malicious code!

In this example we will use the ethregistrar@3.0.0 package sourced from the ens.snakecharmers.eth registry.

web3.pm uses the Package class to represent an ethPM package. This object houses all of the contract assets within a package, and exposes them via an API. So, before we can interact with our package, we need to generate it as a Package instance.

from web3.auto.infura import w3

# Note. To use the web3.pm module, you will need to instantiate your w3 instance
# with a web3 provider connected to the chain on which your registry lives.

# The ethPM module is still experimental and subject to change,
# so for now we need to enable it via a temporary flag.
w3.enable_unstable_package_management_api()

# Then we need to set the registry address that we want to use.
# This should be an ENS address, but can also be a checksummed contract address.
w3.pm.set_registry("ens.snakecharmers.eth")

# This generates a Package instance of the target ethPM package.
ens_package = w3.pm.get_package("ethregistrar", "3.0.0")

Now that we have a Package representation of our target ethPM package, we can generate contract factories and instances from this Package. However, it’s important to note that some packages might be missing the necessary contract assets needed to generate an instance or a factory. You can use the ethPM CLI to figure out the available contract types and deployments within an ethPM package.

# To interact with a deployment located in an ethPM package.
# Note. This will only expose deployments located on the
# chain of the connected provider (in this example, mainnet)
mainnet_registrar = ens_package.deployments.get_instance("BaseRegistrarImplementation")

# Now you can treat mainnet_registrar like any other Web3 Contract instance!
mainnet_registrar.caller.balanceOf("0x123...")
> 0

mainnet_registrar.functions.approve("0x123", 100000).transact()
> 0x123abc...  # tx_hash

# To create a contract factory from a contract type located in an ethPM package.
registrar_factory = ens_package.get_contract_factory("BaseRegistrarImplementation")

# Now you can treat registrar_factory like any other Web3 Contract factory to deploy new instances!
# Note. This will deploy new instances to the chain of the connected provider (in this example, mainnet)
registrar_factory.constructor(...).transact()
> 0x456def...  # tx_hash

# To connect your Package to a new chain - simply pass it a new Web3 instance
# connected to your provider of choice. Now your factories will automatically
# deploy to this new chain, and the deployments available on a package will
# be automatically filtered to those located on the new chain.
from web3.auto.infura.goerli import w3 as goerli_w3
goerli_registrar = ens_package.update_w3(goerli_w3)

Working with an ERC20 Token Contract

Most fungible tokens on the Ethereum blockchain conform to the ERC20 standard. This section of the guide covers interacting with an existing token contract which conforms to this standard.

In this guide we will interact with an existing token contract that we have already deployed to a local testing chain. This guide assumes:

  1. An existing token contract at a known address.

  2. Access to the proper ABI for the given contract.

  3. A web3.main.Web3 instance connected to a provider with an unlocked account which can send transactions.

Creating the contract factory

First we need to create a contract instance with the address of our token contract and the ERC20 ABI.

>>> contract = w3.eth.contract(contract_address, abi=ABI)
>>> contract.address
'0xF2E246BB76DF876Cef8b38ae84130F4F55De395b'

Querying token metadata

Each token will have a total supply which represents the total number of tokens in circulation. In this example we’ve initialized the token contract to have 1 million tokens. Since this token contract is setup to have 18 decimal places, the raw total supply returned by the contract is going to have 18 additional decimal places.

>>> contract.functions.name().call()
'TestToken'
>>> contract.functions.symbol().call()
'TEST'
>>> decimals = contract.functions.decimals().call()
>>> decimals
18
>>> DECIMALS = 10 ** decimals
>>> contract.functions.totalSupply().call() // DECIMALS
1000000

Query account balances

Next we can query some account balances using the contract’s balanceOf function. The token contract we are using starts with a single account which we’ll refer to as alice holding all of the tokens.

>>> alice = '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'
>>> bob = '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF'
>>> raw_balance = contract.functions.balanceOf(alice).call()
>>> raw_balance
1000000000000000000000000
>>> raw_balance // DECIMALS
1000000
>>> contract.functions.balanceOf(bob).call()
0

Sending tokens

Next we can transfer some tokens from alice to bob using the contract’s transfer function.

>>> tx_hash = contract.functions.transfer(bob, 100).transact({'from': alice})
>>> tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
>>> contract.functions.balanceOf(alice).call()
999999999999999999999900
>>> contract.functions.balanceOf(bob).call()
100

Creating an approval for external transfers

Alice could also approve someone else to spend tokens from her account using the approve function. We can also query how many tokens we’re approved to spend using the allowance function.

>>> contract.functions.allowance(alice, bob).call()
0
>>> tx_hash = contract.functions.approve(bob, 200).transact({'from': alice})
>>> tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
>>> contract.functions.allowance(alice, bob).call()
200

Performing an external transfer

When someone has an allowance they can transfer those tokens using the transferFrom function.

>>> contract.functions.allowance(alice, bob).call()
200
>>> contract.functions.balanceOf(bob).call()
100
>>> tx_hash = contract.functions.transferFrom(alice, bob, 75).transact({'from': bob})
>>> tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
>>> contract.functions.allowance(alice, bob).call()
125
>>> contract.functions.balanceOf(bob).call()
175

Contract Unit Tests in Python

Here is an example of how one can use the pytest framework in python, Web3.py, eth-tester, and PyEVM to perform unit tests entirely in python without any additional need for a full featured ethereum node/client. To install needed dependencies you can use the pinned extra for eth_tester in web3 and pytest:

$ pip install web3[tester] pytest

Once you have an environment set up for testing, you can then write your tests like so:

import pytest

from web3 import (
    EthereumTesterProvider,
    Web3,
)


@pytest.fixture
def tester_provider():
    return EthereumTesterProvider()


@pytest.fixture
def eth_tester(tester_provider):
    return tester_provider.ethereum_tester


@pytest.fixture
def w3(tester_provider):
    return Web3(tester_provider)


@pytest.fixture
def foo_contract(eth_tester, w3):
    # For simplicity of this example we statically define the
    # contract code here. You might read your contracts from a
    # file, or something else to test with in your own code
    #
    # pragma solidity^0.5.3;
    #
    # contract Foo {
    #
    #     string public bar;
    #     event barred(string _bar);
    #
    #     constructor() public {
    #         bar = "hello world";
    #     }
    #
    #     function setBar(string memory _bar) public {
    #         bar = _bar;
    #         emit barred(_bar);
    #     }
    #
    # }

    deploy_address = eth_tester.get_accounts()[0]

    abi = """[{"anonymous":false,"inputs":[{"indexed":false,"name":"_bar","type":"string"}],"name":"barred","type":"event"},{"constant":false,"inputs":[{"name":"_bar","type":"string"}],"name":"setBar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[],"name":"bar","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]"""  # noqa: E501
    # This bytecode is the output of compiling with
    # solc version:0.5.3+commit.10d17f24.Emscripten.clang
    bytecode = """608060405234801561001057600080fd5b506040805190810160405280600b81526020017f68656c6c6f20776f726c640000000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6103bb806101166000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c01000000000000000000000000000000000000000000000000000000009004806397bc14aa14610058578063febb0f7e14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b61024c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac9291906102ea565b507f5f71ad82e16f082de5ff496b140e2fbc8621eeb37b36d59b185c3f1364bbd529816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561020f5780820151818401526020810190506101f4565b50505050905090810190601f16801561023c5780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102e25780601f106102b7576101008083540402835291602001916102e2565b820191906000526020600020905b8154815290600101906020018083116102c557829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061032b57805160ff1916838001178555610359565b82800160010185558215610359579182015b8281111561035857825182559160200191906001019061033d565b5b509050610366919061036a565b5090565b61038c91905b80821115610388576000816000905550600101610370565b5090565b9056fea165627a7a72305820ae6ca683d45ee8a71bba45caee29e4815147cd308f772c853a20dfe08214dbb50029"""  # noqa: E501

    # Create our contract class.
    FooContract = w3.eth.contract(abi=abi, bytecode=bytecode)
    # issue a transaction to deploy the contract.
    tx_hash = FooContract.constructor().transact({
        'from': deploy_address,
    })
    # wait for the transaction to be mined
    tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash, 180)
    # instantiate and return an instance of our contract.
    return FooContract(tx_receipt.contractAddress)


def test_initial_greeting(foo_contract):
    hw = foo_contract.caller.bar()
    assert hw == "hello world"


def test_can_update_greeting(w3, foo_contract):
    # send transaction that updates the greeting
    tx_hash = foo_contract.functions.setBar(
        "testing contracts is easy",
    ).transact({
        'from': w3.eth.accounts[1],
    })
    w3.eth.waitForTransactionReceipt(tx_hash, 180)

    # verify that the contract is now using the updated greeting
    hw = foo_contract.caller.bar()
    assert hw == "testing contracts is easy"


def test_updating_greeting_emits_event(w3, foo_contract):
    # send transaction that updates the greeting
    tx_hash = foo_contract.functions.setBar(
        "testing contracts is easy",
    ).transact({
        'from': w3.eth.accounts[1],
    })
    receipt = w3.eth.waitForTransactionReceipt(tx_hash, 180)

    # get all of the `barred` logs for the contract
    logs = foo_contract.events.barred.getLogs()
    assert len(logs) == 1

    # verify that the log's data matches the expected value
    event = logs[0]
    assert event.blockHash == receipt.blockHash
    assert event.args._bar == "testing contracts is easy"

Using Infura Rinkeby Node

Import your required libraries

from web3 import Web3, HTTPProvider

Initialize a web3 instance with an Infura node

w3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/YOUR_INFURA_KEY"))

Inject the middleware into the middleware onion

from web3.middleware import geth_poa_middleware
w3.middleware_onion.inject(geth_poa_middleware, layer=0)

Just remember that you have to sign all transactions locally, as infura does not handle any keys from your wallet ( refer to this )

transaction = contract.functions.function_Name(params).buildTransaction()
transaction.update({ 'gas' : appropriate_gas_amount })
transaction.update({ 'nonce' : w3.eth.getTransactionCount('Your_Wallet_Address') })
signed_tx = w3.eth.account.signTransaction(transaction, private_key)

P.S : the two updates are done to the transaction dictionary, since a raw transaction might not contain gas & nonce amounts, so you have to add them manually.

And finally, send the transaction

txn_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)

Tip : afterwards you can use the value stored in txn_hash, in an explorer like etherscan to view the transaction’s details