Chainscan API async Python wrapper
Project description
aiochainscan
Async Python wrapper for blockchain explorer APIs with unified ChainscanClient interface.
Provides a single, consistent API for accessing blockchain data across multiple scanners (Etherscan, BlockScout, Moralis, etc.) with logical method calls and automatic scanner management.
Features
- 🆕 Unified ChainscanClient - Single interface for all blockchain scanners with logical method calls
- 🔄 Easy Scanner Switching - Switch between Etherscan, BlockScout, Moralis, etc. with one config change
- 📡 Real-time Blockchain Data - Access to 15+ networks including Ethereum, BSC, Polygon, Arbitrum, Optimism, Base
- ⚡ Built-in Rate Limiting - Automatic throttling with configurable limits and retry policies
- 🎯 Comprehensive API Coverage - 17+ blockchain operations (balance, transactions, logs, blocks, contracts, tokens)
- 🔒 Type-safe Operations - Typed data transfer objects and method enums for stable API responses
- 🚀 Optimized Bulk Operations - High-performance range-splitting aggregators for large datasets
- 🧩 Dependency Injection - Configurable HTTP clients, caching, telemetry, and rate limiters
Supported Networks
Etherscan API: Ethereum, BSC, Polygon, Arbitrum, Optimism, Base, Fantom, Gnosis, and more EVM chains (Base supported via Etherscan V2) Blockscout: Public blockchain explorers (no API key needed) - Sepolia, Gnosis, Polygon, and others Moralis: Multi-chain Web3 API - Ethereum, BSC, Polygon, Arbitrum, Base, Optimism, Avalanche
Installation
# From GitHub (current method)
pip install git+https://github.com/VaitaR/aiochainscan.git
# Or clone and install
git clone https://github.com/VaitaR/aiochainscan.git
cd aiochainscan
pip install .
Verify installation:
import aiochainscan
print(f"aiochainscan v{aiochainscan.__version__}")
from aiochainscan import get_balance, get_block
print("✓ Installation successful!")
Quick Start
1. Unified ChainscanClient (Recommended)
The ChainscanClient provides a unified interface for all blockchain scanners with logical method calls:
import asyncio
from aiochainscan.core.client import ChainscanClient
from aiochainscan.core.method import Method
async def main():
# Create client for any scanner using simple config
client = ChainscanClient.from_config(
'blockscout', # Provider name (version defaults to 'v1')
'ethereum' # Chain name/ID
)
# Use logical methods - scanner details hidden under the hood
balance = await client.call(Method.ACCOUNT_BALANCE, address='0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3')
print(f"Balance: {balance} wei ({int(balance) / 10**18:.6f} ETH)")
# Switch to Etherscan easily (requires API key)
client = ChainscanClient.from_config(
'etherscan', # Provider name (version defaults to 'v2')
'ethereum' # Chain name
)
block = await client.call(Method.BLOCK_BY_NUMBER, block_number='latest')
print(f"Latest block: #{block['number']}")
# Use Base network through Etherscan (requires ETHERSCAN_KEY)
client = ChainscanClient.from_config(
'etherscan', # Same provider (version defaults to 'v2')
'base' # Chain name
)
balance = await client.call(Method.ACCOUNT_BALANCE, address='0x...')
print(f"Base balance: {balance} wei")
# Same interface for any scanner!
await client.close()
asyncio.run(main())
2. Legacy Facade Functions
For simple use cases, you can also use the legacy facade functions (maintained for backward compatibility):
import asyncio
from aiochainscan import get_balance, get_block
async def main():
# BlockScout (free, no API key needed)
balance = await get_balance(
address='0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3',
api_kind='blockscout_sepolia',
network='sepolia',
api_key=''
)
# Etherscan (requires API key)
block = await get_block(
tag=17000000,
api_kind='eth',
network='main',
api_key='YOUR_ETHERSCAN_API_KEY'
)
print(f"Balance: {balance} wei")
print(f"Block: #{block['block_number']}")
asyncio.run(main())
2. Optimized Bulk Operations
import asyncio
from aiochainscan import get_all_transactions_optimized
async def main():
# Fetch all transactions for an address efficiently
# Uses range splitting and respects rate limits
transactions = await get_all_transactions_optimized(
address='0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3',
api_kind='blockscout_sepolia', # Works with Blockscout too
network='sepolia',
api_key='',
max_concurrent=5, # Parallel requests
max_offset=10000 # Max results per request
)
print(f"Found {len(transactions)} transactions")
asyncio.run(main())
Advanced Usage
ChainscanClient with Custom Configuration
For advanced use cases with custom rate limiting, retries, and dependency injection:
import asyncio
from aiochainscan.core.client import ChainscanClient
from aiochainscan.core.method import Method
from aiochainscan.adapters.simple_rate_limiter import SimpleRateLimiter
from aiochainscan.adapters.retry_exponential import ExponentialBackoffRetry
async def main():
# Create custom rate limiter and retry policy
rate_limiter = SimpleRateLimiter(requests_per_second=1)
retry_policy = ExponentialBackoffRetry(attempts=3)
# Create client with custom configuration
client = ChainscanClient(
scanner_name='etherscan', # Provider name
scanner_version='v2', # API version
api_kind='eth', # Scanner identifier
network='main', # Network name
api_key='YOUR_ETHERSCAN_API_KEY',
throttler=rate_limiter, # Custom rate limiter
retry_options=retry_policy # Custom retry policy
)
try:
# Use logical methods with automatic routing
balance = await client.call(
Method.ACCOUNT_BALANCE,
address="0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3"
)
# Get transaction history
transactions = await client.call(
Method.ACCOUNT_TRANSACTIONS,
address="0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3",
page=1,
offset=100
)
print(f"Balance: {balance} wei")
print(f"Recent transactions: {len(transactions)}")
finally:
await client.close()
asyncio.run(main())
Easy Scanner Switching with ChainscanClient
The ChainscanClient makes it trivial to switch between different blockchain scanners:
import asyncio
from aiochainscan.core.client import ChainscanClient
from aiochainscan.core.method import Method
async def check_multi_scanner_balance():
address = "0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3"
# Same code works with any scanner - just change config!
scanners = [
# BlockScout (free, no API key needed)
('blockscout', 'v1', 'eth', ''),
# Etherscan (requires API key)
('etherscan', 'v2', 'eth', 'YOUR_ETHERSCAN_API_KEY'),
# Moralis (requires API key)
('moralis', 'v1', 'eth', 'YOUR_MORALIS_API_KEY'),
]
for scanner_name, version, network, api_key in scanners:
try:
client = ChainscanClient.from_config(
scanner_name=scanner_name,
scanner_version=version,
network=network
)
# Same method call for all scanners!
balance = await client.call(Method.ACCOUNT_BALANCE, address=address)
if balance and str(balance).isdigit():
eth_balance = int(balance) / 10**18
print(f"✅ {scanner_name}: {eth_balance:.6f} ETH")
else:
print(f"⚠️ {scanner_name}: {balance}")
await client.close()
except Exception as e:
print(f"❌ {scanner_name}: {e}")
asyncio.run(check_multi_scanner_balance())
Legacy Multiple Networks (Facade Functions)
For simple cases, you can still use the legacy facade functions:
import asyncio
from aiochainscan import get_balance
async def check_balances():
# Works with multiple scanners using legacy interface
networks = [
('blockscout_sepolia', 'sepolia', ''), # Blockscout (free)
('eth', 'main', 'YOUR_ETHERSCAN_KEY'), # Etherscan
('moralis', 'eth', 'YOUR_MORALIS_KEY'), # Moralis
]
for api_kind, network, api_key in networks:
balance = await get_balance(
address="0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3",
api_kind=api_kind,
network=network,
api_key=api_key
)
print(f"{api_kind} {network}: {balance} wei")
asyncio.run(check_balances())
Environment Variables
Set API keys as environment variables:
export ETHERSCAN_KEY="your_etherscan_api_key"
export MORALIS_API_KEY="your_moralis_api_key"
# Blockscout and some networks work without API keys
Configuration Parameters
When using ChainscanClient.from_config(), you need to specify three key parameters:
- scanner_name: Provider name (
'etherscan','blockscout','moralis', etc.) - scanner_version: API version (
'v1','v2') - network: Chain name/ID (
'eth','ethereum',1,'base',8453, etc.)
Common Configurations:
| Provider | scanner_name | default_version | network | API Key |
|---|---|---|---|---|
| BlockScout Ethereum | 'blockscout' |
v1 |
'ethereum' |
❌ Not required |
| BlockScout Polygon | 'blockscout' |
v1 |
'polygon' |
❌ Not required |
| Etherscan Ethereum | 'etherscan' |
v2 |
'ethereum' |
✅ ETHERSCAN_KEY |
| Etherscan Base | 'etherscan' |
v2 |
'base' |
✅ ETHERSCAN_KEY |
| Moralis Ethereum | 'moralis' |
v1 |
'ethereum' |
✅ MORALIS_API_KEY |
Network parameter supports both names and chain IDs:
'ethereum','eth',1- Ethereum'base',8453- Base'polygon','matic'- Polygon'bsc','binance',56- Binance Smart Chain
Available Interfaces
The library provides two main interfaces for accessing blockchain data:
1. ChainscanClient (Recommended)
The unified client provides a single interface for all blockchain scanners with logical method calls:
from aiochainscan.core.client import ChainscanClient
from aiochainscan.core.method import Method
# Create client for any scanner (versions default automatically)
client = ChainscanClient.from_config('blockscout', 'ethereum') # v1 default
# Use logical methods - scanner details hidden
balance = await client.call(Method.ACCOUNT_BALANCE, address='0x...')
logs = await client.call(Method.EVENT_LOGS, address='0x...', **params)
block = await client.call(Method.BLOCK_BY_NUMBER, block_number='latest')
# Easy scanner switching - same interface!
client = ChainscanClient.from_config('etherscan', 'ethereum') # v2 default
balance = await client.call(Method.ACCOUNT_BALANCE, address='0x...')
Key Methods Available:
ACCOUNT_BALANCE- Get account balanceACCOUNT_TRANSACTIONS- Get account transaction historyACCOUNT_INTERNAL_TXS- Get internal transactionsBLOCK_BY_NUMBER- Get block informationTX_BY_HASH- Get transaction detailsEVENT_LOGS- Get contract event logsTOKEN_BALANCE- Get ERC-20 token balanceCONTRACT_ABI- Get contract ABI- And more methods (17 total for full-featured scanners)
2. Legacy Facade Functions
For simple use cases, the library also provides legacy facade functions (maintained for backward compatibility):
get_balance()- Get account balanceget_block()- Get block informationget_transaction()- Get transaction detailsget_eth_price()- Get ETH/USD priceget_all_transactions_optimized()- Fetch all transactions efficiently
All interfaces support dependency injection for customizing HTTP clients, rate limiters, retries, and caching.
Error Handling
import asyncio
from aiochainscan.exceptions import ChainscanClientApiError
async def main():
try:
balance = await get_balance(
address='0x...',
api_kind='eth',
network='main',
api_key='YOUR_API_KEY'
)
except ChainscanClientApiError as e:
print(f"API Error: {e}")
asyncio.run(main())
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiochainscan-0.2.2.tar.gz.
File metadata
- Download URL: aiochainscan-0.2.2.tar.gz
- Upload date:
- Size: 181.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8aa536d1db39a54477b6e8202ffa454cb52a378f16024259d0189424f263023
|
|
| MD5 |
f4039b9a4c86c4a5cdc9c7c53f977f84
|
|
| BLAKE2b-256 |
21a233d2617b626fe3a074299d34072e175679c78f4bfa676d9530e9c18fc2d2
|
Provenance
The following attestation bundles were made for aiochainscan-0.2.2.tar.gz:
Publisher:
ci.yml on VaitaR/aiochainscan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiochainscan-0.2.2.tar.gz -
Subject digest:
f8aa536d1db39a54477b6e8202ffa454cb52a378f16024259d0189424f263023 - Sigstore transparency entry: 597646242
- Sigstore integration time:
-
Permalink:
VaitaR/aiochainscan@ee3d8ed87132c99c63ff57fdef86a49f2222de46 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/VaitaR
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@ee3d8ed87132c99c63ff57fdef86a49f2222de46 -
Trigger Event:
release
-
Statement type:
File details
Details for the file aiochainscan-0.2.2-py3-none-any.whl.
File metadata
- Download URL: aiochainscan-0.2.2-py3-none-any.whl
- Upload date:
- Size: 168.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf39d7d32075e5049f98706e396608bb7f9167cf7c977599c065600584be79e3
|
|
| MD5 |
52549cd83721c3084cea022fbed1bd2a
|
|
| BLAKE2b-256 |
df511eabcb886972ff4fd9f1a4d5b07200bf896033220adc71b5429071f5aab1
|
Provenance
The following attestation bundles were made for aiochainscan-0.2.2-py3-none-any.whl:
Publisher:
ci.yml on VaitaR/aiochainscan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiochainscan-0.2.2-py3-none-any.whl -
Subject digest:
cf39d7d32075e5049f98706e396608bb7f9167cf7c977599c065600584be79e3 - Sigstore transparency entry: 597646244
- Sigstore integration time:
-
Permalink:
VaitaR/aiochainscan@ee3d8ed87132c99c63ff57fdef86a49f2222de46 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/VaitaR
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@ee3d8ed87132c99c63ff57fdef86a49f2222de46 -
Trigger Event:
release
-
Statement type: