import os import json import getpass from web3 import Web3 from Crypto.Cipher import AES from Crypto.Protocol.KDF import PBKDF2 from Crypto.Random import get_random_bytes from rich import print from rich.prompt import Prompt from eth_account import Account import requests WALLETS_DIR = "wallets" web3 = None selected_wallet = None wallet_data = None if not os.path.exists(WALLETS_DIR): os.makedirs(WALLETS_DIR) def encrypt_wallet(private_key, password): salt = get_random_bytes(16) key = PBKDF2(password, salt, dkLen=32) cipher = AES.new(key, AES.MODE_GCM) ciphertext, tag = cipher.encrypt_and_digest(private_key.encode()) return { 'ciphertext': ciphertext.hex(), 'salt': salt.hex(), 'nonce': cipher.nonce.hex(), 'tag': tag.hex() } def decrypt_wallet(data, password): salt = bytes.fromhex(data['salt']) key = PBKDF2(password, salt, dkLen=32) cipher = AES.new(key, AES.MODE_GCM, nonce=bytes.fromhex(data['nonce'])) return cipher.decrypt_and_verify(bytes.fromhex(data['ciphertext']), bytes.fromhex(data['tag'])).decode() def connect_to_network(): global web3 rpc_url = Prompt.ask("[bold cyan]Введите RPC URL[/]") web3 = Web3(Web3.HTTPProvider(rpc_url)) if web3.is_connected(): print("[green]Успешное подключение к сети Ethereum[/]") else: print("[red]Ошибка подключения к сети![/]") web3 = None def create_wallet(): Account.enable_unaudited_hdwallet_features() acct = Account.create() password = getpass.getpass("Введите пароль для шифрования кошелька: ") encrypted = encrypt_wallet(acct.key.hex(), password) filename = os.path.join(WALLETS_DIR, f"{acct.address}.json") with open(filename, 'w') as f: json.dump({"address": acct.address, "data": encrypted}, f) print(f"[green]Кошелек создан и сохранен: {acct.address}[/]") def select_wallet(): global selected_wallet, wallet_data files = os.listdir(WALLETS_DIR) if not files: print("[red]Нет доступных кошельков.[/]") return for i, fname in enumerate(files): print(f"[{i}] {fname}") choice = int(Prompt.ask("Выберите номер кошелька")) with open(os.path.join(WALLETS_DIR, files[choice])) as f: wallet_data = json.load(f) selected_wallet = wallet_data['address'] print(f"[green]Кошелек выбран: {selected_wallet}[/]") def get_balance(): if not selected_wallet: print("[red]Кошелек не выбран.[/]") return balance = web3.eth.get_balance(selected_wallet) print(f"Баланс: {web3.from_wei(balance, 'ether')} ETH") def fetch_gas_data(): try: res = requests.get("https://ethgas.watch/api/gas") data = res.json() fast = data['fast'] / 10 gas_price_wei = web3.to_wei(fast, 'gwei') eth_price = requests.get("https://api.coinbase.com/v2/prices/ETH-USD/spot").json()['data']['amount'] gas_usd = web3.from_wei(gas_price_wei * 21000, 'ether') * float(eth_price) return fast, gas_price_wei, round(gas_usd, 2) except: return None, None, None def send_transaction(): if not selected_wallet: print("[red]Кошелек не выбран.[/]") return password = getpass.getpass("Введите пароль от кошелька: ") try: private_key = decrypt_wallet(wallet_data['data'], password) except: print("[red]Неверный пароль![/]") return to = Prompt.ask("Введите адрес получателя") value = float(Prompt.ask("Введите сумму в ETH")) _, gas_price, _ = fetch_gas_data() print(f"[yellow]Текущая цена за газ: {gas_price}") tx = { 'nonce': web3.eth.get_transaction_count(selected_wallet), 'to': to, 'value': web3.to_wei(value, 'ether'), 'gas': 21000, 'gasPrice': gas_price } signed = web3.eth.account.sign_transaction(tx, private_key) tx_hash = web3.eth.send_raw_transaction(signed.rawTransaction) print(f"[green]Транзакция отправлена! TX Hash: {tx_hash.hex()}[/]") def main(): print(""" [bold blue]Меню:[/] a. Подключение к сети Ethereum c. Создание кошелька w. Выбор кошелька b. Просмотр баланса s. Отправка средств q. Выход """) while True: choice = Prompt.ask("Выберите действие").lower() if choice == 'a': connect_to_network() elif choice == 'c': create_wallet() elif choice == 'w': select_wallet() elif choice == 'b': if web3 and selected_wallet: get_balance() else: print("[red]Необходимо подключиться к сети и выбрать кошелек[/]") elif choice == 's': if web3 and selected_wallet: send_transaction() else: print("[red]Необходимо подключение и выбор кошелька[/]") elif choice == 'q': break else: print("[red]Неверный выбор[/]") if __name__ == "__main__": main()