TLDR:
Demonstrates connecting to Berachain Mainnet using Python and Web3.py via Chainstack endpoints
Shows how to query ERC-20 tokens, core Berachain tokens (BGT, HONEY), and monitor live transfers
Covers Proof-of-Liquidity concepts and real-time blockchain data monitoring
Provides practical scripts for read-only blockchain interactions without requiring private keys
Overview
Berachain is an innovative EVM-compatible blockchain that implements Proof-of-Liquidity (PoL) consensus. Unlike traditional Proof-of-Stake systems, Berachain’s PoL mechanism aligns network incentives through BGT (Berachain Governance Token) emissions and liquidity provision.
This tutorial will walk you through building practical Python applications that interact with Berachain Mainnet using Chainstack’s reliable RPC infrastructure. We’ll explore everything from basic connectivity to advanced monitoring capabilities, all while maintaining a read-only approach that’s perfect for learning and experimentation.
Prerequisites
Understanding Berachain architecture
Before writing code, let’s understand key Berachain concepts:
Core tokens
BERA - Native gas token, similar to ETH on Ethereum
BGT - Governance token that powers Proof-of-Liquidity
HONEY - Algorithmic stablecoin native to Berachain
Key contracts
WBERA (0x6969696969696969696969696969696969696969
) - Wrapped BERA token
BGT (0x656b95E550C07a9ffe548bd4085c72418Ceb1dba
) - Governance token
HONEY (0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce
) - Stablecoin
BeraChef (0xdf960E8F3F19C481dDE769edEDD439ea1a63426a
) - Proof-of-Liquidity manager
Let’s start with a simple connection script that verifies our setup and displays basic network information.
Create connection.py
:
from web3 import Web3
import textwrap
# Connect to Berachain Mainnet via Chainstack
RPC_URL = "YOUR_CHAINSTACK_ENDPOINT"
w3 = Web3(Web3.HTTPProvider( RPC_URL ))
assert w3.is_connected(), "❌ Check your RPC URL 🔌"
# Display connection info
print (textwrap.dedent( f """
✅ Connected to Berachain Mainnet
• Chain ID : { w3.eth.chain_id }
• Latest Block: { w3.eth.block_number }
• Base Fee : { w3.from_wei(w3.eth.fee_history( 1 , 'latest' )[ 'baseFeePerGas' ][ - 1 ], 'gwei' ) :.3f} Gwei
""" ))
Key concepts demonstrated:
Establishing Web3 connection to Berachain
Verifying connectivity with is_connected()
Querying basic network information (chain ID, latest block, gas fees)
Working with wei-to-gwei conversions
ERC-20 token interactions
Next, let’s interact with ERC-20 tokens through node calls, starting with WBERA (Wrapped BERA).
Create wbera_query.py
:
from web3 import Web3
from eth_utils import to_checksum_address
# Connect to Berachain Mainnet via Chainstack
RPC_URL = "YOUR_CHAINSTACK_ENDPOINT"
w3 = Web3(Web3.HTTPProvider( RPC_URL ))
# WBERA token address on Mainnet
wbera = to_checksum_address( "0x6969696969696969696969696969696969696969" )
def get_token_info ( token_address ):
"""Get basic token information using low-level calls"""
# Query token symbol
symbol_data = w3.eth.call({
"to" : token_address,
"data" : w3.keccak( text = "symbol()" )[: 4 ]
})
# Query token name
name_data = w3.eth.call({
"to" : token_address,
"data" : w3.keccak( text = "name()" )[: 4 ]
})
# Query decimals
decimals_data = w3.eth.call({
"to" : token_address,
"data" : w3.keccak( text = "decimals()" )[: 4 ]
})
# Query total supply
supply_data = w3.eth.call({
"to" : token_address,
"data" : w3.keccak( text = "totalSupply()" )[: 4 ]
})
# Parse responses
symbol = symbol_data.rstrip( b " \x00 " ).decode()
name = name_data.rstrip( b " \x00 " ).decode()
decimals = int .from_bytes(decimals_data, "big" )
supply = int .from_bytes(supply_data, "big" ) / ( 10 ** decimals)
return {
"symbol" : symbol,
"name" : name,
"decimals" : decimals,
"total_supply" : supply
}
# Get WBERA information
wbera_info = get_token_info(wbera)
print ( f "🪙 Token: { wbera_info[ 'name' ] } ( { wbera_info[ 'symbol' ] } )" )
print ( f "📊 Decimals: { wbera_info[ 'decimals' ] } " )
print ( f "📈 Total Supply: { wbera_info[ 'total_supply' ] :,.2f} " )
Key concepts demonstrated:
Using w3.keccak()
to generate function selectors
Making contract calls with w3.eth.call()
Parsing contract responses and handling different data types
Working with ERC-20 standard functions
Core Berachain tokens
Let’s explore Berachain’s core tokens: BGT and HONEY.
from web3 import Web3
from eth_utils import to_checksum_address
# Connect to Berachain Mainnet via Chainstack
RPC_URL = "YOUR_CHAINSTACK_ENDPOINT"
w3 = Web3(Web3.HTTPProvider( RPC_URL ))
# Core Berachain token addresses
bgt = to_checksum_address( "0x656b95E550C07a9ffe548bd4085c72418Ceb1dba" ) # BGT - governance/PoL
honey = to_checksum_address( "0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce" ) # HONEY - stablecoin
def get_token_supply ( token_address ):
"""Get total supply for a token"""
sig_total = w3.keccak( text = "totalSupply()" )[: 4 ]
supply_raw = int .from_bytes(w3.eth.call({ "to" : token_address, "data" : sig_total}), "big" )
return supply_raw / 1e18
# Query total supplies
bgt_supply = get_token_supply(bgt)
honey_supply = get_token_supply(honey)
print ( "🐻 Berachain Core Token Supplies" )
print ( "=" * 35 )
print ( f "🗳️ BGT (Governance): { bgt_supply :,.0f} " )
print ( f "🍯 HONEY (Stablecoin): { honey_supply :,.0f} " )
# Additional insights
print ( f " \n 📊 Insights:" )
print ( f "• BGT powers Proof-of-Liquidity consensus" )
print ( f "• HONEY is overcollateralized by BERA" )
print ( f "• Current BGT/HONEY ratio: { bgt_supply / honey_supply :.3f} " )
Key concepts demonstrated:
Querying multiple token contracts efficiently
Understanding Berachain’s tokenomics
Creating reusable functions for common operations
Live transfer monitoring
One of the most powerful features is monitoring live blockchain activity. Let’s track WBERA transfers in real-time.
from web3 import Web3
from eth_utils import to_checksum_address
import time
# Connect to Berachain Mainnet via Chainstack
RPC_URL = "YOUR_CHAINSTACK_ENDPOINT"
w3 = Web3(Web3.HTTPProvider( RPC_URL ))
# WBERA token setup
wbera = to_checksum_address( "0x6969696969696969696969696969696969696969" )
decimals = 18
print ( "🐻 WBERA Live Transfer Monitor" )
print ( "=" * 40 )
print ( f "📍 WBERA Contract: { wbera } " )
# ERC-20 Transfer event signature
TRANSFER_SIG = w3.keccak( text = "Transfer(address,address,uint256)" ).hex()
try :
latest = w3.eth.block_number
print ( f "🔗 Latest Block: { latest } " )
# Query recent transfer logs
block_range = 1000
from_block = latest - block_range
print ( f "🔍 Scanning blocks { from_block } to { latest } ( { block_range } blocks)" )
logs = w3.eth.get_logs({
"fromBlock" : from_block,
"toBlock" : latest,
"address" : wbera,
"topics" : [ TRANSFER_SIG ]
})
print ( f "✅ Found { len (logs) } WBERA transfers in the last { block_range } blocks" )
if logs:
print ( " \n 📋 Recent transfers:" )
for i, lg in enumerate (logs[ - 5 :]): # Show 5 most recent
try :
# Extract addresses from topics
from_addr = "0x" + lg[ "topics" ][ 1 ].hex()[ - 40 :]
to_addr = "0x" + lg[ "topics" ][ 2 ].hex()[ - 40 :]
# Extract amount from data
if isinstance (lg[ "data" ], str ):
data_hex = lg[ "data" ][ 2 :] if lg[ "data" ].startswith( '0x' ) else lg[ "data" ]
amount = int (data_hex, 16 ) / 10 ** decimals
else :
amount = int .from_bytes(lg[ "data" ], "big" ) / 10 ** decimals
# Get block info for timestamp
block_info = w3.eth.get_block(lg[ "blockNumber" ])
timestamp = time.strftime( '%H:%M:%S' , time.localtime(block_info[ "timestamp" ]))
print ( f " { i + 1 } . Block { lg[ 'blockNumber' ] } @ { timestamp } " )
print ( f " { from_addr[: 10 ] } ... { from_addr[ - 6 :] } → { to_addr[: 10 ] } ... { to_addr[ - 6 :] } " )
print ( f " 💰 { amount :.6f} WBERA" )
print ()
except Exception as e:
print ( f " ❌ Error parsing transfer { i + 1 } : { e } " )
except Exception as e:
print ( f "❌ Error querying transfers: { e } " )
Key concepts demonstrated:
Event signature generation with w3.keccak()
Querying historical logs with w3.eth.get_logs()
Parsing event data from topics and data fields
Real-time blockchain monitoring techniques
Finally, let’s create a beautiful, comprehensive dashboard using the Rich library.
from web3 import Web3
from eth_utils import to_checksum_address
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
import time
# Connect to Berachain Mainnet via Chainstack
RPC_URL = "YOUR_CHAINSTACK_ENDPOINT"
# Initialize
console = Console()
w3 = Web3(Web3.HTTPProvider( RPC_URL ))
# Contract addresses
wbera = to_checksum_address( "0x6969696969696969696969696969696969696969" )
bgt = to_checksum_address( "0x656b95E550C07a9ffe548bd4085c72418Ceb1dba" )
honey = to_checksum_address( "0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce" )
def get_network_info ():
"""Get basic network information"""
fee_history = w3.eth.fee_history( 1 , 'latest' )
return {
'chain_id' : w3.eth.chain_id,
'block_number' : w3.eth.block_number,
'base_fee' : w3.from_wei(fee_history[ 'baseFeePerGas' ][ - 1 ], 'gwei' )
}
def get_token_supply ( address ):
"""Get total supply for a token"""
sig_total = w3.keccak( text = "totalSupply()" )[: 4 ]
supply_raw = int .from_bytes(w3.eth.call({ "to" : address, "data" : sig_total}), "big" )
return supply_raw / 1e18
def main ():
console.print( " \n 🐻 [bold cyan]Berachain Mainnet Dashboard[/bold cyan] 🚀" , justify = "center" )
# Network Info Panel
network = get_network_info()
network_text = f """
[green]✅ Connected to Berachain Mainnet[/green]
[blue]• Chain ID:[/blue] { network[ 'chain_id' ] }
[blue]• Latest Block:[/blue] { network[ 'block_number' ] :,}
[blue]• Base Fee:[/blue] { network[ 'base_fee' ] :.3f} Gwei
"""
console.print(Panel(network_text.strip(), title = "🔗 Network Status" , border_style = "green" ))
# Token Supplies Table
table = Table( title = "📊 Token Supplies" )
table.add_column( "Token" , style = "cyan" , no_wrap = True )
table.add_column( "Symbol" , style = "magenta" )
table.add_column( "Total Supply" , style = "green" , justify = "right" )
table.add_column( "Type" , style = "yellow" )
# Get token supplies
bgt_supply = get_token_supply(bgt)
honey_supply = get_token_supply(honey)
table.add_row( "BGT" , "BGT" , f " { bgt_supply :,.0f} " , "Governance/PoL" )
table.add_row( "HONEY" , "HONEY" , f " { honey_supply :,.0f} " , "Stablecoin" )
console.print(table)
# Footer
console.print( " \n [dim]🔄 Refresh this dashboard by running the script again![/dim]" , justify = "center" )
if __name__ == "__main__" :
main()
Conclusion
This tutorial provided a comprehensive introduction to Berachain development using Python and Chainstack’s reliable infrastructure. You’ve learned how to:
Connect to Berachain Mainnet using web3.py
Query ERC-20 tokens and core Berachain assets
Monitor live blockchain activity and transfers
Build beautiful terminal dashboards with Rich
Understand Berachain’s unique Proof-of-Liquidity system
The read-only approach demonstrated here is perfect for learning, monitoring, and building analytics applications. As you continue your Berachain development journey, these foundational skills will serve as the building blocks for more complex applications.
About the author
Ake Director of Developer Experience @ Chainstack
Talk to me all things Web3
20 years in technology | 8+ years in Web3 full time years experience
Trusted advisor helping developers navigate the complexities of blockchain infrastructure