0
# Wallet Operations
1
2
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.
3
4
## Capabilities
5
6
### Wallet Class
7
8
Complete wallet implementation with cryptographic key management and address operations.
9
10
```python { .api }
11
from xrpl.wallet import Wallet
12
from xrpl import CryptoAlgorithm
13
14
class Wallet:
15
"""XRPL wallet containing cryptographic keys and address information."""
16
17
def __init__(
18
self,
19
public_key: str,
20
private_key: str,
21
classic_address: str = None,
22
seed: str = None
23
):
24
"""
25
Initialize wallet with key material.
26
27
Args:
28
public_key: Hex-encoded public key
29
private_key: Hex-encoded private key
30
classic_address: XRPL classic address (derived if not provided)
31
seed: Original seed used to generate keys (optional)
32
"""
33
self.public_key = public_key
34
self.private_key = private_key
35
self.classic_address = classic_address
36
self.seed = seed
37
38
@property
39
def address(self) -> str:
40
"""Get the classic address (alias for classic_address)."""
41
return self.classic_address
42
43
@classmethod
44
def create(cls, algorithm: CryptoAlgorithm = CryptoAlgorithm.ED25519) -> "Wallet":
45
"""
46
Create a new wallet with randomly generated keys.
47
48
Args:
49
algorithm: Cryptographic algorithm to use (ED25519 or SECP256K1)
50
51
Returns:
52
New Wallet instance with generated keys
53
"""
54
55
@classmethod
56
def from_seed(
57
cls,
58
seed: str,
59
algorithm: CryptoAlgorithm = None
60
) -> "Wallet":
61
"""
62
Create wallet from existing seed.
63
64
Args:
65
seed: Base58-encoded seed string
66
algorithm: Algorithm to use (inferred from seed if not provided)
67
68
Returns:
69
Wallet instance derived from seed
70
"""
71
72
@classmethod
73
def from_secret(cls, seed: str) -> "Wallet":
74
"""
75
Create wallet from secret (alias for from_seed).
76
77
Args:
78
seed: Base58-encoded seed/secret string
79
80
Returns:
81
Wallet instance derived from secret
82
"""
83
84
def get_xaddress(self, tag: int = None, is_test: bool = False) -> str:
85
"""
86
Get X-address format of wallet address.
87
88
Args:
89
tag: Optional destination tag to encode
90
is_test: Whether this is for test network
91
92
Returns:
93
X-address string with optional tag encoded
94
"""
95
```
96
97
### Wallet Funding
98
99
Generate wallets funded by testnet faucets for development and testing.
100
101
```python { .api }
102
from xrpl.wallet import generate_faucet_wallet
103
104
def generate_faucet_wallet(
105
client,
106
wallet: Wallet = None,
107
usage_context: str = None
108
) -> Wallet:
109
"""
110
Generate a wallet funded by testnet faucet.
111
112
Args:
113
client: XRPL client connected to testnet
114
wallet: Existing wallet to fund (creates new if None)
115
usage_context: Usage context string for faucet request
116
117
Returns:
118
Funded wallet ready for testnet use
119
120
Raises:
121
XRPLFaucetException: If faucet funding fails
122
"""
123
```
124
125
## Usage Examples
126
127
### Creating New Wallets
128
129
```python
130
from xrpl.wallet import Wallet
131
from xrpl import CryptoAlgorithm
132
133
# Create wallet with default Ed25519 algorithm
134
wallet1 = Wallet.create()
135
print(f"Address: {wallet1.address}")
136
print(f"Public key: {wallet1.public_key}")
137
print(f"Seed: {wallet1.seed}")
138
139
# Create wallet with secp256k1 algorithm
140
wallet2 = Wallet.create(CryptoAlgorithm.SECP256K1)
141
print(f"Address: {wallet2.address}")
142
print(f"Algorithm: secp256k1")
143
144
# Create wallet from existing seed
145
existing_seed = "sEdTM1uX8pu2do5XvTnutH6HsouMaM2"
146
wallet3 = Wallet.from_seed(existing_seed)
147
print(f"Restored address: {wallet3.address}")
148
149
# Alternative method using from_secret
150
wallet4 = Wallet.from_secret(existing_seed)
151
print(f"Same address: {wallet4.address == wallet3.address}")
152
```
153
154
### Wallet Information and Address Formats
155
156
```python
157
from xrpl.wallet import Wallet
158
159
# Create a wallet
160
wallet = Wallet.create()
161
162
# Display wallet information
163
print("=== Wallet Information ===")
164
print(f"Classic Address: {wallet.address}")
165
print(f"Classic Address (property): {wallet.classic_address}")
166
print(f"Public Key: {wallet.public_key}")
167
print(f"Private Key: {wallet.private_key}")
168
print(f"Seed: {wallet.seed}")
169
170
# X-address formats
171
print("\n=== Address Formats ===")
172
print(f"Classic: {wallet.address}")
173
print(f"X-address (mainnet): {wallet.get_xaddress()}")
174
print(f"X-address (testnet): {wallet.get_xaddress(is_test=True)}")
175
print(f"X-address with tag: {wallet.get_xaddress(tag=12345, is_test=True)}")
176
177
# Address validation
178
from xrpl.core.addresscodec import is_valid_classic_address, is_valid_xaddress
179
classic_addr = wallet.address
180
x_addr = wallet.get_xaddress(is_test=True)
181
182
print(f"\nClassic address valid: {is_valid_classic_address(classic_addr)}")
183
print(f"X-address valid: {is_valid_xaddress(x_addr)}")
184
```
185
186
### Testnet Wallet Funding
187
188
```python
189
from xrpl.clients import JsonRpcClient
190
from xrpl.wallet import Wallet, generate_faucet_wallet
191
192
# Connect to testnet
193
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
194
195
# Method 1: Generate and fund new wallet
196
try:
197
funded_wallet = generate_faucet_wallet(client)
198
print(f"✅ Created funded wallet: {funded_wallet.address}")
199
200
# Check balance
201
from xrpl import account
202
balance = account.get_balance(funded_wallet.address, client)
203
print(f"Balance: {balance} drops ({balance / 1_000_000} XRP)")
204
205
except Exception as e:
206
print(f"❌ Faucet funding failed: {e}")
207
208
# Method 2: Fund existing wallet
209
existing_wallet = Wallet.create()
210
print(f"Created wallet: {existing_wallet.address}")
211
212
try:
213
funded_existing = generate_faucet_wallet(client, existing_wallet)
214
print(f"✅ Funded existing wallet: {funded_existing.address}")
215
216
except Exception as e:
217
print(f"❌ Failed to fund existing wallet: {e}")
218
```
219
220
### Wallet Persistence and Recovery
221
222
```python
223
import json
224
from xrpl.wallet import Wallet
225
from xrpl import CryptoAlgorithm
226
227
def save_wallet_safely(wallet: Wallet, filename: str, password: str = None):
228
"""Save wallet to encrypted file (simplified example)."""
229
230
# In production, use proper encryption!
231
wallet_data = {
232
"seed": wallet.seed,
233
"address": wallet.address,
234
"public_key": wallet.public_key,
235
# Never save private keys in plaintext!
236
"algorithm": "ed25519" if "ed25519" in wallet.seed else "secp256k1"
237
}
238
239
with open(filename, 'w') as f:
240
json.dump(wallet_data, f, indent=2)
241
242
print(f"⚠️ Wallet saved to {filename}")
243
print("⚠️ WARNING: This is a simplified example!")
244
print("⚠️ In production, encrypt private keys and use secure storage!")
245
246
def load_wallet_safely(filename: str, password: str = None) -> Wallet:
247
"""Load wallet from file (simplified example)."""
248
249
with open(filename, 'r') as f:
250
wallet_data = json.load(f)
251
252
# Restore wallet from seed
253
wallet = Wallet.from_seed(wallet_data["seed"])
254
255
# Verify address matches
256
if wallet.address != wallet_data["address"]:
257
raise ValueError("Address mismatch - corrupted wallet file!")
258
259
return wallet
260
261
# Example usage
262
original_wallet = Wallet.create()
263
print(f"Original wallet: {original_wallet.address}")
264
265
# Save wallet (INSECURE - for demo only!)
266
save_wallet_safely(original_wallet, "demo_wallet.json")
267
268
# Load wallet
269
restored_wallet = load_wallet_safely("demo_wallet.json")
270
print(f"Restored wallet: {restored_wallet.address}")
271
print(f"Addresses match: {original_wallet.address == restored_wallet.address}")
272
```
273
274
### Multi-Wallet Management
275
276
```python
277
from xrpl.wallet import Wallet, generate_faucet_wallet
278
from xrpl.clients import JsonRpcClient
279
from xrpl import account
280
281
class WalletManager:
282
"""Manage multiple XRPL wallets."""
283
284
def __init__(self, client):
285
self.client = client
286
self.wallets = {}
287
288
def create_wallet(self, name: str, algorithm=None) -> Wallet:
289
"""Create and store a new wallet."""
290
if algorithm:
291
wallet = Wallet.create(algorithm)
292
else:
293
wallet = Wallet.create()
294
295
self.wallets[name] = wallet
296
print(f"Created wallet '{name}': {wallet.address}")
297
return wallet
298
299
def fund_wallet(self, name: str) -> bool:
300
"""Fund a wallet using testnet faucet."""
301
if name not in self.wallets:
302
print(f"Wallet '{name}' not found")
303
return False
304
305
try:
306
funded_wallet = generate_faucet_wallet(self.client, self.wallets[name])
307
self.wallets[name] = funded_wallet
308
print(f"✅ Funded wallet '{name}'")
309
return True
310
except Exception as e:
311
print(f"❌ Failed to fund wallet '{name}': {e}")
312
return False
313
314
def get_balances(self) -> dict:
315
"""Get balances for all wallets."""
316
balances = {}
317
for name, wallet in self.wallets.items():
318
try:
319
if account.does_account_exist(wallet.address, self.client):
320
balance = account.get_balance(wallet.address, self.client)
321
balances[name] = {
322
"address": wallet.address,
323
"balance_drops": balance,
324
"balance_xrp": balance / 1_000_000
325
}
326
else:
327
balances[name] = {
328
"address": wallet.address,
329
"balance_drops": 0,
330
"balance_xrp": 0.0,
331
"exists": False
332
}
333
except Exception as e:
334
balances[name] = {
335
"address": wallet.address,
336
"error": str(e)
337
}
338
return balances
339
340
def get_wallet(self, name: str) -> Wallet:
341
"""Get wallet by name."""
342
return self.wallets.get(name)
343
344
# Usage example
345
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
346
manager = WalletManager(client)
347
348
# Create multiple wallets
349
manager.create_wallet("alice")
350
manager.create_wallet("bob", CryptoAlgorithm.SECP256K1)
351
manager.create_wallet("charlie")
352
353
# Fund wallets
354
manager.fund_wallet("alice")
355
manager.fund_wallet("bob")
356
357
# Check balances
358
balances = manager.get_balances()
359
for name, info in balances.items():
360
if "error" in info:
361
print(f"{name}: Error - {info['error']}")
362
elif info.get("exists", True):
363
print(f"{name} ({info['address']}): {info['balance_xrp']:.6f} XRP")
364
else:
365
print(f"{name} ({info['address']}): Account not funded")
366
```
367
368
### Wallet Security Best Practices
369
370
```python
371
from xrpl.wallet import Wallet
372
import secrets
373
import hashlib
374
375
def create_secure_wallet():
376
"""Create wallet with additional entropy."""
377
378
# Add extra entropy (optional - Wallet.create() is already secure)
379
extra_entropy = secrets.token_bytes(32)
380
wallet = Wallet.create()
381
382
print("🔐 Wallet Security Checklist:")
383
print("✅ Generated with cryptographically secure random number generator")
384
print("✅ Private key never transmitted over network")
385
print("✅ Seed can regenerate the entire wallet")
386
387
return wallet
388
389
def verify_wallet_integrity(wallet: Wallet) -> bool:
390
"""Verify wallet keys are consistent."""
391
392
try:
393
# Create new wallet from same seed
394
verification_wallet = Wallet.from_seed(wallet.seed)
395
396
# Check all components match
397
checks = [
398
wallet.address == verification_wallet.address,
399
wallet.public_key == verification_wallet.public_key,
400
wallet.private_key == verification_wallet.private_key
401
]
402
403
if all(checks):
404
print("✅ Wallet integrity verified")
405
return True
406
else:
407
print("❌ Wallet integrity check failed!")
408
return False
409
410
except Exception as e:
411
print(f"❌ Wallet verification error: {e}")
412
return False
413
414
def wallet_security_audit(wallet: Wallet):
415
"""Perform basic security audit of wallet."""
416
417
print("🔍 Wallet Security Audit")
418
print(f"Address: {wallet.address}")
419
420
# Check key lengths
421
public_key_len = len(wallet.public_key)
422
private_key_len = len(wallet.private_key)
423
424
print(f"Public key length: {public_key_len} chars")
425
print(f"Private key length: {private_key_len} chars")
426
427
# Verify integrity
428
integrity_ok = verify_wallet_integrity(wallet)
429
430
# Check address format
431
from xrpl.core.addresscodec import is_valid_classic_address
432
address_valid = is_valid_classic_address(wallet.address)
433
print(f"Address format valid: {address_valid}")
434
435
# Security recommendations
436
print("\n🛡️ Security Recommendations:")
437
print("- Store seed/private key in encrypted storage")
438
print("- Never share private key or seed")
439
print("- Use hardware wallets for large amounts")
440
print("- Test with small amounts first")
441
print("- Keep backups of seed in secure locations")
442
print("- Use testnet for development")
443
444
# Example usage
445
wallet = create_secure_wallet()
446
wallet_security_audit(wallet)
447
```
448
449
## Exceptions
450
451
```python { .api }
452
class XRPLFaucetException(XRPLException):
453
"""Exception raised when faucet operations fail during wallet funding."""
454
```
455
456
## Wallet Properties Summary
457
458
```python { .api }
459
# Wallet instance properties
460
wallet = Wallet.create()
461
462
wallet.address # str: Classic XRPL address (rXXX...)
463
wallet.classic_address # str: Same as address
464
wallet.public_key # str: Hex-encoded public key
465
wallet.private_key # str: Hex-encoded private key
466
wallet.seed # str: Base58-encoded seed for key derivation
467
468
# Methods
469
wallet.get_xaddress(tag=None, is_test=False) # X-address format
470
471
# Class methods
472
Wallet.create(algorithm=CryptoAlgorithm.ED25519) # Create new wallet
473
Wallet.from_seed(seed, algorithm=None) # From existing seed
474
Wallet.from_secret(seed) # Alias for from_seed
475
```