A complete Python library for interacting with the XRP Ledger blockchain, providing transaction creation, account management, and comprehensive XRPL protocol support
Create, manage, and operate XRPL wallets including key generation, address derivation, and testnet funding. The wallet module provides comprehensive cryptographic wallet functionality for XRPL applications.
Complete wallet implementation with cryptographic key management and address operations.
from xrpl.wallet import Wallet
from xrpl import CryptoAlgorithm
class Wallet:
"""XRPL wallet containing cryptographic keys and address information."""
def __init__(
self,
public_key: str,
private_key: str,
classic_address: str = None,
seed: str = None
):
"""
Initialize wallet with key material.
Args:
public_key: Hex-encoded public key
private_key: Hex-encoded private key
classic_address: XRPL classic address (derived if not provided)
seed: Original seed used to generate keys (optional)
"""
self.public_key = public_key
self.private_key = private_key
self.classic_address = classic_address
self.seed = seed
@property
def address(self) -> str:
"""Get the classic address (alias for classic_address)."""
return self.classic_address
@classmethod
def create(cls, algorithm: CryptoAlgorithm = CryptoAlgorithm.ED25519) -> "Wallet":
"""
Create a new wallet with randomly generated keys.
Args:
algorithm: Cryptographic algorithm to use (ED25519 or SECP256K1)
Returns:
New Wallet instance with generated keys
"""
@classmethod
def from_seed(
cls,
seed: str,
algorithm: CryptoAlgorithm = None
) -> "Wallet":
"""
Create wallet from existing seed.
Args:
seed: Base58-encoded seed string
algorithm: Algorithm to use (inferred from seed if not provided)
Returns:
Wallet instance derived from seed
"""
@classmethod
def from_secret(cls, seed: str) -> "Wallet":
"""
Create wallet from secret (alias for from_seed).
Args:
seed: Base58-encoded seed/secret string
Returns:
Wallet instance derived from secret
"""
def get_xaddress(self, tag: int = None, is_test: bool = False) -> str:
"""
Get X-address format of wallet address.
Args:
tag: Optional destination tag to encode
is_test: Whether this is for test network
Returns:
X-address string with optional tag encoded
"""Generate wallets funded by testnet faucets for development and testing.
from xrpl.wallet import generate_faucet_wallet
def generate_faucet_wallet(
client,
wallet: Wallet = None,
usage_context: str = None
) -> Wallet:
"""
Generate a wallet funded by testnet faucet.
Args:
client: XRPL client connected to testnet
wallet: Existing wallet to fund (creates new if None)
usage_context: Usage context string for faucet request
Returns:
Funded wallet ready for testnet use
Raises:
XRPLFaucetException: If faucet funding fails
"""from xrpl.wallet import Wallet
from xrpl import CryptoAlgorithm
# Create wallet with default Ed25519 algorithm
wallet1 = Wallet.create()
print(f"Address: {wallet1.address}")
print(f"Public key: {wallet1.public_key}")
print(f"Seed: {wallet1.seed}")
# Create wallet with secp256k1 algorithm
wallet2 = Wallet.create(CryptoAlgorithm.SECP256K1)
print(f"Address: {wallet2.address}")
print(f"Algorithm: secp256k1")
# Create wallet from existing seed
existing_seed = "sEdTM1uX8pu2do5XvTnutH6HsouMaM2"
wallet3 = Wallet.from_seed(existing_seed)
print(f"Restored address: {wallet3.address}")
# Alternative method using from_secret
wallet4 = Wallet.from_secret(existing_seed)
print(f"Same address: {wallet4.address == wallet3.address}")from xrpl.wallet import Wallet
# Create a wallet
wallet = Wallet.create()
# Display wallet information
print("=== Wallet Information ===")
print(f"Classic Address: {wallet.address}")
print(f"Classic Address (property): {wallet.classic_address}")
print(f"Public Key: {wallet.public_key}")
print(f"Private Key: {wallet.private_key}")
print(f"Seed: {wallet.seed}")
# X-address formats
print("\n=== Address Formats ===")
print(f"Classic: {wallet.address}")
print(f"X-address (mainnet): {wallet.get_xaddress()}")
print(f"X-address (testnet): {wallet.get_xaddress(is_test=True)}")
print(f"X-address with tag: {wallet.get_xaddress(tag=12345, is_test=True)}")
# Address validation
from xrpl.core.addresscodec import is_valid_classic_address, is_valid_xaddress
classic_addr = wallet.address
x_addr = wallet.get_xaddress(is_test=True)
print(f"\nClassic address valid: {is_valid_classic_address(classic_addr)}")
print(f"X-address valid: {is_valid_xaddress(x_addr)}")from xrpl.clients import JsonRpcClient
from xrpl.wallet import Wallet, generate_faucet_wallet
# Connect to testnet
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
# Method 1: Generate and fund new wallet
try:
funded_wallet = generate_faucet_wallet(client)
print(f"✅ Created funded wallet: {funded_wallet.address}")
# Check balance
from xrpl import account
balance = account.get_balance(funded_wallet.address, client)
print(f"Balance: {balance} drops ({balance / 1_000_000} XRP)")
except Exception as e:
print(f"❌ Faucet funding failed: {e}")
# Method 2: Fund existing wallet
existing_wallet = Wallet.create()
print(f"Created wallet: {existing_wallet.address}")
try:
funded_existing = generate_faucet_wallet(client, existing_wallet)
print(f"✅ Funded existing wallet: {funded_existing.address}")
except Exception as e:
print(f"❌ Failed to fund existing wallet: {e}")import json
from xrpl.wallet import Wallet
from xrpl import CryptoAlgorithm
def save_wallet_safely(wallet: Wallet, filename: str, password: str = None):
"""Save wallet to encrypted file (simplified example)."""
# In production, use proper encryption!
wallet_data = {
"seed": wallet.seed,
"address": wallet.address,
"public_key": wallet.public_key,
# Never save private keys in plaintext!
"algorithm": "ed25519" if "ed25519" in wallet.seed else "secp256k1"
}
with open(filename, 'w') as f:
json.dump(wallet_data, f, indent=2)
print(f"⚠️ Wallet saved to {filename}")
print("⚠️ WARNING: This is a simplified example!")
print("⚠️ In production, encrypt private keys and use secure storage!")
def load_wallet_safely(filename: str, password: str = None) -> Wallet:
"""Load wallet from file (simplified example)."""
with open(filename, 'r') as f:
wallet_data = json.load(f)
# Restore wallet from seed
wallet = Wallet.from_seed(wallet_data["seed"])
# Verify address matches
if wallet.address != wallet_data["address"]:
raise ValueError("Address mismatch - corrupted wallet file!")
return wallet
# Example usage
original_wallet = Wallet.create()
print(f"Original wallet: {original_wallet.address}")
# Save wallet (INSECURE - for demo only!)
save_wallet_safely(original_wallet, "demo_wallet.json")
# Load wallet
restored_wallet = load_wallet_safely("demo_wallet.json")
print(f"Restored wallet: {restored_wallet.address}")
print(f"Addresses match: {original_wallet.address == restored_wallet.address}")from xrpl.wallet import Wallet, generate_faucet_wallet
from xrpl.clients import JsonRpcClient
from xrpl import account
class WalletManager:
"""Manage multiple XRPL wallets."""
def __init__(self, client):
self.client = client
self.wallets = {}
def create_wallet(self, name: str, algorithm=None) -> Wallet:
"""Create and store a new wallet."""
if algorithm:
wallet = Wallet.create(algorithm)
else:
wallet = Wallet.create()
self.wallets[name] = wallet
print(f"Created wallet '{name}': {wallet.address}")
return wallet
def fund_wallet(self, name: str) -> bool:
"""Fund a wallet using testnet faucet."""
if name not in self.wallets:
print(f"Wallet '{name}' not found")
return False
try:
funded_wallet = generate_faucet_wallet(self.client, self.wallets[name])
self.wallets[name] = funded_wallet
print(f"✅ Funded wallet '{name}'")
return True
except Exception as e:
print(f"❌ Failed to fund wallet '{name}': {e}")
return False
def get_balances(self) -> dict:
"""Get balances for all wallets."""
balances = {}
for name, wallet in self.wallets.items():
try:
if account.does_account_exist(wallet.address, self.client):
balance = account.get_balance(wallet.address, self.client)
balances[name] = {
"address": wallet.address,
"balance_drops": balance,
"balance_xrp": balance / 1_000_000
}
else:
balances[name] = {
"address": wallet.address,
"balance_drops": 0,
"balance_xrp": 0.0,
"exists": False
}
except Exception as e:
balances[name] = {
"address": wallet.address,
"error": str(e)
}
return balances
def get_wallet(self, name: str) -> Wallet:
"""Get wallet by name."""
return self.wallets.get(name)
# Usage example
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
manager = WalletManager(client)
# Create multiple wallets
manager.create_wallet("alice")
manager.create_wallet("bob", CryptoAlgorithm.SECP256K1)
manager.create_wallet("charlie")
# Fund wallets
manager.fund_wallet("alice")
manager.fund_wallet("bob")
# Check balances
balances = manager.get_balances()
for name, info in balances.items():
if "error" in info:
print(f"{name}: Error - {info['error']}")
elif info.get("exists", True):
print(f"{name} ({info['address']}): {info['balance_xrp']:.6f} XRP")
else:
print(f"{name} ({info['address']}): Account not funded")from xrpl.wallet import Wallet
import secrets
import hashlib
def create_secure_wallet():
"""Create wallet with additional entropy."""
# Add extra entropy (optional - Wallet.create() is already secure)
extra_entropy = secrets.token_bytes(32)
wallet = Wallet.create()
print("🔐 Wallet Security Checklist:")
print("✅ Generated with cryptographically secure random number generator")
print("✅ Private key never transmitted over network")
print("✅ Seed can regenerate the entire wallet")
return wallet
def verify_wallet_integrity(wallet: Wallet) -> bool:
"""Verify wallet keys are consistent."""
try:
# Create new wallet from same seed
verification_wallet = Wallet.from_seed(wallet.seed)
# Check all components match
checks = [
wallet.address == verification_wallet.address,
wallet.public_key == verification_wallet.public_key,
wallet.private_key == verification_wallet.private_key
]
if all(checks):
print("✅ Wallet integrity verified")
return True
else:
print("❌ Wallet integrity check failed!")
return False
except Exception as e:
print(f"❌ Wallet verification error: {e}")
return False
def wallet_security_audit(wallet: Wallet):
"""Perform basic security audit of wallet."""
print("🔍 Wallet Security Audit")
print(f"Address: {wallet.address}")
# Check key lengths
public_key_len = len(wallet.public_key)
private_key_len = len(wallet.private_key)
print(f"Public key length: {public_key_len} chars")
print(f"Private key length: {private_key_len} chars")
# Verify integrity
integrity_ok = verify_wallet_integrity(wallet)
# Check address format
from xrpl.core.addresscodec import is_valid_classic_address
address_valid = is_valid_classic_address(wallet.address)
print(f"Address format valid: {address_valid}")
# Security recommendations
print("\n🛡️ Security Recommendations:")
print("- Store seed/private key in encrypted storage")
print("- Never share private key or seed")
print("- Use hardware wallets for large amounts")
print("- Test with small amounts first")
print("- Keep backups of seed in secure locations")
print("- Use testnet for development")
# Example usage
wallet = create_secure_wallet()
wallet_security_audit(wallet)class XRPLFaucetException(XRPLException):
"""Exception raised when faucet operations fail during wallet funding."""# Wallet instance properties
wallet = Wallet.create()
wallet.address # str: Classic XRPL address (rXXX...)
wallet.classic_address # str: Same as address
wallet.public_key # str: Hex-encoded public key
wallet.private_key # str: Hex-encoded private key
wallet.seed # str: Base58-encoded seed for key derivation
# Methods
wallet.get_xaddress(tag=None, is_test=False) # X-address format
# Class methods
Wallet.create(algorithm=CryptoAlgorithm.ED25519) # Create new wallet
Wallet.from_seed(seed, algorithm=None) # From existing seed
Wallet.from_secret(seed) # Alias for from_seedInstall with Tessl CLI
npx tessl i tessl/pypi-xrpl-py