Skip to main content

🔵 BasePy SDK - Production-Ready Python SDK for Base Blockchain

The most efficient and reliable way to build on Base (Ethereum Layer 2)

Python 3.8+ License: MIT Production Ready Code style: black

🚀 80% fewer RPC calls - Proven in production
💰 Zero-cost ERC-20 decoding - Extract all token transfers FREE
🛡️ Battle-tested resilience - Circuit breaker, auto-retry, rate limiting
⚡ Production-grade - Thread-safe, cached, monitored


🎯 Why BasePy?

The Problem with Web3.py

When building production applications on Base, raw Web3.py has limitations:

❌ Repetitive boilerplate - Every token balance needs 3+ RPC calls
❌ No retry logic - Network errors crash your app
❌ No rate limiting - Get blocked by RPC providers
❌ Manual optimization - You implement caching yourself
❌ Base L2 complexity - Manual L1+L2 fee calculations

The BasePy Solution

✅ Smart batching - Get entire portfolio in 2 RPC calls (vs 10+)
✅ Automatic retry - Exponential backoff with circuit breaker
✅ Built-in rate limiting - Never get blocked
✅ Intelligent caching - 500x faster repeated queries
✅ Base L2 native - L1+L2 fees calculated automatically
✅ Zero-cost features - ERC-20 decoding from existing data


🏆 Performance Comparison

Real-world performance (Base Mainnet, December 2024):

Task BasePy SDK Web3.py Improvement
Portfolio (ETH + 3 tokens) 2 RPC calls, 1.66s 10+ RPC calls 80% fewer calls ✅
Decode ERC-20 transfers 0 additional RPC calls 1+ RPC calls per token 100% free ✅
Token metadata (cached) <1ms response 300-500ms 500x faster ✅
Multicall (4 operations) 1 RPC call 4 sequential calls 75% reduction ✅

Real Cost Impact:
For 1M portfolio checks at typical RPC pricing:

  • Web3.py: ~$100 (10 calls × $0.01/1000)
  • BasePy: ~$20 (2 calls × $0.01/1000)
  • You save: $80 per million requests (80% reduction) 💰

📦 Installation

pip install basepy-sdk

Requirements:

  • Python 3.8+
  • web3.py >= 6.0.0
  • eth-account >= 0.9.0

🚀 Quick Start

30 Seconds to Your First Request

from basepy import BaseClient

# Connect to Base Mainnet (or Sepolia testnet)
client = BaseClient()  # Mainnet
# client = BaseClient(chain_id=84532)  # Sepolia testnet

# Get complete portfolio (ETH + all common tokens)
portfolio = client.get_portfolio_balance("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1")

print(f"Wallet: {portfolio['address']}")
print(f"ETH: {portfolio['eth']['balance_formatted']:.6f}")
print(f"\nTokens with balance:")
for token_addr, info in portfolio['tokens'].items():
    if info['balance'] > 0:
        print(f"  {info['symbol']:6s}: {info['balance_formatted']:>12.6f}")

Output:

Wallet: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1
ETH: 1.234567

Tokens with balance:
  USDC  :  1000.500000
  DAI   :   250.000000

RPC calls: 2 (vs 10+ with Web3.py) 🎉


💎 Core Features

1. 🪙 Smart Portfolio Tracking

Get ETH + all token balances with minimal RPC calls:

from basepy import BaseClient

client = BaseClient()

# Get portfolio with common Base tokens
portfolio = client.get_portfolio_balance(
    address="0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
    include_common_tokens=True  # USDC, DAI, WETH, etc.
)

# Or specify exact tokens
usdc = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
dai = "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
portfolio = client.get_portfolio_balance(
    address="0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
    token_addresses=[usdc, dai]
)

print(f"Total assets: {portfolio['total_assets']}")
print(f"Tokens with balance: {portfolio['non_zero_tokens']}")

Cost: ~2 RPC calls (regardless of token count!) ⚡


2. 📊 Zero-Cost Transaction Analysis

Extract all ERC-20 transfers without additional RPC calls:

from basepy import BaseClient, Transaction

client = BaseClient()
tx = Transaction(client)

# Get complete transaction details
details = tx.get_full_transaction_details(
    "0x123...",
    include_token_metadata=True
)

print(f"Status: {details['status']}")
print(f"ETH transferred: {details['eth_value_formatted']} ETH")
print(f"Token transfers: {details['transfer_count']}")

for transfer in details['token_transfers']:
    print(f"  {transfer['symbol']}: {transfer['amount_formatted']}")

