Files
eth-wallet-cli/wallet.py
2025-07-14 10:19:19 +03:00

166 lines
5.4 KiB
Python

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()