@@ -18,7 +18,7 @@ Provides a single, consistent API for accessing blockchain data across multiple
1818- ** ⚡ Built-in Rate Limiting** - Automatic throttling with configurable limits and retry policies
1919- ** 🎯 Comprehensive API Coverage** - 28 blockchain operations with typed convenience methods
2020- ** 🔒 Type-safe Operations** - Typed data transfer objects, method enums, 100% mypy --strict
21- - ** 🚀 Optimized Bulk Operations** - Pagination engine, streaming decoder, range-splitting aggregators
21+ - ** 🚀 Optimized Bulk Operations** - Streaming aggregation for ` get_all_* ` plus ` iter_*_streaming ` for low-memory processing
2222- ** 🧩 Dependency Injection** - Configurable HTTP clients, caching, telemetry, and rate limiters
2323- ** ⛓️ Rust FFI** - Fast ABI decoding via PyO3 with LRU cache
2424
@@ -44,7 +44,7 @@ pip install .
4444import aiochainscan
4545print (f " aiochainscan v { aiochainscan.__version__ } " )
4646
47- from aiochainscan import get_balance, get_block
47+ from aiochainscan import ChainscanClient
4848print (" ✓ Installation successful!" )
4949```
5050
@@ -152,7 +152,7 @@ The **ChainscanClient** provides a unified interface with **30+ typed convenienc
152152
153153``` python
154154import asyncio
155- from aiochainscan.core.client import ChainscanClient
155+ from aiochainscan import ChainscanClient
156156
157157async def main ():
158158 # Create client — async context manager handles cleanup
@@ -162,7 +162,7 @@ async def main():
162162 print (f " Balance: { int (balance) / 10 ** 18 :.6f } ETH " )
163163
164164 txs = await client.get_transactions(' 0x...' ) # single page
165- all_txs = await client.get_all_transactions(' 0x...' ) # ALL (paginated )
165+ all_txs = await client.get_all_transactions(' 0x...' ) # ALL (streaming aggregation → list )
166166 tokens = await client.get_token_portfolio(' 0x...' ) # ERC-20 holdings
167167
168168 # Blocks & transactions
@@ -180,9 +180,9 @@ async def main():
180180
181181 # Event logs (single page or ALL)
182182 logs = await client.get_logs(' 0x...' , from_block = 0 )
183- all_logs = await client.get_all_logs(' 0x...' , from_block = 0 )
183+ all_logs = await client.get_all_logs(' 0x...' , from_block = 0 ) # streaming aggregation → list
184184
185- # Streaming for large datasets (~10MB RAM for 1M+ txs)
185+ # Preferred for large datasets (~10MB RAM for 1M+ txs)
186186 async for batch in client.iter_transactions_streaming(' 0x...' , batch_size = 1000 ):
187187 process(batch)
188188
@@ -201,63 +201,18 @@ client = ChainscanClient.from_config('blockscout_v2', 'ethereum')
201201client = ChainscanClient.from_config(' etherscan' , ' ethereum' )
202202```
203203
204- ### 4. ⚠️ Legacy Facade Functions (Deprecated)
205-
206- ** WARNING** : Facade functions are deprecated in v0.4.0 and will be removed in v0.5.0 due to critical connection pooling issues.
207-
208- <details >
209- <summary >Why are facade functions deprecated? (Click to expand)</summary >
210-
211- ** The Problem** : Each facade function call creates and destroys an HTTP client, preventing connection pooling:
212-
213- ``` python
214- # ❌ AVOID - Creates 100 separate HTTP clients (very slow!)
215- balances = await asyncio.gather(* [
216- get_balance(address = addr, api_kind = ' eth' , network = ' main' , api_key = key)
217- for addr in addresses # 100 addresses
218- ])
219- ```
220-
221- This causes:
222- - 100 TCP connection establishments
223- - 100 TLS handshakes
224- - Loss of HTTP/2 multiplexing
225- - High CPU load and API rate limits
204+ ### 4. Legacy API Purge (v0.5+)
226205
227- ** The Solution ** : Use ` ChainscanClient ` which maintains a persistent connection pool (see examples above) .
206+ Public usage is now ** ChainscanClient-only ** .
228207
229- </details >
208+ Removed legacy surfaces:
209+ - Top-level facade functions (` get_balance ` , ` get_block ` , etc.)
210+ - Legacy facade/context/url-builder orchestration services
211+ - Older pagination engines replaced by modern streaming aggregation
230212
231- For simple use cases, you can still use facade functions (but expect deprecation warnings):
232-
233- ``` python
234- import asyncio
235- from aiochainscan import get_balance, get_block
236-
237- async def main ():
238- # BlockScout (free, no API key needed)
239- balance = await get_balance(
240- address = ' 0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3' ,
241- api_kind = ' blockscout_sepolia' ,
242- network = ' sepolia' ,
243- api_key = ' '
244- )
245-
246- # Etherscan (requires API key)
247- block = await get_block(
248- tag = 17000000 ,
249- api_kind = ' eth' ,
250- network = ' main' ,
251- api_key = ' YOUR_ETHERSCAN_API_KEY'
252- )
213+ Use ` get_all_* ` when you need fully materialized results (it now uses streaming aggregation internally), and prefer ` iter_*_streaming ` for large datasets.
253214
254- print (f " Balance: { balance} wei " )
255- print (f " Block: # { block[' block_number' ]} " )
256-
257- asyncio.run(main())
258- ```
259-
260- ** Migration Path** : See [ MIGRATION_GUIDE.md] ( docs/MIGRATION_GUIDE.md ) for detailed migration instructions.
215+ Migration details: [ MIGRATION_GUIDE.md] ( docs/MIGRATION_GUIDE.md ) .
261216
262217### 5. Bulk Operations & Streaming
263218
@@ -301,7 +256,7 @@ For advanced use cases with custom rate limiting, retries, and dependency inject
301256
302257``` python
303258import asyncio
304- from aiochainscan.core.client import ChainscanClient
259+ from aiochainscan import ChainscanClient
305260from aiochainscan.core.method import Method
306261from aiochainscan.adapters.simple_rate_limiter import SimpleRateLimiter
307262from aiochainscan.adapters.retry_exponential import ExponentialBackoffRetry
@@ -353,7 +308,7 @@ The **ChainscanClient** makes it trivial to switch between different blockchain
353308
354309``` python
355310import asyncio
356- from aiochainscan.core.client import ChainscanClient
311+ from aiochainscan import ChainscanClient
357312from aiochainscan.core.method import Method
358313
359314async def check_multi_scanner_balance ():
@@ -395,29 +350,23 @@ async def check_multi_scanner_balance():
395350asyncio.run(check_multi_scanner_balance())
396351```
397352
398- ### Legacy Multiple Networks (Facade Functions)
399-
400- For simple cases, you can still use the legacy facade functions:
353+ ### Multiple Networks with ChainscanClient
401354
402355``` python
403356import asyncio
404- from aiochainscan import get_balance
357+ from aiochainscan import ChainscanClient
405358
406359async def check_balances ():
407- # Works with multiple scanners using legacy interface
408- networks = [
409- (' blockscout_sepolia ' , ' sepolia ' , ' ' ), # Blockscout (free)
410- (' eth ' , ' main ' , ' YOUR_ETHERSCAN_KEY ' ), # Etherscan
360+ address = " 0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3 "
361+ targets = [
362+ (" blockscout_v2 " , " ethereum " ),
363+ (" etherscan " , " ethereum " ),
411364 ]
412365
413- for api_kind, network, api_key in networks:
414- balance = await get_balance(
415- address = " 0x742d35Cc6634C0532925a3b8D9fa7a3D91D1e9b3" ,
416- api_kind = api_kind,
417- network = network,
418- api_key = api_key
419- )
420- print (f " { api_kind} { network} : { balance} wei " )
366+ for scanner_name, network in targets:
367+ async with ChainscanClient.from_config(scanner_name, network) as client:
368+ balance = await client.get_balance(address)
369+ print (f " { scanner_name} { network} : { balance} wei " )
421370
422371asyncio.run(check_balances())
423372```
@@ -435,7 +384,7 @@ export ETHERSCAN_KEY="your_etherscan_api_key"
435384
436385When using ` ChainscanClient.from_config() ` , you need to specify three key parameters:
437386
438- - ** scanner_name** : Provider name (` 'etherscan' ` , ` 'blockscout' ` , ` 'moralis' ` , etc. )
387+ - ** scanner_name** : Provider name (` 'etherscan' ` , ` 'blockscout' ` , ` 'blockscout_v2' ` )
439388- ** scanner_version** : API version (` 'v1' ` , ` 'v2' ` )
440389- ** network** : Chain name/ID (` 'eth' ` , ` 'ethereum' ` , ` 1 ` , ` 'base' ` , ` 8453 ` , etc.)
441390
@@ -456,20 +405,20 @@ When using `ChainscanClient.from_config()`, you need to specify three key parame
456405
457406## Available Interfaces
458407
459- The library provides two main interfaces for accessing blockchain data:
408+ The public interface is ** ChainscanClient ** .
460409
461410### 1. ChainscanClient (Recommended)
462411
463412The ** unified client** provides 30+ typed convenience methods:
464413
465414``` python
466- from aiochainscan.core.client import ChainscanClient
415+ from aiochainscan import ChainscanClient
467416
468417async with ChainscanClient.from_config(' blockscout_v2' , ' ethereum' ) as client:
469418 # Account
470419 balance = await client.get_balance(' 0x...' ) # Wei string
471420 txs = await client.get_transactions(' 0x...' ) # single page
472- all_txs = await client.get_all_transactions(' 0x...' ) # ALL (paginated )
421+ all_txs = await client.get_all_transactions(' 0x...' ) # ALL (streaming aggregation → list )
473422 itxs = await client.get_internal_transactions(' 0x...' ) # internal txs
474423 erc20 = await client.get_token_transfers(' 0x...' ) # ERC-20 transfers
475424 erc721 = await client.get_erc721_transfers(' 0x...' ) # ERC-721 transfers
@@ -506,7 +455,7 @@ async with ChainscanClient.from_config('blockscout_v2', 'ethereum') as client:
506455
507456 # Event Logs
508457 logs = await client.get_logs(' 0x...' , from_block = 0 ) # single page
509- all_logs = await client.get_all_logs(' 0x...' , from_block = 0 ) # ALL (paginated )
458+ all_logs = await client.get_all_logs(' 0x...' , from_block = 0 ) # ALL (streaming aggregation → list )
510459
511460 # Proxy / JSON-RPC
512461 result = await client.eth_call(' 0xTO' , ' 0xDATA' ) # eth_call
@@ -535,24 +484,18 @@ from aiochainscan.core.method import Method
535484result = await client.call(Method.ACCOUNT_BALANCE , address = ' 0x...' )
536485```
537486
538- ### 3. Legacy Facade Functions (Deprecated)
539-
540- Facade functions are deprecated in v0.4.0. Use ` ChainscanClient ` instead.
541-
542487## Error Handling
543488
544489``` python
545490import asyncio
491+ from aiochainscan import ChainscanClient
546492from aiochainscan.exceptions import ChainscanClientApiError
547493
548494async def main ():
549495 try :
550- balance = await get_balance(
551- address = ' 0x...' ,
552- api_kind = ' eth' ,
553- network = ' main' ,
554- api_key = ' YOUR_API_KEY'
555- )
496+ async with ChainscanClient.from_config(' etherscan' , ' ethereum' ) as client:
497+ balance = await client.get_balance(' 0x...' )
498+ print (balance)
556499 except ChainscanClientApiError as e:
557500 print (f " API Error: { e} " )
558501
0 commit comments