or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-management.mdcryptographic-primitives.mderror-handling.mdindex.mdnetwork-sysvars.mdrpc-functionality.mdsystem-programs.mdtesting-infrastructure.mdtoken-operations.mdtransaction-construction.mdtransaction-status.md

transaction-status.mddocs/

0

# Transaction Status

1

2

Transaction metadata, execution results, and status tracking including error handling, parsed transaction data, and confirmation information. This provides comprehensive tools for monitoring transaction lifecycle and analyzing execution outcomes.

3

4

## Capabilities

5

6

### Transaction Status and Confirmation

7

8

Core transaction status information including confirmation levels and execution metadata.

9

10

```python { .api }

11

class TransactionStatus:

12

"""

13

Transaction confirmation status and metadata.

14

"""

15

def __init__(

16

self,

17

slot: int,

18

confirmations: Optional[int],

19

status: Optional['TransactionErrorType'],

20

confirmation_status: Optional['TransactionConfirmationStatus']

21

):

22

"""

23

Create transaction status.

24

25

Parameters:

26

- slot: int, slot where transaction was processed

27

- confirmations: Optional[int], number of confirmations (None if not confirmed)

28

- status: Optional[TransactionErrorType], error status (None if successful)

29

- confirmation_status: Optional[TransactionConfirmationStatus], confirmation level

30

"""

31

32

@property

33

def slot(self) -> int:

34

"""Slot where transaction was processed."""

35

36

@property

37

def confirmations(self) -> Optional[int]:

38

"""Number of confirmations (None if not confirmed)."""

39

40

@property

41

def status(self) -> Optional['TransactionErrorType']:

42

"""Error status (None if successful)."""

43

44

@property

45

def confirmation_status(self) -> Optional['TransactionConfirmationStatus']:

46

"""Current confirmation level."""

47

48

def is_successful(self) -> bool:

49

"""

50

Check if transaction was successful.

51

52

Returns:

53

bool, True if transaction succeeded

54

"""

55

56

def is_confirmed(self) -> bool:

57

"""

58

Check if transaction is confirmed.

59

60

Returns:

61

bool, True if transaction has confirmations

62

"""

63

64

class TransactionConfirmationStatus:

65

"""Transaction confirmation level enumeration."""

66

Processed: 'TransactionConfirmationStatus' # Transaction processed

67

Confirmed: 'TransactionConfirmationStatus' # Transaction confirmed

68

Finalized: 'TransactionConfirmationStatus' # Transaction finalized

69

70

def __str__(self) -> str:

71

"""String representation of confirmation status."""

72

```

73

74

### Transaction Metadata

75

76

Comprehensive transaction execution metadata including fees, logs, and state changes.

77

78

