lunalib 1.2.3__py3-none-any.whl → 1.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lunalib/core/blockchain.py +315 -150
- lunalib/core/crypto.py +265 -27
- lunalib/core/mempool.py +104 -102
- lunalib/core/sm2.py +723 -0
- lunalib/core/wallet.py +1026 -319
- lunalib/core/wallet_manager.py +638 -0
- lunalib/core/wallet_sync_helper.py +163 -0
- lunalib/mining/miner.py +24 -15
- lunalib/storage/cache.py +13 -4
- lunalib/storage/database.py +14 -5
- lunalib/storage/encryption.py +11 -2
- lunalib/transactions/security.py +96 -25
- lunalib/transactions/transactions.py +256 -431
- lunalib-1.5.2.dist-info/METADATA +20 -0
- lunalib-1.5.2.dist-info/RECORD +31 -0
- lunalib-1.5.2.dist-info/top_level.txt +1 -0
- core/__init__.py +0 -0
- core/blockchain.py +0 -172
- core/crypto.py +0 -32
- core/wallet.py +0 -347
- gtx/__init__.py +0 -0
- gtx/bill_registry.py +0 -122
- gtx/digital_bill.py +0 -273
- gtx/genesis.py +0 -338
- lunalib/requirements.txt +0 -44
- lunalib-1.2.3.dist-info/METADATA +0 -283
- lunalib-1.2.3.dist-info/RECORD +0 -50
- lunalib-1.2.3.dist-info/entry_points.txt +0 -2
- lunalib-1.2.3.dist-info/top_level.txt +0 -6
- mining/__init__.py +0 -0
- mining/cuda_manager.py +0 -137
- mining/difficulty.py +0 -106
- mining/miner.py +0 -107
- storage/__init__.py +0 -0
- storage/cache.py +0 -148
- storage/database.py +0 -222
- storage/encryption.py +0 -105
- transactions/__init__.py +0 -0
- transactions/security.py +0 -172
- transactions/transactions.py +0 -379
- transactions/validator.py +0 -71
- {lunalib-1.2.3.dist-info → lunalib-1.5.2.dist-info}/WHEEL +0 -0
lunalib/core/blockchain.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# blockchain.py - Updated version
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from ..storage.cache import BlockchainCache
|
|
4
4
|
import requests
|
|
5
5
|
import time
|
|
6
6
|
import json
|
|
@@ -14,6 +14,17 @@ class BlockchainManager:
|
|
|
14
14
|
self.endpoint_url = endpoint_url.rstrip('/')
|
|
15
15
|
self.cache = BlockchainCache()
|
|
16
16
|
self.network_connected = False
|
|
17
|
+
self._stop_events = [] # Track background monitors so they can be stopped
|
|
18
|
+
|
|
19
|
+
# ------------------------------------------------------------------
|
|
20
|
+
# Address helpers
|
|
21
|
+
# ------------------------------------------------------------------
|
|
22
|
+
def _normalize_address(self, addr: str) -> str:
|
|
23
|
+
"""Normalize LUN addresses for comparison (lowercase, strip, drop prefix)."""
|
|
24
|
+
if not addr:
|
|
25
|
+
return ''
|
|
26
|
+
addr_str = str(addr).strip("'\" ").lower()
|
|
27
|
+
return addr_str[4:] if addr_str.startswith('lun_') else addr_str
|
|
17
28
|
|
|
18
29
|
def broadcast_transaction(self, transaction: Dict) -> Tuple[bool, str]:
|
|
19
30
|
"""Broadcast transaction to mempool with enhanced error handling"""
|
|
@@ -257,6 +268,8 @@ class BlockchainManager:
|
|
|
257
268
|
"""Scan blockchain for transactions involving an address"""
|
|
258
269
|
if end_height is None:
|
|
259
270
|
end_height = self.get_blockchain_height()
|
|
271
|
+
|
|
272
|
+
print(f"[SCAN] Scanning transactions for {address} from block {start_height} to {end_height}")
|
|
260
273
|
|
|
261
274
|
transactions = []
|
|
262
275
|
|
|
@@ -264,14 +277,108 @@ class BlockchainManager:
|
|
|
264
277
|
batch_size = 100
|
|
265
278
|
for batch_start in range(start_height, end_height + 1, batch_size):
|
|
266
279
|
batch_end = min(batch_start + batch_size - 1, end_height)
|
|
280
|
+
print(f"[SCAN] Processing batch {batch_start}-{batch_end}...")
|
|
267
281
|
blocks = self.get_blocks_range(batch_start, batch_end)
|
|
268
282
|
|
|
269
283
|
for block in blocks:
|
|
270
284
|
block_transactions = self._find_address_transactions(block, address)
|
|
271
285
|
transactions.extend(block_transactions)
|
|
272
|
-
|
|
286
|
+
|
|
287
|
+
print(f"[SCAN] Found {len(transactions)} total transactions for {address}")
|
|
273
288
|
return transactions
|
|
274
289
|
|
|
290
|
+
def scan_transactions_for_addresses(self, addresses: List[str], start_height: int = 0, end_height: int = None) -> Dict[str, List[Dict]]:
|
|
291
|
+
"""Scan the blockchain once for multiple addresses (rewards and transfers)."""
|
|
292
|
+
if not addresses:
|
|
293
|
+
return {}
|
|
294
|
+
|
|
295
|
+
if end_height is None:
|
|
296
|
+
end_height = self.get_blockchain_height()
|
|
297
|
+
|
|
298
|
+
if end_height < start_height:
|
|
299
|
+
return {addr: [] for addr in addresses}
|
|
300
|
+
|
|
301
|
+
print(f"[MULTI-SCAN] Scanning {len(addresses)} addresses from block {start_height} to {end_height}")
|
|
302
|
+
|
|
303
|
+
# Map normalized address -> original address for quick lookup
|
|
304
|
+
normalized_map = {}
|
|
305
|
+
for addr in addresses:
|
|
306
|
+
norm = self._normalize_address(addr)
|
|
307
|
+
if norm:
|
|
308
|
+
normalized_map[norm] = addr
|
|
309
|
+
|
|
310
|
+
results: Dict[str, List[Dict]] = {addr: [] for addr in addresses}
|
|
311
|
+
|
|
312
|
+
batch_size = 100
|
|
313
|
+
for batch_start in range(start_height, end_height + 1, batch_size):
|
|
314
|
+
batch_end = min(batch_start + batch_size - 1, end_height)
|
|
315
|
+
print(f"[MULTI-SCAN] Processing batch {batch_start}-{batch_end}...")
|
|
316
|
+
blocks = self.get_blocks_range(batch_start, batch_end)
|
|
317
|
+
|
|
318
|
+
for block in blocks:
|
|
319
|
+
collected = self._collect_transactions_for_addresses(block, normalized_map)
|
|
320
|
+
for original_addr, txs in collected.items():
|
|
321
|
+
if txs:
|
|
322
|
+
results[original_addr].extend(txs)
|
|
323
|
+
|
|
324
|
+
# Summary
|
|
325
|
+
total_txs = sum(len(txs) for txs in results.values())
|
|
326
|
+
print(f"[MULTI-SCAN] Found {total_txs} total transactions")
|
|
327
|
+
for addr in addresses:
|
|
328
|
+
print(f" - {addr}: {len(results[addr])} transactions")
|
|
329
|
+
|
|
330
|
+
return results
|
|
331
|
+
|
|
332
|
+
def monitor_addresses(self, addresses: List[str], on_update, poll_interval: int = 15):
|
|
333
|
+
"""Start background monitor for addresses; returns a stop event."""
|
|
334
|
+
import threading
|
|
335
|
+
from lunalib.core.mempool import MempoolManager
|
|
336
|
+
|
|
337
|
+
stop_event = threading.Event()
|
|
338
|
+
self._stop_events.append(stop_event)
|
|
339
|
+
|
|
340
|
+
mempool = MempoolManager()
|
|
341
|
+
last_height = self.get_blockchain_height()
|
|
342
|
+
|
|
343
|
+
def _emit_update(confirmed_map: Dict[str, List[Dict]], pending_map: Dict[str, List[Dict]], source: str):
|
|
344
|
+
try:
|
|
345
|
+
if on_update:
|
|
346
|
+
on_update({
|
|
347
|
+
'confirmed': confirmed_map or {},
|
|
348
|
+
'pending': pending_map or {},
|
|
349
|
+
'source': source
|
|
350
|
+
})
|
|
351
|
+
except Exception as e:
|
|
352
|
+
print(f"Monitor callback error: {e}")
|
|
353
|
+
|
|
354
|
+
def _monitor_loop():
|
|
355
|
+
nonlocal last_height
|
|
356
|
+
|
|
357
|
+
# Initial emission: existing chain + current mempool
|
|
358
|
+
initial_confirmed = self.scan_transactions_for_addresses(addresses, 0, last_height)
|
|
359
|
+
initial_pending = mempool.get_pending_transactions_for_addresses(addresses)
|
|
360
|
+
_emit_update(initial_confirmed, initial_pending, source="initial")
|
|
361
|
+
|
|
362
|
+
while not stop_event.wait(poll_interval):
|
|
363
|
+
try:
|
|
364
|
+
current_height = self.get_blockchain_height()
|
|
365
|
+
if current_height > last_height:
|
|
366
|
+
new_confirmed = self.scan_transactions_for_addresses(addresses, last_height + 1, current_height)
|
|
367
|
+
if any(new_confirmed.values()):
|
|
368
|
+
_emit_update(new_confirmed, {}, source="blockchain")
|
|
369
|
+
last_height = current_height
|
|
370
|
+
|
|
371
|
+
pending_now = mempool.get_pending_transactions_for_addresses(addresses)
|
|
372
|
+
if any(pending_now.values()):
|
|
373
|
+
_emit_update({}, pending_now, source="mempool")
|
|
374
|
+
|
|
375
|
+
except Exception as e:
|
|
376
|
+
print(f"Monitor loop error: {e}")
|
|
377
|
+
|
|
378
|
+
thread = threading.Thread(target=_monitor_loop, daemon=True)
|
|
379
|
+
thread.start()
|
|
380
|
+
return stop_event
|
|
381
|
+
|
|
275
382
|
def submit_mined_block(self, block_data: Dict) -> bool:
|
|
276
383
|
"""Submit a mined block to the network with built-in validation"""
|
|
277
384
|
try:
|
|
@@ -404,174 +511,232 @@ class BlockchainManager:
|
|
|
404
511
|
}
|
|
405
512
|
}
|
|
406
513
|
|
|
514
|
+
def _collect_transactions_for_addresses(self, block: Dict, normalized_map: Dict[str, str]) -> Dict[str, List[Dict]]:
|
|
515
|
+
"""Collect transactions in a block for multiple addresses in one pass."""
|
|
516
|
+
results: Dict[str, List[Dict]] = {original: [] for original in normalized_map.values()}
|
|
517
|
+
|
|
518
|
+
# Mining reward via block metadata
|
|
519
|
+
miner_norm = self._normalize_address(block.get('miner', ''))
|
|
520
|
+
if miner_norm in normalized_map:
|
|
521
|
+
reward_amount = float(block.get('reward', 0) or 0)
|
|
522
|
+
if reward_amount > 0:
|
|
523
|
+
target_addr = normalized_map[miner_norm]
|
|
524
|
+
reward_tx = {
|
|
525
|
+
'type': 'reward',
|
|
526
|
+
'from': 'network',
|
|
527
|
+
'to': target_addr,
|
|
528
|
+
'amount': reward_amount,
|
|
529
|
+
'block_height': block.get('index'),
|
|
530
|
+
'timestamp': block.get('timestamp'),
|
|
531
|
+
'hash': f"reward_{block.get('index')}_{block.get('hash', '')[:8]}",
|
|
532
|
+
'status': 'confirmed',
|
|
533
|
+
'description': f"Mining reward for block #{block.get('index')}",
|
|
534
|
+
'direction': 'incoming',
|
|
535
|
+
'effective_amount': reward_amount,
|
|
536
|
+
'fee': 0
|
|
537
|
+
}
|
|
538
|
+
results[target_addr].append(reward_tx)
|
|
539
|
+
|
|
540
|
+
# Regular transactions
|
|
541
|
+
for tx_index, tx in enumerate(block.get('transactions', [])):
|
|
542
|
+
tx_type = (tx.get('type') or 'transfer').lower()
|
|
543
|
+
from_norm = self._normalize_address(tx.get('from') or tx.get('sender') or '')
|
|
544
|
+
to_norm = self._normalize_address(tx.get('to') or tx.get('receiver') or '')
|
|
545
|
+
|
|
546
|
+
# Explicit reward transaction
|
|
547
|
+
if tx_type == 'reward' and to_norm in normalized_map:
|
|
548
|
+
target_addr = normalized_map[to_norm]
|
|
549
|
+
amount = float(tx.get('amount', 0) or 0)
|
|
550
|
+
enhanced = tx.copy()
|
|
551
|
+
enhanced.update({
|
|
552
|
+
'block_height': block.get('index'),
|
|
553
|
+
'status': 'confirmed',
|
|
554
|
+
'tx_index': tx_index,
|
|
555
|
+
'direction': 'incoming',
|
|
556
|
+
'effective_amount': amount,
|
|
557
|
+
'fee': 0,
|
|
558
|
+
})
|
|
559
|
+
enhanced.setdefault('from', 'network')
|
|
560
|
+
results[target_addr].append(enhanced)
|
|
561
|
+
continue
|
|
562
|
+
|
|
563
|
+
# Incoming transfer
|
|
564
|
+
if to_norm in normalized_map:
|
|
565
|
+
target_addr = normalized_map[to_norm]
|
|
566
|
+
amount = float(tx.get('amount', 0) or 0)
|
|
567
|
+
fee = float(tx.get('fee', 0) or tx.get('gas', 0) or 0)
|
|
568
|
+
enhanced = tx.copy()
|
|
569
|
+
enhanced.update({
|
|
570
|
+
'block_height': block.get('index'),
|
|
571
|
+
'status': 'confirmed',
|
|
572
|
+
'tx_index': tx_index,
|
|
573
|
+
'direction': 'incoming',
|
|
574
|
+
'effective_amount': amount,
|
|
575
|
+
'amount': amount,
|
|
576
|
+
'fee': fee
|
|
577
|
+
})
|
|
578
|
+
results[target_addr].append(enhanced)
|
|
579
|
+
|
|
580
|
+
# Outgoing transfer
|
|
581
|
+
if from_norm in normalized_map:
|
|
582
|
+
target_addr = normalized_map[from_norm]
|
|
583
|
+
amount = float(tx.get('amount', 0) or 0)
|
|
584
|
+
fee = float(tx.get('fee', 0) or tx.get('gas', 0) or 0)
|
|
585
|
+
enhanced = tx.copy()
|
|
586
|
+
enhanced.update({
|
|
587
|
+
'block_height': block.get('index'),
|
|
588
|
+
'status': 'confirmed',
|
|
589
|
+
'tx_index': tx_index,
|
|
590
|
+
'direction': 'outgoing',
|
|
591
|
+
'effective_amount': -(amount + fee),
|
|
592
|
+
'amount': amount,
|
|
593
|
+
'fee': fee
|
|
594
|
+
})
|
|
595
|
+
results[target_addr].append(enhanced)
|
|
596
|
+
|
|
597
|
+
# Trim empty entries
|
|
598
|
+
return {addr: txs for addr, txs in results.items() if txs}
|
|
599
|
+
|
|
407
600
|
def _find_address_transactions(self, block: Dict, address: str) -> List[Dict]:
|
|
408
|
-
"""Find transactions in block that involve the address - FIXED
|
|
601
|
+
"""Find transactions in block that involve the address - FIXED REWARD DETECTION"""
|
|
409
602
|
transactions = []
|
|
410
|
-
address_lower = address.lower()
|
|
603
|
+
address_lower = address.lower().strip('"\'') # Remove quotes if present
|
|
411
604
|
|
|
412
605
|
print(f"🔍 Scanning block #{block.get('index')} for address: {address}")
|
|
606
|
+
print(f" Block data: {block}")
|
|
607
|
+
|
|
608
|
+
# ==================================================================
|
|
609
|
+
# 1. CHECK BLOCK MINING REWARD (from block metadata)
|
|
610
|
+
# ==================================================================
|
|
611
|
+
miner = block.get('miner', '')
|
|
612
|
+
# Clean the miner address (remove quotes, trim)
|
|
613
|
+
miner_clean = str(miner).strip('"\' ')
|
|
614
|
+
|
|
615
|
+
print(f" Miner in block: '{miner_clean}'")
|
|
616
|
+
print(f" Our address: '{address_lower}'")
|
|
617
|
+
print(f" Block reward: {block.get('reward', 0)}")
|
|
618
|
+
|
|
619
|
+
# Function to normalize addresses for comparison
|
|
620
|
+
def normalize_address(addr):
|
|
621
|
+
if not addr:
|
|
622
|
+
return ''
|
|
623
|
+
# Remove LUN_ prefix and quotes, convert to lowercase
|
|
624
|
+
addr_str = str(addr).strip('"\' ').lower()
|
|
625
|
+
# Remove 'lun_' prefix if present
|
|
626
|
+
if addr_str.startswith('lun_'):
|
|
627
|
+
addr_str = addr_str[4:]
|
|
628
|
+
return addr_str
|
|
629
|
+
|
|
630
|
+
# Normalize both addresses
|
|
631
|
+
miner_normalized = normalize_address(miner_clean)
|
|
632
|
+
address_normalized = normalize_address(address_lower)
|
|
633
|
+
|
|
634
|
+
print(f" Miner normalized: '{miner_normalized}'")
|
|
635
|
+
print(f" Address normalized: '{address_normalized}'")
|
|
636
|
+
|
|
637
|
+
# Check if this block was mined by our address
|
|
638
|
+
if miner_normalized == address_normalized and miner_normalized:
|
|
639
|
+
reward_amount = float(block.get('reward', 0))
|
|
640
|
+
if reward_amount > 0:
|
|
641
|
+
reward_tx = {
|
|
642
|
+
'type': 'reward',
|
|
643
|
+
'from': 'network',
|
|
644
|
+
'to': address,
|
|
645
|
+
'amount': reward_amount,
|
|
646
|
+
'block_height': block.get('index'),
|
|
647
|
+
'timestamp': block.get('timestamp'),
|
|
648
|
+
'hash': f"reward_{block.get('index')}_{block.get('hash', '')[:8]}",
|
|
649
|
+
'status': 'confirmed',
|
|
650
|
+
'description': f'Mining reward for block #{block.get("index")}',
|
|
651
|
+
'direction': 'incoming',
|
|
652
|
+
'effective_amount': reward_amount,
|
|
653
|
+
'fee': 0
|
|
654
|
+
}
|
|
655
|
+
transactions.append(reward_tx)
|
|
656
|
+
print(f"🎁 FOUND MINING REWARD: {reward_amount} LUN for block #{block.get('index')}")
|
|
657
|
+
print(f" Miner match: '{miner_clean}' == '{address}'")
|
|
658
|
+
else:
|
|
659
|
+
print(f" Not our block - Miner: '{miner_clean}', Our address: '{address}'")
|
|
413
660
|
|
|
414
|
-
#
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
reward_tx = {
|
|
418
|
-
'type': 'reward',
|
|
419
|
-
'from': 'network',
|
|
420
|
-
'to': address,
|
|
421
|
-
'amount': float(block.get('reward', 0)),
|
|
422
|
-
'block_height': block.get('index'),
|
|
423
|
-
'timestamp': block.get('timestamp'),
|
|
424
|
-
'hash': f"reward_{block.get('index')}_{address}",
|
|
425
|
-
'status': 'confirmed',
|
|
426
|
-
'description': f'Mining reward for block #{block.get("index")}',
|
|
427
|
-
'direction': 'incoming',
|
|
428
|
-
'effective_amount': float(block.get('reward', 0))
|
|
429
|
-
}
|
|
430
|
-
transactions.append(reward_tx)
|
|
431
|
-
print(f"🎁 Found mining reward: {block.get('reward', 0)} LUN for block #{block.get('index')}")
|
|
432
|
-
|
|
433
|
-
# Check all transactions in the block
|
|
661
|
+
# ==================================================================
|
|
662
|
+
# 2. CHECK ALL TRANSACTIONS IN THE BLOCK
|
|
663
|
+
# ==================================================================
|
|
434
664
|
block_transactions = block.get('transactions', [])
|
|
435
|
-
print(f"
|
|
665
|
+
print(f" Block has {len(block_transactions)} transactions")
|
|
436
666
|
|
|
437
667
|
for tx_index, tx in enumerate(block_transactions):
|
|
438
|
-
|
|
668
|
+
enhanced_tx = tx.copy()
|
|
669
|
+
enhanced_tx['block_height'] = block.get('index')
|
|
670
|
+
enhanced_tx['status'] = 'confirmed'
|
|
671
|
+
enhanced_tx['tx_index'] = tx_index
|
|
439
672
|
|
|
440
|
-
#
|
|
441
|
-
|
|
673
|
+
# Get transaction type
|
|
674
|
+
tx_type = tx.get('type', 'transfer').lower()
|
|
442
675
|
|
|
443
|
-
#
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
676
|
+
# Helper function for address matching with normalization
|
|
677
|
+
def addresses_match(addr1, addr2):
|
|
678
|
+
if not addr1 or not addr2:
|
|
679
|
+
return False
|
|
447
680
|
|
|
448
|
-
#
|
|
449
|
-
|
|
681
|
+
# Normalize both addresses
|
|
682
|
+
addr1_norm = normalize_address(addr1)
|
|
683
|
+
addr2_norm = normalize_address(addr2)
|
|
450
684
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
print(f" To: {enhanced_tx.get('to', 'unknown')}")
|
|
468
|
-
else:
|
|
469
|
-
# For incoming: positive amount only
|
|
470
|
-
enhanced_tx['effective_amount'] = enhanced_tx['amount']
|
|
471
|
-
print(f" ⬆️ INCOMING: +{enhanced_tx['amount']}")
|
|
472
|
-
print(f" From: {enhanced_tx.get('from', 'unknown')}")
|
|
473
|
-
print(f" To: {enhanced_tx.get('to', 'unknown')}")
|
|
474
|
-
|
|
685
|
+
# Check if they match
|
|
686
|
+
return addr1_norm == addr2_norm
|
|
687
|
+
|
|
688
|
+
# ==================================================================
|
|
689
|
+
# A) REWARD TRANSACTIONS (explicit reward transactions)
|
|
690
|
+
# ==================================================================
|
|
691
|
+
tx_type = tx.get('type', 'transfer').lower()
|
|
692
|
+
if tx_type == 'reward':
|
|
693
|
+
reward_to_address = tx.get('to', '')
|
|
694
|
+
# Compare the reward's destination with our wallet address
|
|
695
|
+
if addresses_match(reward_to_address, address):
|
|
696
|
+
amount = float(tx.get('amount', 0))
|
|
697
|
+
enhanced_tx['direction'] = 'incoming'
|
|
698
|
+
enhanced_tx['effective_amount'] = amount
|
|
699
|
+
enhanced_tx['fee'] = 0
|
|
700
|
+
enhanced_tx.setdefault('from', 'network') # Ensure sender is set
|
|
475
701
|
transactions.append(enhanced_tx)
|
|
476
|
-
|
|
702
|
+
print(f"✅ Found mining reward: {amount} LUN (to: {reward_to_address})")
|
|
703
|
+
continue # Move to next transaction
|
|
477
704
|
|
|
478
|
-
#
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
705
|
+
# ==================================================================
|
|
706
|
+
# B) REGULAR TRANSFERS
|
|
707
|
+
# ==================================================================
|
|
708
|
+
from_addr = tx.get('from') or tx.get('sender') or ''
|
|
709
|
+
to_addr = tx.get('to') or tx.get('receiver') or ''
|
|
710
|
+
|
|
711
|
+
# Check if transaction involves our address
|
|
712
|
+
is_incoming = addresses_match(to_addr, address)
|
|
713
|
+
is_outgoing = addresses_match(from_addr, address)
|
|
714
|
+
|
|
715
|
+
if is_incoming:
|
|
482
716
|
amount = float(tx.get('amount', 0))
|
|
483
|
-
fee = float(tx.get('fee', 0))
|
|
717
|
+
fee = float(tx.get('fee', 0) or tx.get('gas', 0) or 0)
|
|
484
718
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
enhanced_tx['type'] = tx.get('bill_type', 'transfer')
|
|
495
|
-
|
|
496
|
-
# Ensure amounts are floats
|
|
497
|
-
enhanced_tx['amount'] = amount
|
|
498
|
-
enhanced_tx['fee'] = fee
|
|
499
|
-
|
|
500
|
-
# Add direction information
|
|
501
|
-
if from_addr == address_lower:
|
|
502
|
-
enhanced_tx['direction'] = 'outgoing'
|
|
503
|
-
# For outgoing: negative (amount + fee)
|
|
504
|
-
enhanced_tx['effective_amount'] = -(amount + fee)
|
|
505
|
-
print(f" ⬇️ STANDARD OUTGOING from our address")
|
|
506
|
-
print(f" From: {from_addr} (OURS)")
|
|
507
|
-
print(f" To: {to_addr}")
|
|
508
|
-
print(f" Amount: {amount}, Fee: {fee}, Total: {enhanced_tx['effective_amount']}")
|
|
509
|
-
else:
|
|
510
|
-
enhanced_tx['direction'] = 'incoming'
|
|
511
|
-
enhanced_tx['effective_amount'] = amount
|
|
512
|
-
print(f" ⬆️ STANDARD INCOMING to our address")
|
|
513
|
-
print(f" From: {from_addr}")
|
|
514
|
-
print(f" To: {to_addr} (OURS)")
|
|
515
|
-
print(f" Amount: {amount}")
|
|
516
|
-
|
|
517
|
-
transactions.append(enhanced_tx)
|
|
518
|
-
continue
|
|
519
|
-
|
|
520
|
-
# Method 2: Check for GTX/bill_type format
|
|
521
|
-
if 'bill_type' in tx:
|
|
522
|
-
bill_type = tx.get('bill_type', '')
|
|
719
|
+
enhanced_tx['direction'] = 'incoming'
|
|
720
|
+
enhanced_tx['effective_amount'] = amount
|
|
721
|
+
enhanced_tx['amount'] = amount
|
|
722
|
+
enhanced_tx['fee'] = fee
|
|
723
|
+
|
|
724
|
+
transactions.append(enhanced_tx)
|
|
725
|
+
print(f"⬆️ Found incoming transaction: {amount} LUN")
|
|
726
|
+
|
|
727
|
+
elif is_outgoing:
|
|
523
728
|
amount = float(tx.get('amount', 0))
|
|
524
|
-
fee = float(tx.get('fee', 0))
|
|
729
|
+
fee = float(tx.get('fee', 0) or tx.get('gas', 0) or 0)
|
|
525
730
|
|
|
526
|
-
|
|
527
|
-
|
|
731
|
+
enhanced_tx['direction'] = 'outgoing'
|
|
732
|
+
enhanced_tx['effective_amount'] = -(amount + fee)
|
|
733
|
+
enhanced_tx['amount'] = amount
|
|
734
|
+
enhanced_tx['fee'] = fee
|
|
528
735
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
tx_addr = (tx.get(field) or '').lower()
|
|
532
|
-
if tx_addr == address_lower:
|
|
533
|
-
enhanced_tx = tx.copy()
|
|
534
|
-
enhanced_tx['block_height'] = block.get('index')
|
|
535
|
-
enhanced_tx['status'] = 'confirmed'
|
|
536
|
-
enhanced_tx['tx_index'] = tx_index
|
|
537
|
-
enhanced_tx['type'] = bill_type.lower()
|
|
538
|
-
|
|
539
|
-
# Map bill_type to standard type
|
|
540
|
-
if 'gtx_genesis' in bill_type.lower():
|
|
541
|
-
enhanced_tx['type'] = 'gtx_genesis'
|
|
542
|
-
enhanced_tx['description'] = 'GTX Genesis Transaction'
|
|
543
|
-
|
|
544
|
-
enhanced_tx['amount'] = amount
|
|
545
|
-
enhanced_tx['fee'] = fee
|
|
546
|
-
|
|
547
|
-
# Determine direction
|
|
548
|
-
if field in ['from_address', 'from', 'sender']:
|
|
549
|
-
enhanced_tx['direction'] = 'outgoing'
|
|
550
|
-
enhanced_tx['effective_amount'] = -(amount + fee)
|
|
551
|
-
enhanced_tx['from'] = tx_addr
|
|
552
|
-
enhanced_tx['to'] = tx.get('to_address') or tx.get('receiver') or tx.get('to') or 'unknown'
|
|
553
|
-
print(f" ⬇️ GTX OUTGOING ({bill_type})")
|
|
554
|
-
print(f" From: {tx_addr} (OURS)")
|
|
555
|
-
print(f" Amount: {amount}, Fee: {fee}, Total: {enhanced_tx['effective_amount']}")
|
|
556
|
-
else:
|
|
557
|
-
enhanced_tx['direction'] = 'incoming'
|
|
558
|
-
enhanced_tx['effective_amount'] = amount
|
|
559
|
-
enhanced_tx['from'] = tx.get('from_address') or tx.get('sender') or tx.get('from') or 'network'
|
|
560
|
-
enhanced_tx['to'] = tx_addr
|
|
561
|
-
print(f" ⬆️ GTX INCOMING ({bill_type})")
|
|
562
|
-
print(f" To: {tx_addr} (OURS)")
|
|
563
|
-
print(f" Amount: {amount}")
|
|
564
|
-
|
|
565
|
-
transactions.append(enhanced_tx)
|
|
566
|
-
break
|
|
567
|
-
|
|
568
|
-
print(f"\n ✅ Total transactions found for address: {len(transactions)}")
|
|
569
|
-
|
|
570
|
-
# Debug: Show transaction types found
|
|
571
|
-
incoming = [t for t in transactions if t.get('direction') == 'incoming']
|
|
572
|
-
outgoing = [t for t in transactions if t.get('direction') == 'outgoing']
|
|
573
|
-
print(f" Incoming: {len(incoming)}, Outgoing: {len(outgoing)}")
|
|
736
|
+
transactions.append(enhanced_tx)
|
|
737
|
+
print(f"⬇️ Found outgoing transaction: {amount} LUN + {fee} fee")
|
|
574
738
|
|
|
739
|
+
print(f"📊 Scan complete for block #{block.get('index')}: {len(transactions)} transactions found")
|
|
575
740
|
return transactions
|
|
576
741
|
def _handle_regular_transfers(self, tx: Dict, address_lower: str) -> Dict:
|
|
577
742
|
"""Handle regular transfer transactions that might be in different formats"""
|