diff --git a/scripts/manage.py b/scripts/manage.py index bb10507..bd55a8e 100644 --- a/scripts/manage.py +++ b/scripts/manage.py @@ -3,6 +3,10 @@ from asyncio import run from tonsdk.boc import Cell, begin_cell from tonsdk.utils import Address +import pandas as pd +from datetime import datetime +from pytonapi import AsyncTonapi + from _auth import get_or_create_wallet_settings from _core import unpack_wallet, serialize_command, perform_action, print_actions @@ -11,6 +15,7 @@ async def main(): print('\n' * 30) wallet_settings = get_or_create_wallet_settings() wallet = unpack_wallet(wallet_settings) + wallet_address = wallet.address.to_string(1, 1, 1) print(f"=== Successfully loaded wallet {wallet.address.to_string(1, 1, 0)}") # print(wallet_settings) actions = [] @@ -24,6 +29,8 @@ async def main(): print("5) Export mnemonic phrase") print("7) New decentralized note") print("8) Read decentralized note") + print("9) View transactions history") + print("10) Export transactions history") print("0) View actions and exit | send transactions") choice = input("Select an action (1/2/3/4/0): ") @@ -33,6 +40,103 @@ async def main(): elif choice in {"5"}: print("=== Mnemonic phrase:") print(wallet_settings['mnemonic']) + continue + elif choice in {"9", "10"}: + print("=== Transactions history:") + tonapi = AsyncTonapi('AEA5YM3PU2YFXJIAAAAH3JWVNWRM57SFIBJGVJHCOK2GGPJ2L2MNKXBYPO7VTTY26ZRLX6I') + + transactions = [] + start_ts = None + while not start_ts or events.events: + try: + events = await tonapi.accounts.get_events(wallet_address, end_date=start_ts or None) + except BaseException as e: + if "rate limit" in str(e): + print("Rate limit exceeded. Please try again later.") + time.sleep(1) + continue + else: + print(f"TonAPI error: {e}") + + print(f"Fetched {len(events.events)} events from {start_ts}") + for event in events.events: + if event.in_progress is True: + continue + + event_dt = datetime.fromtimestamp(event.timestamp) + event_dtf = event_dt.strftime("%Y-%m-%d %H:%M:%S") + for event_action in event.actions: + transactions.append( + (event.event_id, event.lt, event_dtf, event_action.type, event_action) + ) + + if not start_ts or start_ts > event.timestamp: + start_ts = event.timestamp + + if choice == "9": + for event_action in reversed(transactions): + e_id, e_lt, e_dtf, e_type, e_action = event_action + action_formatted = f"TXID: {e_id}, logic time: {e_lt}. {e_dtf} {e_type}:" + '\n' + " " * 6 + if e_type == "TonTransfer": + e_action = e_action.TonTransfer + action_formatted += f"{Address(e_action.sender.address.to_raw()).to_string(1, 1, 1)}" \ + + f" sent {round(int(e_action.amount) / 10 ** 9, 3)} TON => {Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1)}" + if e_action.comment: + action_formatted += f". Comment: {e_action.comment}" + elif e_type == "JettonTransfer": + e_action = e_action.JettonTransfer + action_formatted += f"{Address(e_action.sender.address.to_raw()).to_string(1, 1, 1)}" \ + + f" sent {round(int(e_action.amount) / 10 ** e_action.jetton.decimals, 3)} {e_action.jetton.symbol} => {Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1)}" + if e_action.comment: + action_formatted += f". Comment: {e_action.comment}" + elif e_type == "NftItemTransfer": + e_action = e_action.NftItemTransfer + action_formatted += f"{Address(e_action.sender.address.to_raw()).to_string(1, 1, 1)}" \ + + f" sent NFT ({e_action.nft}) => {Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1)}" + else: + e_action = getattr(e_action, e_type) + action_formatted += "unknown action: " + str(e_action) + + print(action_formatted + '\n') + elif choice == "10": + dfr = [] + for event_action in reversed(transactions): + e_id, e_lt, e_dtf, e_type, e_action = event_action + if e_type == "TonTransfer": + e_action = e_action.TonTransfer + dfr.append([ + e_id, e_lt, e_dtf, e_type, + Address(e_action.sender.address.to_raw()).to_string(1, 1, 1), + Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1), + str(round(int(e_action.amount) / 10 ** 9, 3)), + e_action.comment or '' + ]) + elif e_type == "JettonTransfer": + e_action = e_action.JettonTransfer + dfr.append([ + e_id, e_lt, e_dtf, e_type, + Address(e_action.sender.address.to_raw()).to_string(1, 1, 1), + Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1), + str(round(int(e_action.amount) / 10 ** e_action.jetton.decimals, 3)), + e_action.comment or '' + ]) + elif e_type == "NftItemTransfer": + e_action = e_action.NftItemTransfer + dfr.append([ + e_id, e_lt, e_dtf, e_type, + Address(e_action.sender.address.to_raw()).to_string(1, 1, 1), + Address(e_action.recipient.address.to_raw()).to_string(1, 1, 1), + e_action.nft, + '' + ]) + + df = pd.DataFrame(dfr, columns=[ + 'TXID', 'Logic Time', 'Time', 'Type', 'Sender', 'Recipient', 'Amount', 'Comment' + ]) + df.to_csv('transactions_history.csv', sep=",") + print("Transactions history saved to transactions_history.csv") + + continue elif choice in {"1", "2", "3", "4", "7"}: action_type = int(choice) action = {"type": action_type, "args": []} diff --git a/scripts/requirements.txt b/scripts/requirements.txt index fb4dabe..9433d87 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,3 +1,5 @@ httpx==0.25.0 tonsdk==1.0.13 pycryptodome==3.19.0 +pytonapi==0.2.2 +pandas==2.2.2