```python { .api }

79

class UiTransactionStatusMeta:

80

"""

81

Transaction execution metadata in UI-friendly format.

82

"""

83

def __init__(

84

self,

85

err: Optional['TransactionErrorType'],

86

fee: int,

87

pre_balances: List[int],

88

post_balances: List[int],

89

inner_instructions: Optional[List['UiInnerInstructions']],

90

log_messages: Optional[List[str]],

91

pre_token_balances: Optional[List['UiTransactionTokenBalance']],

92

post_token_balances: Optional[List['UiTransactionTokenBalance']],

93

rewards: Optional[List['Reward']],

94

loaded_addresses: Optional['UiLoadedAddresses'],

95

return_data: Optional['TransactionReturnData'],

96

compute_units_consumed: Optional[int]

97

):

98

"""

99

Create transaction metadata.

100

101

Parameters:

102

- err: Optional[TransactionErrorType], transaction error (None if successful)

103

- fee: int, transaction fee in lamports

104

- pre_balances: List[int], account balances before execution

105

- post_balances: List[int], account balances after execution

106

- inner_instructions: Optional[List], cross-program invocation instructions

107

- log_messages: Optional[List[str]], program log messages

108

- pre_token_balances: Optional[List], token balances before execution

109

- post_token_balances: Optional[List], token balances after execution

110

- rewards: Optional[List[Reward]], epoch rewards (if any)

111

- loaded_addresses: Optional[UiLoadedAddresses], addresses loaded from lookup tables

112

- return_data: Optional[TransactionReturnData], program return data

113

- compute_units_consumed: Optional[int], compute units used

114

"""

115

116

@property

117

def err(self) -> Optional['TransactionErrorType']:

118

"""Transaction error (None if successful)."""

119

120

@property

121

def fee(self) -> int:

122

"""Transaction fee in lamports."""

123

124

@property

125

def pre_balances(self) -> List[int]:

126

"""Account balances before execution."""

127

128

@property

129

def post_balances(self) -> List[int]:

130

"""Account balances after execution."""

131

132

@property

133

def inner_instructions(self) -> Optional[List['UiInnerInstructions']]:

134

"""Cross-program invocation instructions."""

135

136

@property

137

def log_messages(self) -> Optional[List[str]]:

138

"""Program log messages."""

139

140

@property

141

def pre_token_balances(self) -> Optional[List['UiTransactionTokenBalance']]:

142

"""Token balances before execution."""

143

144

@property

145

def post_token_balances(self) -> Optional[List['UiTransactionTokenBalance']]:

146

"""Token balances after execution."""

147

148

@property

149

def rewards(self) -> Optional[List['Reward']]:

150

"""Epoch rewards (if any)."""

151

152

@property

153

def loaded_addresses(self) -> Optional['UiLoadedAddresses']:

154

"""Addresses loaded from lookup tables."""

155

156

@property

157

def return_data(self) -> Optional['TransactionReturnData']:

158

"""Program return data."""

159

160

@property

161

def compute_units_consumed(self) -> Optional[int]:

162

"""Compute units used."""

163

164

def is_successful(self) -> bool:

165

"""Check if transaction was successful."""

166

167

def get_balance_changes(self) -> List[int]:

168

"""

169

Calculate balance changes for each account.

170

171

Returns:

172

List[int], balance change for each account (post - pre)

173

"""

174

175

def get_fee_payer_balance_change(self) -> int:

176

"""

177

Get balance change for fee payer (first account).

178

179

Returns:

180

int, fee payer balance change including fees

181

"""

182

```

183

184

### Token Balance Changes

185

186

Token-specific balance tracking and change analysis.

187

188

```python { .api }

189

class UiTransactionTokenBalance:

190

"""

191

Token balance information for a transaction account.

192

"""

193

def __init__(

194

self,

195

account_index: int,

196

mint: str,

197

ui_token_amount: 'UiTokenAmount',

198

owner: Optional[str],

199

program_id: Optional[str]

200

):

201

"""

202

Create token balance information.

203

204

Parameters:

205

- account_index: int, index of account in transaction

206

- mint: str, token mint address

207

- ui_token_amount: UiTokenAmount, token amount with decimals

208

- owner: Optional[str], token account owner

209

- program_id: Optional[str], token program ID

210

"""

211

212

@property

213

def account_index(self) -> int:

214

"""Index of account in transaction."""

215

216

@property

217

def mint(self) -> str:

218

"""Token mint address."""

219

220

@property

221

def ui_token_amount(self) -> 'UiTokenAmount':

222

"""Token amount with decimals."""

223

224

@property

225

def owner(self) -> Optional[str]:

226

"""Token account owner."""

227

228

@property

229

def program_id(self) -> Optional[str]:

230

"""Token program ID."""

231

232

def calculate_token_balance_changes(

233

pre_balances: List['UiTransactionTokenBalance'],

234

post_balances: List['UiTransactionTokenBalance']

235

) -> List[tuple[str, str, float]]:

236

"""

237

Calculate token balance changes across transaction.

238

239

Parameters:

240

- pre_balances: List, token balances before transaction

241

- post_balances: List, token balances after transaction

242

243

Returns:

244

List[tuple[str, str, float]], (mint, owner, change_amount) for each change

245

"""

246

```

247

248

### Inner Instructions and Cross-Program Invocations

249

250

Detailed tracking of cross-program invocations and nested instruction execution.

251

252

