Skip to main content

Production-ready Python SDK for Base blockchain with 80% fewer RPC calls, zero-cost ERC-20 decoding, and built-in resilience

Project description

๐Ÿ”ต 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


๐ŸŽฏ Quick Links


Built for developers who want to focus on building, not debugging RPC calls ๐Ÿ”ต

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

basepy_sdk-1.1.0.tar.gz (352.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

basepy_sdk-1.1.0-py3-none-any.whl (72.7 kB view details)

Uploaded Python 3

File details

Details for the file basepy_sdk-1.1.0.tar.gz.

File metadata

  • Download URL: basepy_sdk-1.1.0.tar.gz
  • Upload date:
  • Size: 352.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.1

File hashes

Hashes for basepy_sdk-1.1.0.tar.gz
Algorithm Hash digest
SHA256 295a2d1fe3bb3bb89b9e5f7d48b8d14ef6cace2da0675e3a42cdcb6a6c0d7ac6
MD5 c4016f4669bcdee7a48a235299607d70
BLAKE2b-256 331cda00c2e0a0357280e5a875a5de12569c1e352fc3442086f5023af8cd5b80

See more details on using hashes here.

File details

Details for the file basepy_sdk-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: basepy_sdk-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 72.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.1

File hashes

Hashes for basepy_sdk-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a1cccf7a44ba1f8fc1ec0e1e71ca1f96714dc6b0b2529c95b3e967b0eeb69b5d
MD5 f4405131ba8e9f2c529333b9a9981e7f
BLAKE2b-256 fe450fba096cc4a74911962fa7a56118f488ac18d5252f232a9de37550dc0ca1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page