Advanced Analysis:

# Decode ALL ERC-20 transfers (zero cost!)
transfers = tx.decode_erc20_transfers("0x123...")

# Calculate balance changes for an address
changes = tx.get_balance_changes("0x123...", your_address)
print(f"ETH change: {changes['eth_change_formatted']:.6f} ETH")
for token, info in changes['token_changes'].items():
    print(f"{info['symbol']}: {info['change_formatted']}")

# Classify transaction type
classification = tx.classify_transaction("0x123...")
print(f"Type: {classification['type']}")  # 'swap', 'transfer', etc.
print(f"Complexity: {classification['complexity']}")

Cost: FREE - uses existing receipt data! 🎉


3. 💸 Send Transactions (Wallet Required)

Simple, production-ready transaction sending:

from basepy import BaseClient, Wallet, Transaction

# Initialize with wallet
client = BaseClient()
wallet = Wallet.from_private_key("0xYourPrivateKey...", client=client)
tx = Transaction(client, wallet)

# Send ETH with automatic gas optimization
tx_hash = tx.send_eth(
    to_address="0xRecipient...",
    amount=0.1,  # 0.1 ETH
    gas_strategy='fast',  # 'slow', 'standard', 'fast', 'instant'
    wait_for_receipt=True  # Wait for confirmation
)
print(f"Sent! TX: {tx_hash}")

# Send ERC-20 tokens
from basepy.abis import ERC20_ABI

usdc = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
tx_hash = tx.send_erc20(
    token_address=usdc,
    to_address="0xRecipient...",
    amount=100 * 10**6,  # 100 USDC (6 decimals)
    abi=ERC20_ABI,
    gas_strategy='standard'
)

Features:

  • ✅ Automatic gas estimation with buffer
  • ✅ Nonce management with collision detection
  • ✅ Transaction simulation before sending
  • ✅ Automatic retry with exponential backoff
  • ✅ Balance validation

4. ⚡ Batch & Multicall Operations

Execute multiple operations efficiently:

# Batch get balances
addresses = ["0xAddr1...", "0xAddr2...", "0xAddr3..."]
balances = client.batch_get_balances(addresses)

# Multicall - Multiple contract calls in 1 RPC request
from basepy.abis import ERC20_ABI

usdc = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
calls = [
    {'contract': usdc, 'abi': ERC20_ABI, 'function': 'name'},
    {'contract': usdc, 'abi': ERC20_ABI, 'function': 'symbol'},
    {'contract': usdc, 'abi': ERC20_ABI, 'function': 'decimals'},
    {'contract': usdc, 'abi': ERC20_ABI, 'function': 'totalSupply'},
]
results = client.multicall(calls)
print(results)  # ['USD Coin', 'USDC', 6, 1234567890...]

Cost: 1 RPC call (vs 4 sequential calls) 🚀


5. ⛽ Base L2 Fee Calculation

Get complete transaction cost breakdown:

# Estimate total cost (L1 + L2)
cost = client.estimate_total_fee({
    'from': wallet.address,
    'to': recipient,
    'value': 10**18,  # 1 ETH
    'data': '0x'
})

print(f"L2 execution cost: {cost['l2_fee_eth']:.6f} ETH")
print(f"L1 data cost: {cost['l1_fee_eth']:.6f} ETH")
print(f"Total cost: {cost['total_fee_eth']:.6f} ETH")

# Check if wallet can afford transaction
affordable = wallet.can_afford_transaction(
    to=recipient,
    value=0.1,
    buffer_percent=10
)
print(f"Can afford: {affordable}")

6. 🛡️ Production-Ready Resilience

Built-in reliability features (no configuration needed):

from basepy import BaseClient, Config

# Advanced configuration (optional)
config = Config()
config.MAX_RETRIES = 5
config.CACHE_TTL = 15  # seconds
config.RATE_LIMIT_REQUESTS = 100  # per minute
config.CIRCUIT_BREAKER_THRESHOLD = 5

client = BaseClient(config=config, environment='production')

# Monitor performance
stats = client.get_metrics()
print(f"Total requests: {sum(stats['requests'].values())}")
print(f"Cache hit rate: {stats['cache_hit_rate']:.1%}")
print(f"Avg latency: {stats['avg_latencies']}")

# Health check
health = client.health_check()
print(f"Status: {health['status']}")
print(f"Block number: {health['block_number']}")

Automatic Features:

  • ✅ Exponential backoff retry
  • ✅ Multiple RPC endpoint failover
  • ✅ Token bucket rate limiting
  • ✅ Circuit breaker pattern
  • ✅ Intelligent TTL caching
  • ✅ Thread-safe operations
  • ✅ Performance monitoring