```python { .api }

253

class UiInnerInstructions:

254

"""

255

Inner instructions from cross-program invocations.

256

"""

257

def __init__(self, index: int, instructions: List['UiInstruction']):

258

"""

259

Create inner instructions container.

260

261

Parameters:

262

- index: int, index of parent instruction that generated these

263

- instructions: List[UiInstruction], list of inner instructions

264

"""

265

266

@property

267

def index(self) -> int:

268

"""Index of parent instruction."""

269

270

@property

271

def instructions(self) -> List['UiInstruction']:

272

"""List of inner instructions."""

273

274

class UiInstruction:

275

"""

276

UI representation of an instruction (union type).

277

"""

278

# This is a union of UiParsedInstruction and UiCompiledInstruction

279

280

class UiParsedInstruction:

281

"""

282

Union of parsed and partially decoded instructions.

283

"""

284

# This is a union of ParsedInstruction and UiPartiallyDecodedInstruction

285

286

class ParsedInstruction:

287

"""

288

Fully parsed instruction with program-specific interpretation.

289

"""

290

def __init__(

291

self,

292

program: str,

293

program_id: Pubkey,

294

parsed: dict

295

):

296

"""

297

Create parsed instruction.

298

299

Parameters:

300

- program: str, program name (e.g., "spl-token")

301

- program_id: Pubkey, program ID that was invoked

302

- parsed: dict, program-specific parsed data

303

"""

304

305

@property

306

def program(self) -> str:

307

"""Program name."""

308

309

@property

310

def program_id(self) -> Pubkey:

311

"""Program ID that was invoked."""

312

313

@property

314

def parsed(self) -> dict:

315

"""Program-specific parsed data."""

316

317

class UiPartiallyDecodedInstruction:

318

"""

319

Partially decoded instruction with raw accounts and data.

320

"""

321

def __init__(

322

self,

323

program_id: Pubkey,

324

accounts: List[Pubkey],

325

data: str,

326

stack_height: Optional[int]

327

):

328

"""

329

Create partially decoded instruction.

330

331

Parameters:

332

- program_id: Pubkey, program that was invoked

333

- accounts: List[Pubkey], accounts passed to instruction

334

- data: str, base58-encoded instruction data

335

- stack_height: Optional[int], call stack depth

336

"""

337

338

@property

339

def program_id(self) -> Pubkey:

340

"""Program that was invoked."""

341

342

@property

343

def accounts(self) -> List[Pubkey]:

344

"""Accounts passed to instruction."""

345

346

@property

347

def data(self) -> str:

348

"""Base58-encoded instruction data."""

349

350

@property

351

def stack_height(self) -> Optional[int]:

352

"""Call stack depth."""

353

354

class UiCompiledInstruction:

355

"""

356

Compiled instruction with account indexes.

357

"""

358

def __init__(self, program_id_index: int, accounts: List[int], data: str):

359

"""

360

Create compiled instruction.

361

362

Parameters:

363

- program_id_index: int, index of program ID in account keys

364

- accounts: List[int], account indexes

365

- data: str, base58-encoded instruction data

366

"""

367

368

@property

369

def program_id_index(self) -> int:

370

"""Program ID index in account keys."""

371

372

@property

373

def accounts(self) -> List[int]:

374

"""Account indexes."""

375

376

@property

377

def data(self) -> str:

378

"""Base58-encoded instruction data."""

379

```

380

381

### Rewards and Incentives

382

383

Epoch reward distribution and staking incentive tracking.

384

385

```python { .api }

386

class Reward:

387

"""

388

Individual reward from epoch distribution.

389

"""

390

def __init__(

391

self,

392

pubkey: str,

393

lamports: int,

394

post_balance: int,

395

reward_type: Optional['RewardType'],

396

commission: Optional[int]

397

):

398

"""

399

Create reward information.

400

401

Parameters:

402

- pubkey: str, recipient account address

403

- lamports: int, reward amount in lamports

404

- post_balance: int, account balance after reward

405

- reward_type: Optional[RewardType], type of reward

406

- commission: Optional[int], validator commission (if applicable)

407

"""

408

409

@property

410

def pubkey(self) -> str:

411

"""Recipient account address."""

412

413

@property

414

def lamports(self) -> int:

415

"""Reward amount in lamports."""

416

417

@property

418

def post_balance(self) -> int:

419

"""Account balance after reward."""

420

421

@property

422

def reward_type(self) -> Optional['RewardType']:

423

"""Type of reward."""

424

425

@property

426

def commission(self) -> Optional[int]:

427

"""Validator commission (if applicable)."""

428

429

class RewardType:

430

"""Reward type enumeration."""

431

Fee: 'RewardType' # Transaction fees

432

Rent: 'RewardType' # Rent collection

433

Staking: 'RewardType' # Staking rewards

434

Voting: 'RewardType' # Voting rewards

435

436

def __str__(self) -> str:

437

"""String representation of reward type."""

438

```

439

440

### Transaction Encoding and Details

441

442

Transaction representation options and detail levels for different use cases.

