feat: migrate coordinator-api routers to use centralized aitbc package utilities
Some checks failed
Security Scanning / security-scan (push) Waiting to run
API Endpoint Tests / test-api-endpoints (push) Successful in 57s
CLI Tests / test-cli (push) Failing after 6s
Integration Tests / test-service-integration (push) Successful in 40s
Python Tests / test-python (push) Failing after 37s

- Replace logging.getLogger with aitbc.get_logger across all router files
- Migrate HTTP client usage from httpx to aitbc.AITBCHTTPClient in blockchain.py
- Add NetworkError exception handling from aitbc package
- Update blockchain status and sync status endpoints to use AITBCHTTPClient
- Add from __future__ import annotations to admin.py, client.py, governance.py
- Consistent logger initialization across 20+ router
This commit is contained in:
aitbc
2026-04-24 23:33:11 +02:00
parent 858790b89e
commit 3103debecf
38 changed files with 414 additions and 475 deletions

View File

@@ -1,13 +1,20 @@
"""Cross-chain trading commands for AITBC CLI"""
import click
import httpx
import json
from typing import Optional
from tabulate import tabulate
from ..config import get_config
from ..utils import success, error, output
# Import shared modules
from aitbc.aitbc_logging import get_logger
from aitbc.http_client import AITBCHTTPClient
from aitbc.exceptions import NetworkError
# Initialize logger
logger = get_logger(__name__)
@click.group()
def cross_chain():
@@ -27,7 +34,7 @@ def rates(ctx, from_chain: Optional[str], to_chain: Optional[str],
config = ctx.obj['config']
try:
with httpx.Client() as client:
with AITBCHTTPClient() as client:
# Get rates from cross-chain exchange
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/rates",
@@ -96,7 +103,7 @@ def swap(ctx, from_chain: str, to_chain: str, from_token: str, to_token: str,
if not min_amount:
# Get rate first
try:
with httpx.Client() as client:
with AITBCHTTPClient() as client:
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/rates",
timeout=10
@@ -123,26 +130,19 @@ def swap(ctx, from_chain: str, to_chain: str, from_token: str, to_token: str,
}
try:
with httpx.Client() as client:
response = client.post(
f"http://localhost:8001/api/v1/cross-chain/swap",
json=swap_data,
timeout=30
)
if response.status_code == 200:
swap_result = response.json()
success("Cross-chain swap created successfully!")
output({
"Swap ID": swap_result.get('swap_id'),
"From Chain": swap_result.get('from_chain'),
"To Chain": swap_result.get('to_chain'),
"Amount": swap_result.get('amount'),
"Expected Amount": swap_result.get('expected_amount'),
"Rate": swap_result.get('rate'),
"Total Fees": swap_result.get('total_fees'),
"Status": swap_result.get('status')
}, ctx.obj['output_format'])
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1/cross-chain", timeout=30)
swap_result = http_client.post("/swap", json=swap_data)
success("Cross-chain swap created successfully!")
output({
"Swap ID": swap_result.get('swap_id'),
"From Chain": swap_result.get('from_chain'),
"To Chain": swap_result.get('to_chain'),
"Amount": swap_result.get('amount'),
"Expected Amount": swap_result.get('expected_amount'),
"Rate": swap_result.get('rate'),
"Total Fees": swap_result.get('total_fees'),
"Status": swap_result.get('status')
}, ctx.obj['output_format'])
# Show swap ID for tracking
success(f"Track swap with: aitbc cross-chain status {swap_result.get('swap_id')}")
@@ -160,34 +160,44 @@ def swap(ctx, from_chain: str, to_chain: str, from_token: str, to_token: str,
def status(ctx, swap_id: str):
"""Check cross-chain swap status"""
try:
with httpx.Client() as client:
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/swap/{swap_id}",
timeout=10
)
if response.status_code == 200:
swap_data = response.json()
success(f"Swap Status: {swap_data.get('status', 'unknown')}")
# Display swap details
details = {
"Swap ID": swap_data.get('swap_id'),
"From Chain": swap_data.get('from_chain'),
"To Chain": swap_data.get('to_chain'),
"From Token": swap_data.get('from_token'),
"To Token": swap_data.get('to_token'),
"Amount": swap_data.get('amount'),
"Expected Amount": swap_data.get('expected_amount'),
"Actual Amount": swap_data.get('actual_amount'),
"Status": swap_data.get('status'),
"Created At": swap_data.get('created_at'),
"Completed At": swap_data.get('completed_at'),
"Bridge Fee": swap_data.get('bridge_fee'),
"From Tx Hash": swap_data.get('from_tx_hash'),
"To Tx Hash": swap_data.get('to_tx_hash')
}
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
swap_data = http_client.get(f"/cross-chain/swap/{swap_id}")
success(f"Swap Status: {swap_data.get('status', 'unknown')}")
# Display swap details
details = {
"Swap ID": swap_data.get('swap_id'),
"From Chain": swap_data.get('from_chain'),
"To Chain": swap_data.get('to_chain'),
"From Token": swap_data.get('from_token'),
"To Token": swap_data.get('to_token'),
"Amount": swap_data.get('amount'),
"Expected Amount": swap_data.get('expected_amount'),
"Actual Amount": swap_data.get('actual_amount'),
"Status": swap_data.get('status'),
"Created At": swap_data.get('created_at'),
"Completed At": swap_data.get('completed_at'),
"Bridge Fee": swap_data.get('bridge_fee'),
"From Tx Hash": swap_data.get('from_tx_hash'),
"To Tx Hash": swap_data.get('to_tx_hash')
}
output(details, ctx.obj['output_format'])
# Show additional status info
if swap_data.get('status') == 'completed':
success("✅ Swap completed successfully!")
elif swap_data.get('status') == 'failed':
error("❌ Swap failed")
if swap_data.get('error_message'):
error(f"Error: {swap_data['error_message']}")
elif swap_data.get('status') == 'pending':
success("⏳ Swap is pending...")
elif swap_data.get('status') == 'executing':
success("🔄 Swap is executing...")
elif swap_data.get('status') == 'refunded':
success("💰 Swap was refunded")
except NetworkError as e:
output(details, ctx.obj['output_format'])
# Show additional status info
@@ -223,19 +233,12 @@ def swaps(ctx, user_address: Optional[str], status: Optional[str], limit: int):
params['status'] = status
try:
with httpx.Client() as client:
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/swaps",
params=params,
timeout=10
)
if response.status_code == 200:
swaps_data = response.json()
swaps = swaps_data.get('swaps', [])
if swaps:
success(f"Found {len(swaps)} cross-chain swaps:")
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
swaps_data = http_client.get("/cross-chain/swaps", params=params)
swaps = swaps_data.get('swaps', [])
if swaps:
success(f"Found {len(swaps)} cross-chain swaps:")
# Create table
swap_table = []
@@ -295,23 +298,16 @@ def bridge(ctx, source_chain: str, target_chain: str, token: str,
}
try:
with httpx.Client() as client:
response = client.post(
f"http://localhost:8001/api/v1/cross-chain/bridge",
json=bridge_data,
timeout=30
)
if response.status_code == 200:
bridge_result = response.json()
success("Cross-chain bridge created successfully!")
output({
"Bridge ID": bridge_result.get('bridge_id'),
"Source Chain": bridge_result.get('source_chain'),
"Target Chain": bridge_result.get('target_chain'),
"Token": bridge_result.get('token'),
"Amount": bridge_result.get('amount'),
"Bridge Fee": bridge_result.get('bridge_fee'),
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=30)
bridge_result = http_client.post("/cross-chain/bridge", json=bridge_data)
success("Cross-chain bridge created successfully!")
output({
"Bridge ID": bridge_result.get('bridge_id'),
"Source Chain": bridge_result.get('source_chain'),
"Target Chain": bridge_result.get('target_chain'),
"Token": bridge_result.get('token'),
"Amount": bridge_result.get('amount'),
"Bridge Fee": bridge_result.get('bridge_fee'),
"Status": bridge_result.get('status')
}, ctx.obj['output_format'])
@@ -331,15 +327,9 @@ def bridge(ctx, source_chain: str, target_chain: str, token: str,
def bridge_status(ctx, bridge_id: str):
"""Check cross-chain bridge status"""
try:
with httpx.Client() as client:
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/bridge/{bridge_id}",
timeout=10
)
if response.status_code == 200:
bridge_data = response.json()
success(f"Bridge Status: {bridge_data.get('status', 'unknown')}")
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
bridge_data = http_client.get(f"/cross-chain/bridge/{bridge_id}")
success(f"Bridge Status: {bridge_data.get('status', 'unknown')}")
# Display bridge details
details = {
@@ -383,7 +373,7 @@ def bridge_status(ctx, bridge_id: str):
def pools(ctx):
"""Show cross-chain liquidity pools"""
try:
with httpx.Client() as client:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/pools",
timeout=10
@@ -426,7 +416,7 @@ def pools(ctx):
def stats(ctx):
"""Show cross-chain trading statistics"""
try:
with httpx.Client() as client:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
response = client.get(
f"http://localhost:8001/api/v1/cross-chain/stats",
timeout=10

View File

@@ -1,7 +1,6 @@
"""Exchange integration commands for AITBC CLI"""
import click
import httpx
import json
import os
from pathlib import Path
@@ -10,6 +9,14 @@ from datetime import datetime
from ..utils import output, error, success, warning
from ..config import get_config
# Import shared modules
from aitbc.aitbc_logging import get_logger
from aitbc.http_client import AITBCHTTPClient
from aitbc.exceptions import NetworkError
# Initialize logger
logger = get_logger(__name__)
@click.group()
def exchange():
@@ -368,20 +375,14 @@ def status(ctx, exchange_name: str):
config = ctx.obj['config']
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/v1/exchange/rates",
timeout=10
)
if response.status_code == 200:
rates_data = response.json()
success("Current exchange rates:")
output(rates_data, ctx.obj['output_format'])
else:
error(f"Failed to get exchange rates: {response.status_code}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
rates_data = http_client.get(f"/exchange/rates")
success("Current exchange rates:")
output(rates_data, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.command()
@@ -410,55 +411,36 @@ def create_payment(ctx, aitbc_amount: Optional[float], btc_amount: Optional[floa
# Get exchange rates to calculate missing amount
try:
with httpx.Client() as client:
rates_response = client.get(
f"{config.coordinator_url}/v1/exchange/rates",
timeout=10
)
if rates_response.status_code != 200:
error("Failed to get exchange rates")
return
rates = rates_response.json()
btc_to_aitbc = rates.get('btc_to_aitbc', 100000)
# Calculate missing amount
if aitbc_amount and not btc_amount:
btc_amount = aitbc_amount / btc_to_aitbc
elif btc_amount and not aitbc_amount:
aitbc_amount = btc_amount * btc_to_aitbc
# Prepare payment request
payment_data = {
"user_id": user_id or "cli_user",
"aitbc_amount": aitbc_amount,
"btc_amount": btc_amount
}
if notes:
payment_data["notes"] = notes
# Create payment
response = client.post(
f"{config.coordinator_url}/v1/exchange/create-payment",
json=payment_data,
timeout=10
)
if response.status_code == 200:
payment = response.json()
success(f"Payment created: {payment.get('payment_id')}")
success(f"Send {btc_amount:.8f} BTC to: {payment.get('payment_address')}")
success(f"Expires at: {payment.get('expires_at')}")
output(payment, ctx.obj['output_format'])
else:
error(f"Failed to create payment: {response.status_code}")
if response.text:
error(f"Error details: {response.text}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
rates = http_client.get("/exchange/rates")
btc_to_aitbc = rates.get('btc_to_aitbc', 100000)
# Calculate missing amount
if aitbc_amount and not btc_amount:
btc_amount = aitbc_amount / btc_to_aitbc
elif btc_amount and not aitbc_amount:
aitbc_amount = btc_amount * btc_to_aitbc
# Prepare payment request
payment_data = {
"user_id": user_id or "cli_user",
"aitbc_amount": aitbc_amount,
"btc_amount": btc_amount
}
if notes:
payment_data["notes"] = notes
# Create payment
payment = http_client.post("/exchange/create-payment", json=payment_data)
success(f"Payment created: {payment.get('payment_id')}")
success(f"Send {btc_amount:.8f} BTC to: {payment.get('payment_address')}")
success(f"Expires at: {payment.get('expires_at')}")
output(payment, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.command()
@@ -469,31 +451,25 @@ def payment_status(ctx, payment_id: str):
config = ctx.obj['config']
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/v1/exchange/payment-status/{payment_id}",
timeout=10
)
if response.status_code == 200:
status_data = response.json()
status = status_data.get('status', 'unknown')
if status == 'confirmed':
success(f"Payment {payment_id} is confirmed!")
success(f"AITBC amount: {status_data.get('aitbc_amount', 0)}")
elif status == 'pending':
success(f"Payment {payment_id} is pending confirmation")
elif status == 'expired':
error(f"Payment {payment_id} has expired")
else:
success(f"Payment {payment_id} status: {status}")
output(status_data, ctx.obj['output_format'])
else:
error(f"Failed to get payment status: {response.status_code}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
status_data = http_client.get(f"/exchange/payment-status/{payment_id}")
status = status_data.get('status', 'unknown')
if status == 'confirmed':
success(f"Payment {payment_id} is confirmed!")
success(f"AITBC amount: {status_data.get('aitbc_amount', 0)}")
elif status == 'pending':
success(f"Payment {payment_id} is pending confirmation")
elif status == 'expired':
error(f"Payment {payment_id} has expired")
else:
success(f"Payment {payment_id} status: {status}")
output(status_data, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.command()
@@ -503,20 +479,14 @@ def market_stats(ctx):
config = ctx.obj['config']
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/v1/exchange/market-stats",
timeout=10
)
if response.status_code == 200:
stats = response.json()
success("Exchange market statistics:")
output(stats, ctx.obj['output_format'])
else:
error(f"Failed to get market stats: {response.status_code}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
stats = http_client.get("/exchange/market-stats")
success("Exchange market statistics:")
output(stats, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.group()
@@ -532,20 +502,14 @@ def balance(ctx):
config = ctx.obj['config']
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/exchange/wallet/balance",
timeout=10
)
if response.status_code == 200:
balance_data = response.json()
success("Bitcoin wallet balance:")
output(balance_data, ctx.obj['output_format'])
else:
error(f"Failed to get wallet balance: {response.status_code}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
balance_data = http_client.get("/exchange/wallet/balance")
success("Bitcoin wallet balance:")
output(balance_data, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@wallet.command()
@@ -555,20 +519,14 @@ def info(ctx):
config = ctx.obj['config']
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/exchange/wallet/info",
timeout=10
)
if response.status_code == 200:
wallet_info = response.json()
success("Bitcoin wallet information:")
output(wallet_info, ctx.obj['output_format'])
else:
error(f"Failed to get wallet info: {response.status_code}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
wallet_info = http_client.get("/exchange/wallet/info")
success("Bitcoin wallet information:")
output(wallet_info, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.command()
@@ -591,24 +549,15 @@ def register(ctx, name: str, api_key: str, api_secret: Optional[str], sandbox: b
exchange_data["api_secret"] = api_secret
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url}/v1/exchange/register",
json=exchange_data,
timeout=10
)
if response.status_code == 200:
result = response.json()
success(f"Exchange '{name}' registered successfully!")
success(f"Exchange ID: {result.get('exchange_id')}")
output(result, ctx.obj['output_format'])
else:
error(f"Failed to register exchange: {response.status_code}")
if response.text:
error(f"Error details: {response.text}")
except Exception as e:
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
result = http_client.post("/exchange/register", json=exchange_data)
success(f"Exchange '{name}' registered successfully!")
success(f"Exchange ID: {result.get('exchange_id')}")
output(result, ctx.obj['output_format'])
except NetworkError as e:
error(f"Network error: {e}")
except Exception as e:
error(f"Error: {e}")
@exchange.command()
@@ -640,8 +589,8 @@ def create_pair(ctx, pair: str, base_asset: str, quote_asset: str,
pair_data["max_order_size"] = max_order_size
try:
with httpx.Client() as client:
response = client.post(
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
response = http_client.post(
f"{config.coordinator_url}/v1/exchange/create-pair",
json=pair_data,
timeout=10
@@ -679,8 +628,8 @@ def start_trading(ctx, pair: str, exchange: Optional[str], order_type: tuple):
trading_data["exchange"] = exchange
try:
with httpx.Client() as client:
response = client.post(
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
response = http_client.post(
f"{config.coordinator_url}/v1/exchange/start-trading",
json=trading_data,
timeout=10
@@ -717,8 +666,8 @@ def list_pairs(ctx, pair: Optional[str], exchange: Optional[str], status: Option
params["status"] = status
try:
with httpx.Client() as client:
response = client.get(
http_client = AITBCHTTPClient(base_url="http://localhost:8001/api/v1", timeout=10)
response = http_client.get(
f"{config.coordinator_url}/v1/exchange/pairs",
params=params,
timeout=10

View File

@@ -17,6 +17,14 @@ from ..utils.island_credentials import (
get_island_id, get_island_name
)
# Import shared modules
from aitbc.aitbc_logging import get_logger
from aitbc.http_client import AITBCHTTPClient
from aitbc.exceptions import NetworkError
# Initialize logger
logger = get_logger(__name__)
# Supported trading pairs
SUPPORTED_PAIRS = ['AIT/BTC', 'AIT/ETH']

View File

@@ -1,7 +1,6 @@
"""Wallet commands for AITBC CLI"""
import click
import httpx
import json
import os
import shutil
@@ -12,6 +11,15 @@ from datetime import datetime, timedelta
from ..utils import output, error, success
import getpass
# Import shared modules
from aitbc.aitbc_logging import get_logger
from aitbc.http_client import AITBCHTTPClient
from aitbc.exceptions import NetworkError
from aitbc.constants import KEYSTORE_DIR
# Initialize logger
logger = get_logger(__name__)
def encrypt_value(value: str, password: str) -> str:
"""Simple encryption for wallet data (placeholder)"""
@@ -523,16 +531,13 @@ def balance(ctx):
# Try to get balance from blockchain if available
if config:
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url.replace('/api', '')}/rpc/balance/{wallet_data['address']}",
timeout=5,
)
if response.status_code == 200:
blockchain_balance = response.json().get("balance", 0)
output(
{
http_client = AITBCHTTPClient(
base_url=config.coordinator_url.replace('/api', ''),
timeout=5
)
blockchain_balance = http_client.get(f"/rpc/balance/{wallet_data['address']}")
output(
{
"wallet": wallet_name,
"address": wallet_data["address"],
"local_balance": wallet_data.get("balance", 0),
@@ -737,27 +742,25 @@ def send(ctx, to_address: str, amount: float, description: Optional[str]):
# Try to send via blockchain
if config:
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url.replace('/api', '')}/rpc/transactions",
json={
"from": wallet_data["address"],
"to": to_address,
"amount": amount,
"description": description or "",
},
headers={"X-Api-Key": getattr(config, "api_key", "") or ""},
)
http_client = AITBCHTTPClient(
base_url=config.coordinator_url.replace('/api', ''),
timeout=30,
headers={"X-Api-Key": getattr(config, "api_key", "") or ""}
)
result = http_client.post(
"/rpc/transactions",
json={
"from": wallet_data["address"],
"to": to_address,
"amount": amount,
"description": description or "",
}
)
if response.status_code == 201:
tx = response.json()
# Update local wallet
transaction = {
"type": "send",
"amount": -amount,
"to_address": to_address,
"tx_hash": tx.get("hash"),
"description": description or "",
if result:
success(f"Transaction sent: {result.get('transaction_hash', 'N/A')}")
output(result, ctx.obj.get("output_format", "table"))
return
"timestamp": datetime.now().isoformat(),
}