7. 👛 Complete Wallet Management

from basepy import BaseClient, Wallet

client = BaseClient()

# Create new wallet
wallet = Wallet.create(client)

# Import from private key
wallet = Wallet.from_private_key("0x...", client)

# Import from mnemonic (BIP-39)
wallet = Wallet.from_mnemonic(
    "your twelve word mnemonic phrase here...",
    client=client,
    account_path="m/44'/60'/0'/0/0"  # Derivation path
)

# Import from keystore
wallet = Wallet.from_keystore(
    path="keystore.json",
    password="your-password",
    client=client
)

# Export to keystore
wallet.to_keystore(
    password="secure-password",
    output_path="backup.json"
)

# Wallet operations with caching
balance = wallet.get_balance(use_cache=True)
nonce = wallet.get_nonce(use_cache=True)
portfolio = wallet.get_portfolio(use_cache=True)

# Sign messages (EIP-191)
signature = wallet.sign_message("Hello, Base!")

# Sign typed data (EIP-712)
typed_data = {...}
signature = wallet.sign_typed_data(typed_data)

🆚 BasePy vs Web3.py

Feature Comparison

Feature BasePy Web3.py Winner
Portfolio balance get_portfolio_balance() (2 calls) Manual loops (10+ calls) BasePy (80% fewer)
ERC-20 decoding decode_erc20_transfers() (0 calls) Manual parsing (1+ calls/token) BasePy (100% free)
Multicall Native multicall() (1 call) Sequential (N calls) BasePy (N→1)
Retry logic ✅ Automatic exponential backoff ❌ Manual implementation BasePy
Rate limiting ✅ Token bucket built-in ❌ Not included BasePy
Circuit breaker ✅ Automatic failover ❌ Not available BasePy
Caching ✅ Intelligent TTL (500x speedup) ❌ Manual implementation BasePy
RPC failover ✅ Multi-endpoint auto-switch ❌ Manual switching BasePy
Thread safety ✅ Fully thread-safe ⚠️ Partial BasePy
Base L2 fees ✅ Native L1+L2 calculation ❌ Manual calculation BasePy
Wallet management ✅ Complete (create, import, export, sign) ⚠️ Basic signing only BasePy
Transaction mgmt ✅ Nonce collision handling, simulation ⚠️ Basic BasePy
Monitoring ✅ Built-in metrics & health checks ❌ Not included BasePy
Production ready ✅ Battle-tested ⚠️ Requires hardening BasePy

Code Comparison

Get portfolio balance:

# ❌ Web3.py - Verbose, 10+ RPC calls
from web3 import Web3

w3 = Web3(Web3.HTTPProvider(rpc_url))
eth_balance = w3.eth.get_balance(address)

tokens_data = {}
for token in [usdc, dai, weth]:
    contract = w3.eth.contract(address=token, abi=ERC20_ABI)
    balance = contract.functions.balanceOf(address).call()  # Call 1
    symbol = contract.functions.symbol().call()            # Call 2
    decimals = contract.functions.decimals().call()        # Call 3
    tokens_data[token] = {'balance': balance, 'symbol': symbol, 'decimals': decimals}
# Total: 1 + (3 × N tokens) = 10+ calls for 3 tokens

# ✅ BasePy - Simple, 2 RPC calls
from basepy import BaseClient

client = BaseClient()
portfolio = client.get_portfolio_balance(address, [usdc, dai, weth])
# Total: 2 calls (1 for ETH, 1 multicall for all tokens)

Decode token transfers:

# ❌ Web3.py - Manual, error-prone
receipt = w3.eth.get_transaction_receipt(tx_hash)
transfers = []
for log in receipt['logs']:
    if len(log['topics']) == 3 and log['topics'][0].hex() == TRANSFER_SIG:
        token = log['address']
        from_addr = '0x' + log['topics'][1].hex()[-40:]
        to_addr = '0x' + log['topics'][2].hex()[-40:]
        amount = int(log['data'].hex(), 16)
        transfers.append({'token': token, 'from': from_addr, 'to': to_addr, 'amount': amount})

# ✅ BasePy - Zero extra calls, automatic
from basepy import Transaction

tx = Transaction(client)
transfers = tx.decode_erc20_transfers(tx_hash)  # Done!

📚 Complete Examples

Example 1: DeFi Portfolio Tracker

from basepy import BaseClient