443

444

```python { .api }

445

class TransactionDetails:

446

"""Transaction detail level for responses."""

447

Full: 'TransactionDetails' # Include all transaction details

448

Accounts: 'TransactionDetails' # Include only account keys

449

Signatures: 'TransactionDetails' # Include only signatures

450

None_: 'TransactionDetails' # Exclude transaction details

451

452

class UiTransactionEncoding:

453

"""Transaction encoding format for responses."""

454

Json: 'UiTransactionEncoding' # JSON format with parsed data

455

JsonParsed: 'UiTransactionEncoding' # JSON with program-specific parsing

456

Base58: 'UiTransactionEncoding' # Base58 encoded

457

Base64: 'UiTransactionEncoding' # Base64 encoded

458

459

class TransactionBinaryEncoding:

460

"""Binary transaction encoding format."""

461

Base58: 'TransactionBinaryEncoding' # Base58 encoded

462

Base64: 'TransactionBinaryEncoding' # Base64 encoded

463

```

464

465

### Transaction Return Data

466

467

Program return data and execution results.

468

469

```python { .api }

470

class TransactionReturnData:

471

"""

472

Return data from program execution.

473

"""

474

def __init__(self, program_id: Pubkey, data: bytes):

475

"""

476

Create transaction return data.

477

478

Parameters:

479

- program_id: Pubkey, program that returned the data

480

- data: bytes, returned data

481

"""

482

483

@property

484

def program_id(self) -> Pubkey:

485

"""Program that returned the data."""

486

487

@property

488

def data(self) -> bytes:

489

"""Returned data."""

490

491

def decode_string(self) -> str:

492

"""

493

Decode return data as UTF-8 string.

494

495

Returns:

496

str, decoded string data

497

498

Raises:

499

- UnicodeDecodeError: if data is not valid UTF-8

500

"""

501

502

def decode_json(self) -> dict:

503

"""

504

Decode return data as JSON.

505

506

Returns:

507

dict, parsed JSON data

508

509

Raises:

510

- JSONDecodeError: if data is not valid JSON

511

"""

512

```

513

514

### Address Lookup Table Support

515

516

Address lookup table metadata and loaded address information.

517

518

```python { .api }

519

class UiLoadedAddresses:

520

"""

521

Addresses loaded from lookup tables in versioned transactions.

522

"""

523

def __init__(self, writable: List[str], readonly: List[str]):

524

"""

525

Create loaded addresses information.

526

527

Parameters:

528

- writable: List[str], writable addresses from lookup tables

529

- readonly: List[str], readonly addresses from lookup tables

530

"""

531

532

@property

533

def writable(self) -> List[str]:

534

"""Writable addresses from lookup tables."""

535

536

@property

537

def readonly(self) -> List[str]:

538

"""Readonly addresses from lookup tables."""

539

540

def total_loaded(self) -> int:

541

"""

542

Get total number of loaded addresses.

543

544

Returns:

545

int, total loaded addresses (writable + readonly)

546

"""

547

548

class UiAddressTableLookup:

549

"""

550

Address table lookup reference in UI format.

551

"""

552

def __init__(

553

self,

554

account_key: str,

555

writable_indexes: List[int],

556

readonly_indexes: List[int]

557

):

558

"""

559

Create address table lookup.

560

561

Parameters:

562

- account_key: str, lookup table account address

563

- writable_indexes: List[int], indexes of writable addresses

564

- readonly_indexes: List[int], indexes of readonly addresses

565

"""

566

567

@property

568

def account_key(self) -> str:

569

"""Lookup table account address."""

570

571

@property

572

def writable_indexes(self) -> List[int]:

573

"""Indexes of writable addresses."""

574

575

@property

576

def readonly_indexes(self) -> List[int]:

577

"""Indexes of readonly addresses."""

578

```

579

580

## Usage Examples

581

582

### Transaction Status Monitoring

583

584

