0
# Account Management
1
2
Account data structures, encoding formats, and metadata handling for both raw and parsed account information. This includes account state management, commitment levels, data encoding options, and parsing utilities for program-specific account data.
3
4
## Capabilities
5
6
### Account Data Structures
7
8
Core account representations containing balance, data, ownership, and metadata information.
9
10
```python { .api }
11
class Account:
12
"""
13
Solana account containing balance, data, owner, and metadata.
14
"""
15
def __init__(self, lamports: int, data: bytes, owner: Pubkey, executable: bool, rent_epoch: int):
16
"""
17
Create account with balance, data, and metadata.
18
19
Parameters:
20
- lamports: int, account balance in lamports (1 SOL = 1e9 lamports)
21
- data: bytes, account data (program-specific)
22
- owner: Pubkey, program that owns this account
23
- executable: bool, whether account contains executable program code
24
- rent_epoch: int, epoch when rent was last collected
25
"""
26
27
@classmethod
28
def default() -> 'Account':
29
"""
30
Create default empty account.
31
32
Returns:
33
Account with zero balance, empty data, system program owner
34
"""
35
36
@property
37
def lamports(self) -> int:
38
"""Account balance in lamports."""
39
40
@property
41
def data(self) -> bytes:
42
"""Account data bytes."""
43
44
@property
45
def owner(self) -> Pubkey:
46
"""Program that owns this account."""
47
48
@property
49
def executable(self) -> bool:
50
"""Whether account contains executable code."""
51
52
@property
53
def rent_epoch(self) -> int:
54
"""Epoch when rent was last collected."""
55
56
def serialize(self) -> bytes:
57
"""
58
Serialize account to bytes.
59
60
Returns:
61
bytes, serialized account data
62
"""
63
64
@classmethod
65
def deserialize(cls, data: bytes) -> 'Account':
66
"""
67
Deserialize account from bytes.
68
69
Parameters:
70
- data: bytes, serialized account data
71
72
Returns:
73
Account object
74
"""
75
```
76
77
```python { .api }
78
class AccountJSON:
79
"""
80
JSON-serializable account representation for RPC responses.
81
"""
82
def __init__(
83
self,
84
lamports: int,
85
data: Union[str, List[str]],
86
owner: str,
87
executable: bool,
88
rent_epoch: int
89
):
90
"""
91
Create JSON account representation.
92
93
Parameters:
94
- lamports: int, account balance
95
- data: Union[str, List[str]], encoded account data
96
- owner: str, base58 owner pubkey
97
- executable: bool, executable flag
98
- rent_epoch: int, rent epoch
99
"""
100
101
def to_json(self) -> dict:
102
"""
103
Convert to JSON dictionary.
104
105
Returns:
106
dict, JSON-compatible account data
107
"""
108
109
@classmethod
110
def from_json(cls, data: dict) -> 'AccountJSON':
111
"""
112
Create from JSON dictionary.
113
114
Parameters:
115
- data: dict, JSON account data
116
117
Returns:
118
AccountJSON object
119
"""
120
```
121
122
### Account Encoding and Parsing
123
124
Data encoding formats and parsing utilities for account data representation.
125
126
```python { .api }
127
class UiAccountEncoding:
128
"""
129
Account data encoding format enumeration.
130
"""
131
Base64: 'UiAccountEncoding' # Base64 encoded data
132
JsonParsed: 'UiAccountEncoding' # Parsed JSON format (program-specific)
133
Base58: 'UiAccountEncoding' # Base58 encoded data
134
Base64Zstd: 'UiAccountEncoding' # Base64 + Zstandard compression
135
136
def __str__(self) -> str:
137
"""String representation of encoding type."""
138
```
139
140
```python { .api }
141
class ParsedAccount:
142
"""
143
Account with parsed/decoded program-specific data.
144
"""
145
def __init__(self, account: Account, parsed_data: Optional[dict]):
146
"""
147
Create parsed account with structured data.
148
149
Parameters:
150
- account: Account, base account information
151
- parsed_data: Optional[dict], program-specific parsed data
152
"""
153
154
@property
155
def account(self) -> Account:
156
"""Base account information."""
157
158
@property
159
def parsed_data(self) -> Optional[dict]:
160
"""Program-specific parsed data."""
161
162
def is_token_account(self) -> bool:
163
"""
164
Check if account contains SPL token data.
165
166
Returns:
167
bool, True if account is token account
168
"""
169
170
def is_mint_account(self) -> bool:
171
"""
172
Check if account contains SPL mint data.
173
174
Returns:
175
bool, True if account is mint account
176
"""
177
```
178
179
```python { .api }
180
class UiDataSliceConfig:
181
"""
182
Configuration for slicing account data in RPC requests.
183
"""
184
def __init__(self, offset: int, length: int):
185
"""
186
Create data slice configuration.
187
188
Parameters:
189
- offset: int, byte offset to start slice
190
- length: int, number of bytes to return
191
"""
192
193
@property
194
def offset(self) -> int:
195
"""Slice offset in bytes."""
196
197
@property
198
def length(self) -> int:
199
"""Slice length in bytes."""
200
```
201
202
### Token Amount Handling
203
204
Specialized handling for token amounts with proper decimal representation.
205
206
```python { .api }
207
class UiTokenAmount:
208
"""
209
Token amount with decimal precision handling.
210
"""
211
def __init__(self, ui_amount: Optional[float], decimals: int, amount: str, ui_amount_string: str):
212
"""
213
Create token amount with decimal handling.
214
215
Parameters:
216
- ui_amount: Optional[float], human-readable amount (may be None for large numbers)
217
- decimals: int, number of decimal places for token
218
- amount: str, raw amount as string (no decimal adjustment)
219
- ui_amount_string: str, human-readable amount as string
220
"""
221
222
@property
223
def ui_amount(self) -> Optional[float]:
224
"""Human-readable amount (float, may be None for large values)."""
225
226
@property
227
def decimals(self) -> int:
228
"""Number of decimal places for this token."""
229
230
@property
231
def amount(self) -> str:
232
"""Raw token amount as string."""
233
234
@property
235
def ui_amount_string(self) -> str:
236
"""Human-readable amount as string."""
237
238
def to_float(self) -> float:
239
"""
240
Convert to float value.
241
242
Returns:
243
float, token amount as floating point
244
245
Raises:
246
- ValueError: if amount cannot be represented as float
247
"""
248
249
def to_decimal(self) -> 'Decimal':
250
"""
251
Convert to decimal for precise arithmetic.
252
253
Returns:
254
Decimal, exact token amount
255
"""
256
```
257
258
### Commitment and Configuration
259
260
Transaction commitment levels and account query configuration.
261
262
```python { .api }
263
class CommitmentLevel:
264
"""
265
Transaction confirmation levels.
266
"""
267
Processed: 'CommitmentLevel' # Transaction processed but not confirmed
268
Confirmed: 'CommitmentLevel' # Transaction confirmed by cluster
269
Finalized: 'CommitmentLevel' # Transaction finalized (cannot be rolled back)
270
271
def __str__(self) -> str:
272
"""String representation of commitment level."""
273
```
274
275
```python { .api }
276
class CommitmentConfig:
277
"""
278
Configuration for RPC request commitment level.
279
"""
280
def __init__(self, commitment: CommitmentLevel):
281
"""
282
Create commitment configuration.
283
284
Parameters:
285
- commitment: CommitmentLevel, desired confirmation level
286
"""
287
288
@classmethod
289
def processed() -> 'CommitmentConfig':
290
"""
291
Create processed commitment config.
292
293
Returns:
294
CommitmentConfig for processed transactions
295
"""
296
297
@classmethod
298
def confirmed() -> 'CommitmentConfig':
299
"""
300
Create confirmed commitment config.
301
302
Returns:
303
CommitmentConfig for confirmed transactions
304
"""
305
306
@classmethod
307
def finalized() -> 'CommitmentConfig':
308
"""
309
Create finalized commitment config.
310
311
Returns:
312
CommitmentConfig for finalized transactions
313
"""
314
315
@property
316
def commitment(self) -> CommitmentLevel:
317
"""Commitment level."""
318
```
319
320
## Usage Examples
321
322
### Basic Account Operations
323
324
```python
325
from solders.account import Account
326
from solders.pubkey import Pubkey
327
328
# Create account
329
owner = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
330
account_data = b"token_account_data_here"
331
332
account = Account(
333
lamports=2039280, # Rent-exempt minimum
334
data=account_data,
335
owner=owner,
336
executable=False,
337
rent_epoch=361
338
)
339
340
print(f"Account balance: {account.lamports / 1e9:.9f} SOL")
341
print(f"Data length: {len(account.data)} bytes")
342
print(f"Owner: {account.owner}")
343
print(f"Executable: {account.executable}")
344
```
345
346
### Working with Token Amounts
347
348
```python
349
from solders.account_decoder import UiTokenAmount
350
from decimal import Decimal
351
352
# Token amount with 6 decimals (USDC-style)
353
token_amount = UiTokenAmount(
354
ui_amount=1000.50,
355
decimals=6,
356
amount="1000500000", # Raw amount: 1000.5 * 10^6
357
ui_amount_string="1000.5"
358
)
359
360
print(f"UI amount: {token_amount.ui_amount}")
361
print(f"Raw amount: {token_amount.amount}")
362
print(f"Decimals: {token_amount.decimals}")
363
364
# Precise decimal arithmetic
365
precise_amount = token_amount.to_decimal()
366
print(f"Precise amount: {precise_amount}")
367
368
# Large number handling (ui_amount may be None)
369
large_amount = UiTokenAmount(
370
ui_amount=None, # Too large for float
371
decimals=9,
372
amount="999999999999999999999",
373
ui_amount_string="999999999999.999999999"
374
)
375
```
376
377
### Account Data Slicing
378
379
```python
380
from solders.account_decoder import UiDataSliceConfig
381
382
# Get first 64 bytes of account data
383
slice_config = UiDataSliceConfig(offset=0, length=64)
384
385
# Get specific portion (e.g., skip mint info, get owner)
386
token_account_slice = UiDataSliceConfig(offset=32, length=32)
387
388
print(f"Slice offset: {slice_config.offset}")
389
print(f"Slice length: {slice_config.length}")
390
```
391
392
### Commitment Level Usage
393
394
```python
395
from solders.commitment_config import CommitmentLevel, CommitmentConfig
396
397
# Different commitment levels
398
processed_config = CommitmentConfig.processed()
399
confirmed_config = CommitmentConfig.confirmed()
400
finalized_config = CommitmentConfig.finalized()
401
402
# Check commitment level
403
if confirmed_config.commitment == CommitmentLevel.Confirmed:
404
print("Using confirmed commitment level")
405
406
# Custom commitment
407
custom_config = CommitmentConfig(CommitmentLevel.Finalized)
408
```
409
410
### Account Serialization
411
412
```python
413
# Serialize account for storage or transmission
414
serialized = account.serialize()
415
print(f"Serialized size: {len(serialized)} bytes")
416
417
# Deserialize account
418
restored_account = Account.deserialize(serialized)
419
assert restored_account.lamports == account.lamports
420
assert restored_account.data == account.data
421
assert restored_account.owner == account.owner
422
```
423
424
### JSON Account Handling
425
426
```python
427
from solders.account import AccountJSON
428
429
# Create JSON representation
430
json_account = AccountJSON(
431
lamports=2039280,
432
data="dGVzdF9kYXRh", # Base64 encoded data
433
owner="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
434
executable=False,
435
rent_epoch=361
436
)
437
438
# Convert to dictionary for JSON serialization
439
json_dict = json_account.to_json()
440
441
# Restore from JSON
442
restored = AccountJSON.from_json(json_dict)
443
```
444
445
### Parsed Account Analysis
446
447
```python
448
from solders.account_decoder import ParsedAccount
449
450
# Parsed token account data
451
parsed_data = {
452
"type": "account",
453
"info": {
454
"mint": "So11111111111111111111111111111111111111112",
455
"owner": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj",
456
"tokenAmount": {
457
"amount": "1000000000",
458
"decimals": 9,
459
"uiAmount": 1.0,
460
"uiAmountString": "1"
461
}
462
}
463
}
464
465
parsed_account = ParsedAccount(account, parsed_data)
466
467
# Check account type
468
if parsed_account.is_token_account():
469
print("This is a token account")
470
token_info = parsed_account.parsed_data["info"]
471
print(f"Token mint: {token_info['mint']}")
472
print(f"Owner: {token_info['owner']}")
473
474
if parsed_account.is_mint_account():
475
print("This is a mint account")
476
```
477
478
## Account State Management
479
480
### Account Lifecycle
481
482
```python
483
# New account (empty, system-owned)
484
new_account = Account.default()
485
assert new_account.lamports == 0
486
assert new_account.owner == SYSTEM_PROGRAM_ID
487
assert not new_account.executable
488
489
# Funded account
490
funded_account = Account(
491
lamports=5000000, # 0.005 SOL
492
data=b"",
493
owner=SYSTEM_PROGRAM_ID,
494
executable=False,
495
rent_epoch=361
496
)
497
498
# Program account (executable)
499
program_account = Account(
500
lamports=10000000,
501
data=b"program_bytecode_here",
502
owner=SYSTEM_PROGRAM_ID,
503
executable=True,
504
rent_epoch=361
505
)
506
```
507
508
### Rent Exemption Checking
509
510
```python
511
from solders.rent import Rent
512
513
# Calculate rent exemption
514
rent = Rent.default()
515
data_size = 165 # Size of token account
516
minimum_balance = rent.minimum_balance(data_size)
517
518
# Check if account is rent exempt
519
def is_rent_exempt(account: Account) -> bool:
520
return account.lamports >= minimum_balance
521
522
if is_rent_exempt(account):
523
print("Account is rent exempt")
524
else:
525
print(f"Need {minimum_balance - account.lamports} more lamports for rent exemption")
526
```
527
528
## Encoding Utilities
529
530
### Data Encoding Helpers
531
532
```python
533
import base64
534
import base58
535
536
def encode_account_data(data: bytes, encoding: UiAccountEncoding) -> Union[str, List[str]]:
537
"""Encode account data in specified format."""
538
if encoding == UiAccountEncoding.Base64:
539
return base64.b64encode(data).decode()
540
elif encoding == UiAccountEncoding.Base58:
541
return base58.b58encode(data).decode()
542
elif encoding == UiAccountEncoding.JsonParsed:
543
# Would require program-specific parsing
544
return "parsed"
545
else:
546
return data.hex()
547
548
def decode_account_data(encoded_data: str, encoding: UiAccountEncoding) -> bytes:
549
"""Decode account data from specified format."""
550
if encoding == UiAccountEncoding.Base64:
551
return base64.b64decode(encoded_data)
552
elif encoding == UiAccountEncoding.Base58:
553
return base58.b58decode(encoded_data)
554
else:
555
return bytes.fromhex(encoded_data)
556
```
557
558
## Constants and Defaults
559
560
### Well-Known Accounts
561
562
```python { .api }
563
# System Program ID (default owner for user accounts)
564
SYSTEM_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string("11111111111111111111111111111112")
565
566
# Native SOL Token Mint
567
NATIVE_MINT: Final[Pubkey] = Pubkey.from_string("So11111111111111111111111111111111111111112")
568
```
569
570
### Default Values
571
572
```python { .api }
573
# Default commitment level for most operations
574
DEFAULT_COMMITMENT: Final[CommitmentLevel] = CommitmentLevel.Finalized
575
576
# Minimum account sizes
577
MINIMUM_ACCOUNT_SIZE: Final[int] = 0
578
TOKEN_ACCOUNT_SIZE: Final[int] = 165
579
MINT_ACCOUNT_SIZE: Final[int] = 82
580
```