How to Programmatically Retrieve Uniswap V3 ETH/USDC Pool Balances with Python
This guide explains why accessing on‑chain data directly is the most trustless method, outlines the steps to query a Uniswap V3 ETH/USDC pool using Web3.py, provides full Python code, and offers practical tips for extending the approach to other pools and historical data.
Why Access the Blockchain Directly?
In DeFi, data equals money. Querying pool information directly from the chain provides reliable, decentralized, 24/7 automation and avoids latency, outages, or errors that centralized APIs may introduce.
Core Idea: Talk to the Smart Contract
Liquidity pools are smart contracts that hold user‑deposited tokens. To obtain a pool’s asset status, query the contract’s token balances (ETH/WETH and USDC) via the ERC‑20 balanceOf function. For Uniswap V3 this is the most straightforward and reliable method.
Step‑by‑Step Process
Connect to an Ethereum node Use a provider such as Infura, Alchemy, or a self‑hosted node.
Locate the target contracts Identify the Uniswap V3 ETH/USDC pool address and the token contract addresses for WETH and USDC.
Use a minimal ERC‑20 ABI Include only the balanceOf , decimals , and symbol functions.
Execute the query and parse results Call balanceOf(pool_address).call() for each token, then adjust for token decimals.
Visual overview of the workflow:
Hands‑On Demo: Query with Python and Web3.py
Install the library: pip install web3 You also need an Ethereum node URL (Infura, Alchemy, or a local node).
Key Addresses on Mainnet
Uniswap V3 Pool (ETH/USDC 0.3%) 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640 WETH Token 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 USDC Token
0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48Core Python Code
from web3 import Web3
# 1. Preparation
infura_url = "https://mainnet.infura.io/v3/72a0c21cf2854a9d810d8986b88b9e8d"
web3 = Web3(Web3.HTTPProvider(infura_url))
if not web3.is_connected():
raise ConnectionError("Unable to connect to Ethereum node")
print("Connected to Ethereum node!")
# 2. Define addresses and a minimal ERC‑20 ABI
pool_address = web3.to_checksum_address("0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640")
weth_address = web3.to_checksum_address("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
usdc_address = web3.to_checksum_address("0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
erc20_abi = [
{"constant": True, "inputs": [{"name": "_owner", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "balance", "type": "uint256"}], "type": "function"},
{"constant": True, "inputs": [], "name": "decimals", "outputs": [{"name": "", "type": "uint8"}], "type": "function"},
{"constant": True, "inputs": [], "name": "symbol", "outputs": [{"name": "", "type": "string"}], "type": "function"}
]
# 3. Create contract instances
weth_contract = web3.eth.contract(address=weth_address, abi=erc20_abi)
usdc_contract = web3.eth.contract(address=usdc_address, abi=erc20_abi)
# 4. Query raw balances
weth_balance_raw = weth_contract.functions.balanceOf(pool_address).call()
usdc_balance_raw = usdc_contract.functions.balanceOf(pool_address).call()
# 5. Adjust for decimals
weth_decimals = weth_contract.functions.decimals().call()
usdc_decimals = usdc_contract.functions.decimals().call()
weth_balance = weth_balance_raw / (10 ** weth_decimals)
usdc_balance = usdc_balance_raw / (10 ** usdc_decimals)
# 6. Get token symbols
weth_symbol = weth_contract.functions.symbol().call()
usdc_symbol = usdc_contract.functions.symbol().call()
# 7. Print results
print(f" {weth_symbol} balance: {weth_balance:.4f}")
print(f" {usdc_symbol} balance: {usdc_balance:.2f}")Code Walkthrough
web3.to_checksum_address ensures addresses are correctly formatted, avoiding case‑sensitivity issues.
erc20_abi includes only the balanceOf, decimals, and symbol functions, which are sufficient for balance queries.
.call() performs a read‑only operation that does not consume gas.
Handling Decimals – On‑chain balances are integers; dividing by 10**decimals converts them to human‑readable values (WETH = 18 decimals, USDC = 6 decimals).
Conclusion & Practical Recommendations
The method equips you with the core skill of automatically monitoring DEX pool assets directly from the blockchain, eliminating reliance on centralized services and providing a foundation for more advanced on‑chain tools.
Practical tips:
Extend to other pools – Locate the desired pool and token addresses (via Etherscan or DEX documentation) and reuse the same script.
Query historical data – Pass a block_identifier to .call(), e.g., balanceOf(pool_address).call(block_identifier=18000000), to retrieve balances at a specific block.
Select reliable node providers – For production, use paid, high‑availability services with fallback nodes.
Stay updated – DeFi evolves rapidly; monitor upcoming upgrades such as Uniswap V4.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