```python

585

from solders.transaction_status import TransactionStatus, TransactionConfirmationStatus

586

from solders.rpc.requests import GetSignatureStatuses

587

588

# Monitor transaction confirmation

589

def monitor_transaction_status(signatures: List[Signature]) -> dict:

590

"""Monitor status of multiple transactions."""

591

status_request = GetSignatureStatuses(signatures)

592

593

# After RPC call, process responses

594

results = {}

595

596

# Example processing (would get actual response from RPC)

597

for i, signature in enumerate(signatures):

598

# Parse status response

599

status = TransactionStatus(

600

slot=100000000,

601

confirmations=31, # Number of confirmations

602

status=None, # None means success

603

confirmation_status=TransactionConfirmationStatus.Finalized

604

)

605

606

results[str(signature)] = {

607

'successful': status.is_successful(),

608

'confirmed': status.is_confirmed(),

609

'slot': status.slot,

610

'confirmations': status.confirmations,

611

'confirmation_level': str(status.confirmation_status)

612

}

613

614

return results

615

616

# Wait for transaction confirmation

617

def wait_for_confirmation(signature: Signature, target_confirmations: int = 31):

618

"""Wait for transaction to reach target confirmation level."""

619

import time

620

621

while True:

622

status_request = GetSignatureStatuses([signature])

623

# Get response from RPC...

624

625

# Example status check (would parse actual RPC response)

626

if status and status.confirmations and status.confirmations >= target_confirmations:

627

print(f"Transaction confirmed with {status.confirmations} confirmations")

628

return True

629

630

time.sleep(1) # Wait 1 second before checking again

631

```

632

633

### Transaction Metadata Analysis

634

635

```python

636

from solders.transaction_status import UiTransactionStatusMeta

637

638

def analyze_transaction_execution(meta: UiTransactionStatusMeta):

639

"""Analyze transaction execution results."""

640

641

# Check success/failure

642

if meta.is_successful():

643

print("Transaction executed successfully")

644

else:

645

print(f"Transaction failed with error: {meta.err}")

646

647

# Analyze fees and balance changes

648

print(f"Transaction fee: {meta.fee} lamports ({meta.fee / 1e9:.9f} SOL)")

649

650

balance_changes = meta.get_balance_changes()

651

for i, change in enumerate(balance_changes):

652

if change != 0:

653

print(f"Account {i} balance change: {change:+,} lamports")

654

655

# Fee payer analysis

656

fee_payer_change = meta.get_fee_payer_balance_change()

657

print(f"Fee payer total change: {fee_payer_change:+,} lamports (including fees)")

658

659

# Compute unit consumption

660

if meta.compute_units_consumed:

661

print(f"Compute units used: {meta.compute_units_consumed:,}")

662

efficiency = (meta.compute_units_consumed / 200000) * 100 # Assuming 200k limit

663

print(f"Compute efficiency: {efficiency:.1f}% of limit")

664

665

# Log analysis

666

if meta.log_messages:

667

print(f"Program logs ({len(meta.log_messages)} messages):")

668

for log in meta.log_messages[:5]: # Show first 5 logs

669

print(f" {log}")

670

if len(meta.log_messages) > 5:

671

print(f" ... and {len(meta.log_messages) - 5} more")

672

673

def analyze_token_transfers(meta: UiTransactionStatusMeta):

674

"""Analyze token transfers in transaction."""

675

if not meta.pre_token_balances or not meta.post_token_balances:

676

print("No token balance information available")

677

return

678

679

# Calculate token changes

680

token_changes = calculate_token_balance_changes(

681

meta.pre_token_balances,

682

meta.post_token_balances

683

)

684

685

print(f"Token transfers ({len(token_changes)} changes):")

686

for mint, owner, change in token_changes:

687

if change != 0:

688

print(f" {owner}: {change:+.6f} tokens (mint: {mint})")

689

```

690

691

### Inner Instruction Analysis

692

693

```python

694

def analyze_cross_program_invocations(meta: UiTransactionStatusMeta):

695

"""Analyze cross-program invocations and inner instructions."""

696

if not meta.inner_instructions:

697

print("No cross-program invocations")

698

return

699

700

print(f"Cross-program invocations: {len(meta.inner_instructions)} instruction groups")

701

702

for inner_group in meta.inner_instructions:

703

print(f"\nInstruction {inner_group.index} invoked {len(inner_group.instructions)} inner instructions:")

704

705

for inner_ix in inner_group.instructions:

706

if isinstance(inner_ix, ParsedInstruction):

707

print(f" {inner_ix.program}: {inner_ix.parsed.get('type', 'unknown')}")

708

elif isinstance(inner_ix, UiPartiallyDecodedInstruction):

709

print(f" Program {inner_ix.program_id}: {len(inner_ix.accounts)} accounts")

710

if inner_ix.stack_height:

711

print(f" Stack height: {inner_ix.stack_height}")

712

713

def trace_program_execution(meta: UiTransactionStatusMeta):

714

"""Trace program execution through logs and inner instructions."""

715

execution_trace = []

716

717

# Add main instructions (would need transaction data)

718

# execution_trace.append("Main instruction: ...")

719

720

# Add inner instructions

721

if meta.inner_instructions:

722

for inner_group in meta.inner_instructions:

723

for inner_ix in inner_group.instructions:

724

if isinstance(inner_ix, ParsedInstruction):

725

execution_trace.append(f"CPI: {inner_ix.program}")

726

727

# Correlate with logs

728

if meta.log_messages:

729

for log in meta.log_messages:

730

if "invoke" in log.lower():

731

execution_trace.append(f"Log: {log}")

732

733

print("Execution trace:")

734

for i, event in enumerate(execution_trace):

735

print(f"{i+1:2d}. {event}")

736

```