def track_portfolio(wallet_address):
    client = BaseClient()
    portfolio = client.get_portfolio_balance(wallet_address)
    
    print(f"📊 Portfolio for {wallet_address}\n")
    print(f"💰 ETH: {portfolio['eth']['balance_formatted']:.6f}")
    print(f"\n🪙 Tokens ({portfolio['non_zero_tokens']} with balance):")
    
    for token_addr, info in portfolio['tokens'].items():
        if info['balance'] > 0:
            print(f"  {info['symbol']:8s}: {info['balance_formatted']:>15.6f}")
    
    print(f"\n📈 Summary:")
    print(f"  Total assets: {portfolio['total_assets']}")
    print(f"  RPC calls used: ~2 (vs {portfolio['total_assets'] * 3}+ with Web3.py)")

track_portfolio("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1")

Example 2: Transaction Monitor

from basepy import BaseClient, Transaction

def analyze_transaction(tx_hash):
    client = BaseClient()
    tx = Transaction(client)
    
    # Get full details
    details = tx.get_full_transaction_details(tx_hash, include_token_metadata=True)
    
    # Calculate cost
    cost = tx.get_transaction_cost(tx_hash)
    
    print(f"🔍 Transaction: {tx_hash}")
    print(f"Status: {'✅ Success' if details['status'] == 'confirmed' else '❌ Failed'}")
    print(f"Block: {details['block_number']}")
    print(f"Gas used: {details['gas_used']:,}")
    print(f"Total cost: {cost['total_cost_eth']:.6f} ETH")
    print(f"  L2 execution: {cost['l2_cost_eth']:.6f} ETH")
    print(f"  L1 data: {cost['l1_cost_eth']:.6f} ETH")
    
    if details['eth_value'] > 0:
        print(f"\n💸 ETH Transfer: {details['eth_value_formatted']} ETH")
    
    if details['transfer_count'] > 0:
        print(f"\n🪙 Token Transfers ({details['transfer_count']}):")
        for t in details['token_transfers']:
            print(f"  {t['symbol']}: {t['amount_formatted']}")
    
    # Classify
    classification = tx.classify_transaction(tx_hash)
    print(f"\n🏷️  Type: {classification['type']}")
    print(f"Complexity: {classification['complexity']}")

analyze_transaction("0x...")

Example 3: Production Bot with Monitoring

from basepy import BaseClient, Wallet, Transaction
import time

def trading_bot():
    # Initialize with monitoring
    client = BaseClient(environment='production')
    wallet = Wallet.from_private_key(private_key, client)
    tx = Transaction(client, wallet)
    
    print("🤖 Trading bot started...")
    
    while True:
        try:
            # Check health
            health = client.health_check()
            if health['status'] != 'healthy':
                print(f"⚠️  Unhealthy: {health}")
                time.sleep(60)
                continue
            
            # Get portfolio
            portfolio = wallet.get_portfolio(use_cache=True)
            
            # Your trading logic here...
            
            # Monitor performance
            metrics = client.get_metrics()
            print(f"📊 Cache hit rate: {metrics['cache_hit_rate']:.1%}")
            print(f"📊 Avg latency: {metrics['avg_latencies']}")
            
            time.sleep(10)
            
        except Exception as e:
            print(f"❌ Error: {e}")
            time.sleep(30)

trading_bot()

See examples/ for more real-world code!


🏗️ Project Structure

basepy-sdk/
├── basepy/
│   ├── __init__.py          # Main exports
│   ├── client.py            # BaseClient with all RPC operations
│   ├── wallet.py            # Complete wallet management
│   ├── transactions.py      # Transaction operations
│   ├── abis.py              # Contract ABIs and constants
│   ├── utils.py             # Utility functions
│   └── exceptions.py        # Custom exceptions
│
├── examples/
│   ├── basic_usage.py       # Simple examples
│   ├── portfolio_tracker.py # DeFi portfolio tracker
│   ├── transaction_monitor.py # TX analysis
│   └── wallet_demo.py       # Complete wallet demo
│
├── tests/
│   ├── test_client.py       # Client tests
│   ├── test_wallet.py       # Wallet tests
│   └── test_transactions.py # Transaction tests
│
├── README.md                # This file
├── LICENSE                  # MIT License
├── setup.py                 # Package setup
├── pyproject.toml          # Modern Python config
└── requirements.txt         # Dependencies

⚙️ Configuration

Basic Configuration

from basepy import BaseClient, Config

# Use defaults (recommended)
client = BaseClient()

