feat: migrate wallet daemon and CLI to use centralized aitbc package utilities
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 9s
CLI Tests / test-cli (push) Failing after 3s
Integration Tests / test-service-integration (push) Successful in 41s
Python Tests / test-python (push) Failing after 18s
Security Scanning / security-scan (push) Failing after 2m0s
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 9s
CLI Tests / test-cli (push) Failing after 3s
Integration Tests / test-service-integration (push) Successful in 41s
Python Tests / test-python (push) Failing after 18s
Security Scanning / security-scan (push) Failing after 2m0s
- Migrate simple_daemon.py from mock data to real keystore and blockchain RPC integration - Add httpx for async HTTP client in wallet daemon - Implement real wallet listing from keystore directory - Implement blockchain balance queries via RPC - Update CLI to use aitbc.AITBCHTTPClient instead of requests - Add aitbc imports: constants, http_client, exceptions, logging, paths, validation - Add address and amount validation in
This commit is contained in:
@@ -8,9 +8,11 @@ import json
|
||||
import base64
|
||||
from typing import Dict, Any, Optional, List
|
||||
from pathlib import Path
|
||||
import httpx
|
||||
from dataclasses import dataclass
|
||||
|
||||
from aitbc.http_client import AITBCHTTPClient
|
||||
from aitbc.exceptions import NetworkError
|
||||
|
||||
from utils import error, success
|
||||
from config import Config
|
||||
|
||||
@@ -65,10 +67,10 @@ class WalletDaemonClient:
|
||||
self.config = config
|
||||
self.base_url = config.wallet_url.rstrip('/')
|
||||
self.timeout = getattr(config, 'timeout', 30)
|
||||
|
||||
def _get_http_client(self) -> httpx.Client:
|
||||
|
||||
def _get_http_client(self) -> AITBCHTTPClient:
|
||||
"""Create HTTP client with appropriate settings"""
|
||||
return httpx.Client(
|
||||
return AITBCHTTPClient(
|
||||
base_url=self.base_url,
|
||||
timeout=self.timeout,
|
||||
headers={"Content-Type": "application/json"}
|
||||
@@ -77,47 +79,46 @@ class WalletDaemonClient:
|
||||
def is_available(self) -> bool:
|
||||
"""Check if wallet daemon is available and responsive"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
response = client.get("/health")
|
||||
return response.status_code == 200
|
||||
client = self._get_http_client()
|
||||
client.get("/health")
|
||||
return True
|
||||
except NetworkError:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
"""Get wallet daemon status information"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
response = client.get("/health")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
return {"status": "unavailable", "error": f"HTTP {response.status_code}"}
|
||||
client = self._get_http_client()
|
||||
return client.get("/health")
|
||||
except NetworkError as e:
|
||||
return {"status": "unavailable", "error": str(e)}
|
||||
except Exception as e:
|
||||
return {"status": "error", "error": str(e)}
|
||||
|
||||
def create_wallet(self, wallet_id: str, password: str, metadata: Optional[Dict[str, Any]] = None) -> WalletInfo:
|
||||
"""Create a new wallet in the daemon"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
payload = {
|
||||
"wallet_id": wallet_id,
|
||||
"password": password,
|
||||
"metadata": metadata or {}
|
||||
}
|
||||
|
||||
response = client.post("/v1/wallets", json=payload)
|
||||
if response.status_code == 201:
|
||||
data = response.json()
|
||||
return WalletInfo(
|
||||
wallet_id=data["wallet_id"],
|
||||
public_key=data["public_key"],
|
||||
address=data.get("address"),
|
||||
created_at=data.get("created_at"),
|
||||
metadata=data.get("metadata")
|
||||
)
|
||||
else:
|
||||
error(f"Failed to create wallet: {response.text}")
|
||||
raise Exception(f"HTTP {response.status_code}: {response.text}")
|
||||
client = self._get_http_client()
|
||||
payload = {
|
||||
"wallet_id": wallet_id,
|
||||
"password": password,
|
||||
"metadata": metadata or {}
|
||||
}
|
||||
|
||||
data = client.post("/v1/wallets", json=payload)
|
||||
return WalletInfo(
|
||||
wallet_id=data["wallet_id"],
|
||||
chain_id=data.get("chain_id", "default"),
|
||||
public_key=data["public_key"],
|
||||
address=data.get("address"),
|
||||
created_at=data.get("created_at"),
|
||||
metadata=data.get("metadata")
|
||||
)
|
||||
except NetworkError as e:
|
||||
error(f"Error creating wallet: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
error(f"Error creating wallet: {str(e)}")
|
||||
raise
|
||||
@@ -125,23 +126,24 @@ class WalletDaemonClient:
|
||||
def list_wallets(self) -> List[WalletInfo]:
|
||||
"""List all wallets in the daemon"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
response = client.get("/v1/wallets")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
wallets = []
|
||||
for wallet_data in data.get("wallets", []):
|
||||
wallets.append(WalletInfo(
|
||||
wallet_id=wallet_data["wallet_id"],
|
||||
public_key=wallet_data["public_key"],
|
||||
address=wallet_data.get("address"),
|
||||
created_at=wallet_data.get("created_at"),
|
||||
metadata=wallet_data.get("metadata")
|
||||
))
|
||||
return wallets
|
||||
else:
|
||||
error(f"Failed to list wallets: {response.text}")
|
||||
raise Exception(f"HTTP {response.status_code}: {response.text}")
|
||||
client = self._get_http_client()
|
||||
data = client.get("/v1/wallets")
|
||||
wallets = []
|
||||
# Handle both "wallets" and "items" keys for compatibility
|
||||
wallet_list = data.get("wallets", data.get("items", []))
|
||||
for wallet_data in wallet_list:
|
||||
wallets.append(WalletInfo(
|
||||
wallet_id=wallet_data.get("wallet_id", wallet_data.get("wallet_name", "")),
|
||||
chain_id=wallet_data.get("chain_id", "default"),
|
||||
public_key=wallet_data.get("public_key", ""),
|
||||
address=wallet_data.get("address", ""),
|
||||
created_at=wallet_data.get("created_at", ""),
|
||||
metadata=wallet_data.get("metadata", {})
|
||||
))
|
||||
return wallets
|
||||
except NetworkError as e:
|
||||
error(f"Failed to list daemon wallets: {str(e)}")
|
||||
raise
|
||||
except Exception as e:
|
||||
error(f"Error listing wallets: {str(e)}")
|
||||
raise
|
||||
@@ -149,47 +151,41 @@ class WalletDaemonClient:
|
||||
def get_wallet_info(self, wallet_id: str) -> Optional[WalletInfo]:
|
||||
"""Get information about a specific wallet"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
response = client.get(f"/v1/wallets/{wallet_id}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return WalletInfo(
|
||||
wallet_id=data["wallet_id"],
|
||||
public_key=data["public_key"],
|
||||
address=data.get("address"),
|
||||
created_at=data.get("created_at"),
|
||||
metadata=data.get("metadata")
|
||||
)
|
||||
elif response.status_code == 404:
|
||||
return None
|
||||
else:
|
||||
error(f"Failed to get wallet info: {response.text}")
|
||||
raise Exception(f"HTTP {response.status_code}: {response.text}")
|
||||
client = self._get_http_client()
|
||||
data = client.get(f"/v1/wallets/{wallet_id}")
|
||||
return WalletInfo(
|
||||
wallet_id=data["wallet_id"],
|
||||
chain_id=data.get("chain_id", "default"),
|
||||
public_key=data["public_key"],
|
||||
address=data.get("address"),
|
||||
created_at=data.get("created_at"),
|
||||
metadata=data.get("metadata")
|
||||
)
|
||||
except NetworkError as e:
|
||||
error(f"Failed to get wallet info: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
error(f"Error getting wallet info: {str(e)}")
|
||||
raise
|
||||
return None
|
||||
|
||||
def get_wallet_balance(self, wallet_id: str) -> Optional[WalletBalance]:
|
||||
"""Get wallet balance from daemon"""
|
||||
try:
|
||||
with self._get_http_client() as client:
|
||||
response = client.get(f"/v1/wallets/{wallet_id}/balance")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return WalletBalance(
|
||||
wallet_id=wallet_id,
|
||||
balance=data["balance"],
|
||||
address=data.get("address"),
|
||||
last_updated=data.get("last_updated")
|
||||
)
|
||||
elif response.status_code == 404:
|
||||
return None
|
||||
else:
|
||||
error(f"Failed to get wallet balance: {response.text}")
|
||||
raise Exception(f"HTTP {response.status_code}: {response.text}")
|
||||
client = self._get_http_client()
|
||||
data = client.get(f"/v1/wallets/{wallet_id}/balance")
|
||||
return WalletBalance(
|
||||
wallet_id=wallet_id,
|
||||
chain_id=data.get("chain_id", "default"),
|
||||
balance=data["balance"],
|
||||
address=data.get("address"),
|
||||
last_updated=data.get("last_updated")
|
||||
)
|
||||
except NetworkError as e:
|
||||
error(f"Failed to get wallet balance: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
error(f"Error getting wallet balance: {str(e)}")
|
||||
raise
|
||||
return None
|
||||
|
||||
def sign_message(self, wallet_id: str, password: str, message: bytes) -> str:
|
||||
"""Sign a message with wallet private key"""
|
||||
@@ -349,6 +345,31 @@ class WalletDaemonClient:
|
||||
error(f"Error creating chain: {str(e)}")
|
||||
raise
|
||||
|
||||
def create_wallet(self, wallet_id: str, password: str, metadata: Optional[Dict[str, Any]] = None) -> WalletInfo:
|
||||
"""Create a new wallet in the daemon"""
|
||||
try:
|
||||
client = self._get_http_client()
|
||||
payload = {
|
||||
"wallet_id": wallet_id,
|
||||
"password": password,
|
||||
"metadata": metadata or {}
|
||||
}
|
||||
|
||||
data = client.post("/v1/wallets", json=payload)
|
||||
return WalletInfo(
|
||||
wallet_id=data["wallet_id"],
|
||||
public_key=data["public_key"],
|
||||
address=data.get("address"),
|
||||
created_at=data.get("created_at"),
|
||||
metadata=data.get("metadata")
|
||||
)
|
||||
except NetworkError as e:
|
||||
error(f"Failed to create wallet: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
error(f"Error creating wallet: {str(e)}")
|
||||
raise
|
||||
|
||||
def create_wallet_in_chain(self, chain_id: str, wallet_id: str, password: str,
|
||||
metadata: Optional[Dict[str, Any]] = None) -> WalletInfo:
|
||||
"""Create a wallet in a specific chain"""
|
||||
|
||||
Reference in New Issue
Block a user