737

738

### Reward Distribution Analysis

739

740

```python

741

def analyze_epoch_rewards(rewards: List[Reward]):

742

"""Analyze epoch reward distribution."""

743

if not rewards:

744

print("No rewards in this transaction")

745

return

746

747

total_rewards = sum(reward.lamports for reward in rewards)

748

print(f"Total rewards distributed: {total_rewards:,} lamports ({total_rewards / 1e9:.6f} SOL)")

749

750

# Group by reward type

751

by_type = {}

752

for reward in rewards:

753

reward_type = str(reward.reward_type) if reward.reward_type else "Unknown"

754

if reward_type not in by_type:

755

by_type[reward_type] = []

756

by_type[reward_type].append(reward)

757

758

for reward_type, type_rewards in by_type.items():

759

type_total = sum(r.lamports for r in type_rewards)

760

print(f"{reward_type}: {len(type_rewards)} recipients, {type_total:,} lamports")

761

762

# Show largest rewards

763

sorted_rewards = sorted(rewards, key=lambda r: r.lamports, reverse=True)

764

print(f"\nTop rewards:")

765

for reward in sorted_rewards[:5]:

766

print(f" {reward.pubkey}: {reward.lamports:,} lamports")

767

if reward.commission:

768

print(f" Commission: {reward.commission}%")

769

```

770

771

### Transaction Return Data Processing

772

773

```python

774

def process_return_data(return_data: TransactionReturnData):

775

"""Process program return data."""

776

print(f"Return data from program: {return_data.program_id}")

777

print(f"Data length: {len(return_data.data)} bytes")

778

779

# Try to decode as string

780

try:

781

text_data = return_data.decode_string()

782

print(f"String data: {text_data}")

783

except UnicodeDecodeError:

784

print("Data is not valid UTF-8 text")

785

786

# Try to decode as JSON

787

try:

788

json_data = return_data.decode_json()

789

print(f"JSON data: {json_data}")

790

except:

791

print("Data is not valid JSON")

792

793

# Show raw bytes (first 50 bytes)

794

hex_data = return_data.data[:50].hex()

795

print(f"Raw data (hex): {hex_data}{'...' if len(return_data.data) > 50 else ''}")

796

```

797

798

### Address Lookup Table Analysis

799

800

```python

801

def analyze_loaded_addresses(loaded_addresses: UiLoadedAddresses):

802

"""Analyze addresses loaded from lookup tables."""

803

total = loaded_addresses.total_loaded()

804

print(f"Loaded addresses: {total} total")

805

print(f" Writable: {len(loaded_addresses.writable)}")

806

print(f" Readonly: {len(loaded_addresses.readonly)}")

807

808

# Calculate compression savings

809

# Each address is 32 bytes, lookup table reference is much smaller

810

bytes_saved = total * 32 - (total * 1) # Simplified calculation

811

print(f"Approximate bytes saved: {bytes_saved}")

812

813

# Show some addresses

814

if loaded_addresses.writable:

815

print("Writable addresses:")

816

for addr in loaded_addresses.writable[:3]:

817

print(f" {addr}")

818

if len(loaded_addresses.writable) > 3:

819

print(f" ... and {len(loaded_addresses.writable) - 3} more")

820

821

def calculate_transaction_efficiency(meta: UiTransactionStatusMeta):

822

"""Calculate transaction efficiency metrics."""

823

metrics = {

824

'fee_per_account': meta.fee / len(meta.pre_balances) if meta.pre_balances else 0,

825

'accounts_modified': sum(1 for change in meta.get_balance_changes() if change != 0),

826

'inner_instruction_count': 0,

827

'log_message_count': len(meta.log_messages) if meta.log_messages else 0

828

}

829

830

if meta.inner_instructions:

831

metrics['inner_instruction_count'] = sum(

832

len(group.instructions) for group in meta.inner_instructions

833

)

834

835

if meta.compute_units_consumed:

836

metrics['compute_efficiency'] = meta.compute_units_consumed / 200000 # Assuming 200k limit

837

838

# Fee efficiency

839

if meta.compute_units_consumed:

840

metrics['fee_per_cu'] = meta.fee / meta.compute_units_consumed

841

842

return metrics

843

```

