🐍 Python₿ Crypto
Crypto Wallet Address Validation
Validate Bitcoin and Ethereum wallet addresses in Python. Detect address types (P2PKH, P2SH, bech32), verify EIP-55 checksums, and run parallel checks with asyncio.gather.
Also available in Node.js
Contents
1. Validate Bitcoin address
Use await iv.btc_address(value) (SDK) or GET /v0/btc-address?value=….
{ "valid": true, "type": "P2WPKH" }
| type | Prefix | Description |
|---|---|---|
| P2PKH | 1… | Legacy — highest fees |
| P2SH | 3… | Script hash — SegWit-wrapped |
| P2WPKH | bc1q… (42) | Native SegWit — lowest fees |
| P2WSH | bc1q… (62) | Native SegWit script hash |
- Check
valid - Use
typefor fee estimation - Warn users with P2PKH about higher fees
2. Validate Ethereum address
Use await iv.eth_address(value) (SDK) or GET /v0/eth-address?value=….
{ "valid": true, "address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "isChecksumValid": true }
- Check
valid - Check
is_checksum_valid— EIP-55 - Normalise to checksummed form before storing
⚠️All-lowercase ETH addresses pass validation but are not checksummed. Normalise to EIP-55 mixed-case before storage to prevent duplicates.
3. Parallel validation with asyncio.gather
import asyncio import re from isvalid_sdk import IsValidConfig, create_client config = IsValidConfig(api_key="YOUR_API_KEY") iv = create_client(config) def detect_chain(address: str) -> str: if re.match(r"^0x[0-9a-fA-F]{40}$", address): return "ETH" if re.match(r"^(1|3)[1-9A-HJ-NP-Za-km-z]{25,34}$", address): return "BTC" if re.match(r"^bc1[a-z0-9]{6,}$", address): return "BTC" return "unknown" async def validate_wallet(chain: str, address: str): warnings = [] if chain == "BTC": result = await iv.btc_address(address) if result.valid and result.type == "P2PKH": warnings.append("Legacy P2PKH — consider migrating to bech32 for lower fees") return {"chain": chain, "valid": result.valid, "type": result.type, "warnings": warnings} elif chain == "ETH": result = await iv.eth_address(address) if result.valid and not result.is_checksum_valid: warnings.append("Address lacks EIP-55 checksum casing — normalise before storage") return {"chain": chain, "valid": result.valid, "address": result.address, "checksumValid": result.is_checksum_valid, "warnings": warnings} else: raise ValueError(f"Unknown chain for address: {address}") async def validate_both(btc: str, eth: str): btc_r, eth_r = await asyncio.gather( validate_wallet("BTC", btc), validate_wallet("ETH", eth), ) return {"btc": btc_r, "eth": eth_r} async def main(): result = await validate_both( "1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", ) print(f"BTC valid: {result['btc']['valid']}, type: {result['btc']['type']}") print(f"ETH valid: {result['eth']['valid']}, checksum: {result['eth']['checksumValid']}") asyncio.run(main())
4. Edge cases
Auto-detect chain from address format
import re def detect_chain(address: str) -> str: if re.match(r"^0x[0-9a-fA-F]{40}$", address): return "ETH" if re.match(r"^(1|3)[1-9A-HJ-NP-Za-km-z]{25,34}$", address): return "BTC" if re.match(r"^bc1[a-z0-9]{6,}$", address): return "BTC" return "unknown"
ETH checksum normalisation
# Using eth-utils or web3.py for EIP-55 normalisation from eth_utils import to_checksum_address result = await iv.eth_address(user_input) if result.valid and not result.is_checksum_valid: normalised = to_checksum_address(user_input.lower()) # Store normalised form
BTC testnet rejection
ℹ️Testnet addresses (prefix m, n, or tb1) will fail validation against the mainnet endpoint. Reject any address that returns
valid: False.5. Summary checklist
✓Detect chain from address format before API call
✓Check BTC type for fee estimation
✓Warn users about legacy P2PKH higher fees
✓Validate ETH is_checksum_valid for EIP-55
✓Normalise ETH to checksum form before storage
✓Run BTC + ETH with asyncio.gather
✓Reject testnet addresses in production
✓Return 422 with field-level error on invalid addresses