# Or customize
config = Config()
config.MAX_RETRIES = 5
config.CACHE_TTL = 15
config.RATE_LIMIT_REQUESTS = 100
config.CIRCUIT_BREAKER_THRESHOLD = 5

client = BaseClient(config=config)

Environment-Based Config

# Development (verbose logging)
client = BaseClient(environment='development')

# Production (optimized)
client = BaseClient(environment='production')

Custom RPC Endpoints

# Use your own RPC endpoints
custom_rpcs = [
    "https://mainnet.base.org",
    "https://base.llamarpc.com",
    "https://base.meowrpc.com",
]
client = BaseClient(chain_id=8453, rpc_urls=custom_rpcs)

🧪 Testing

# Install with dev dependencies
pip install -e ".[dev]"

# Run all tests
pytest tests/ -v

# Run with coverage
pytest tests/ --cov=basepy --cov-report=html

# Run specific test file
pytest tests/test_client.py -v

# Run with benchmarks
pytest tests/test_client.py --benchmark-only

📊 Performance Benchmarks

Tested on Base Mainnet (December 2024):

Operation Avg Time RPC Calls vs Web3.py
Portfolio (3 tokens) 1.66s 2 80% fewer calls
Decode ERC-20 transfers <10ms 0 100% free
Token metadata (cached) <1ms 0 500x faster
Multicall (4 functions) ~1s 1 75% fewer calls
Health check ~0.5s 2 N/A

Benchmarks run with pytest-benchmark on Base Mainnet


🛣️ Roadmap

✅ Completed (v1.0)

  • Core RPC operations
  • ERC-20 token support
  • Portfolio tracking (80% fewer calls)
  • Zero-cost transaction decoding
  • Complete wallet management
  • Automatic retry & failover
  • Rate limiting & circuit breaker
  • Intelligent caching
  • Base L2 fee calculation
  • Thread-safe operations
  • Performance monitoring
  • Comprehensive testing

🔜 Planned (v1.1-1.2)

  • ERC-721 (NFT) support
  • ERC-1155 (Multi-token) support
  • WebSocket support for events
  • ENS resolution
  • Price oracle integration
  • GraphQL support

🔮 Future (v2.0+)

  • Multi-chain support (Optimism, Arbitrum)
  • Advanced DeFi integrations
  • MEV protection
  • Account abstraction (ERC-4337)

🤝 Contributing

We welcome contributions! Here's how to get started:

# Fork and clone
git clone https://github.com/yourusername/basepy-sdk.git
cd basepy-sdk

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Format code
black basepy/
flake8 basepy/

# Type check
mypy basepy/

Please see CONTRIBUTING.md for detailed guidelines.


📄 License

MIT License - see LICENSE file for details.

TL;DR: Free to use in commercial and personal projects. Just keep the license notice.


🔗 Resources


📞 Support

Need help? We're here:


🙏 Acknowledgments

Built with ❤️ for the Base ecosystem:

  • Powered by Web3.py
  • Inspired by the Ethereum and Base communities
  • Thanks to all contributors and users

⭐ Star Us!

If BasePy makes your development easier, please star the repository!

It helps others discover the project and motivates us to keep improving.

GitHub stars



Built for developers who want to focus on building, not debugging RPC calls 🔵

Making Base blockchain development 10x easier, 10x faster, and 80% cheaper

Metadata

Release files for basepy-sdk 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for basepy-sdk 1.1.0
File Size Uploaded Provenance
basepy_sdk-1.1.0.tar.gz 352.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for basepy-sdk 1.1.0
File Interpreter ABI Platform
basepy_sdk-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 424.7 kB

Release files / basepy_sdk-1.1.0.tar.gz

Download URL basepy_sdk-1.1.0.tar.gz
Size 352.0 kB
Tags Source
SHA-256 checksum
How to use checksums
295a2d1fe3bb3bb89b9e5f7d48b8d14ef6cace2da0675e3a42cdcb6a6c0d7ac6
BLAKE2b-256 checksum
How to use checksums
331cda00c2e0a0357280e5a875a5de12569c1e352fc3442086f5023af8cd5b80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.1

Release files / basepy_sdk-1.1.0-py3-none-any.whl

Download URL basepy_sdk-1.1.0-py3-none-any.whl
Size 72.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a1cccf7a44ba1f8fc1ec0e1e71ca1f96714dc6b0b2529c95b3e967b0eeb69b5d
BLAKE2b-256 checksum
How to use checksums
fe450fba096cc4a74911962fa7a56118f488ac18d5252f232a9de37550dc0ca1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.1

Security for basepy-sdk 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page