844

845

## Error Analysis

846

847

### Transaction Error Types

848

849

```python { .api }

850

# Union types for transaction errors

851

TransactionErrorType = Union[

852

TransactionErrorFieldless,

853

TransactionErrorInstructionError,

854

TransactionErrorDuplicateInstruction,

855

TransactionErrorInsufficientFundsForRent,

856

TransactionErrorProgramExecutionTemporarilyRestricted

857

]

858

859

InstructionErrorType = Union[

860

InstructionErrorFieldless,

861

InstructionErrorCustom,

862

InstructionErrorBorshIO

863

]

864

```

865

866

### Error Processing

867

868

```python

869

def analyze_transaction_error(error: TransactionErrorType):

870

"""Analyze and explain transaction error."""

871

if isinstance(error, TransactionErrorInstructionError):

872

instruction_index = error.instruction_index

873

instruction_error = error.error

874

875

print(f"Instruction {instruction_index} failed:")

876

877

if isinstance(instruction_error, InstructionErrorCustom):

878

print(f" Custom error code: {instruction_error.code}")

879

elif isinstance(instruction_error, InstructionErrorFieldless):

880

print(f" Error type: {instruction_error}")

881

else:

882

print(f" Error: {instruction_error}")

883

884

elif isinstance(error, TransactionErrorInsufficientFundsForRent):

885

account_index = error.account_index

886

print(f"Account {account_index} has insufficient funds for rent")

887

888

else:

889

print(f"Transaction error: {error}")

890

891

def suggest_error_fixes(error: TransactionErrorType) -> List[str]:

892

"""Suggest fixes for common transaction errors."""

893

suggestions = []

894

895

if "InsufficientFunds" in str(error):

896

suggestions.append("Add more SOL to the fee payer account")

897

suggestions.append("Reduce transaction complexity to lower fees")

898

899

elif "AccountNotFound" in str(error):

900

suggestions.append("Ensure all referenced accounts exist")

901

suggestions.append("Create missing accounts before transaction")

902

903

elif "InvalidAccountData" in str(error):

904

suggestions.append("Check account data format and size")

905

suggestions.append("Ensure account is owned by correct program")

906

907

elif "CustomError" in str(error):

908

suggestions.append("Check program documentation for error codes")

909

suggestions.append("Verify instruction parameters")

910

911

return suggestions

912

```

913

914

## Performance Monitoring

915

916

### Transaction Performance Metrics

917

918

```python

919

def calculate_performance_metrics(meta: UiTransactionStatusMeta) -> dict:

920

"""Calculate transaction performance metrics."""

921

metrics = {}

922

923

# Cost efficiency

924

metrics['cost_per_account'] = meta.fee / len(meta.pre_balances)

925

926

# Compute efficiency

927

if meta.compute_units_consumed:

928

metrics['compute_units_used'] = meta.compute_units_consumed

929

metrics['compute_utilization'] = meta.compute_units_consumed / 1400000 # Max CU

930

metrics['cost_per_compute_unit'] = meta.fee / meta.compute_units_consumed

931

932

# Complexity metrics

933

metrics['accounts_involved'] = len(meta.pre_balances)

934

metrics['accounts_modified'] = len([c for c in meta.get_balance_changes() if c != 0])

935

936

if meta.inner_instructions:

937

metrics['cpi_count'] = sum(len(group.instructions) for group in meta.inner_instructions)

938

metrics['max_stack_depth'] = max(

939

ix.stack_height or 1

940

for group in meta.inner_instructions

941

for ix in group.instructions

942

if hasattr(ix, 'stack_height') and ix.stack_height

943

)

944

945

return metrics

946

```