feat: add market stats endpoint, wallet integration, and browser wallet link

- Update devnet genesis timestamp to 1767000206
- Add market statistics endpoint with 24h volume, price change, and payment counts
- Add wallet balance and info API endpoints in exchange router
- Remove unused SessionDep dependencies from exchange endpoints
- Integrate real AITBC wallet extension connection in trade-exchange UI
- Add market data fetching with API fallback for price and volume display
- Add cache-busting query
This commit is contained in:
oib
2025-12-29 18:04:04 +01:00
parent b3fd0ea05c
commit 2cb2fbbeda
63 changed files with 4329 additions and 54 deletions

View File

@@ -4,15 +4,13 @@ Bitcoin Exchange Router for AITBC
from typing import Dict, Any
from fastapi import APIRouter, HTTPException, BackgroundTasks
from sqlmodel import Session
import uuid
import time
import json
import os
from ..deps import SessionDep
from ..domain import Wallet
from ..schemas import ExchangePaymentRequest, ExchangePaymentResponse
from ..services.bitcoin_wallet import get_wallet_balance, get_wallet_info
router = APIRouter(tags=["exchange"])
@@ -31,7 +29,6 @@ BITCOIN_CONFIG = {
@router.post("/exchange/create-payment", response_model=ExchangePaymentResponse)
async def create_payment(
request: ExchangePaymentRequest,
session: SessionDep,
background_tasks: BackgroundTasks
) -> Dict[str, Any]:
"""Create a new Bitcoin payment request"""
@@ -88,8 +85,7 @@ async def get_payment_status(payment_id: str) -> Dict[str, Any]:
@router.post("/exchange/confirm-payment/{payment_id}")
async def confirm_payment(
payment_id: str,
tx_hash: str,
session: SessionDep
tx_hash: str
) -> Dict[str, Any]:
"""Confirm payment (webhook from payment processor)"""
@@ -132,6 +128,48 @@ async def get_exchange_rates() -> Dict[str, float]:
'fee_percent': 0.5
}
@router.get("/exchange/market-stats")
async def get_market_stats() -> Dict[str, Any]:
"""Get market statistics"""
# Calculate 24h volume from payments
current_time = int(time.time())
yesterday_time = current_time - 24 * 60 * 60 # 24 hours ago
daily_volume = 0
for payment in payments.values():
if payment['status'] == 'confirmed' and payment.get('confirmed_at', 0) > yesterday_time:
daily_volume += payment['aitbc_amount']
# Calculate price change (simulated)
base_price = 1.0 / BITCOIN_CONFIG['exchange_rate']
price_change_percent = 5.2 # Simulated +5.2%
return {
'price': base_price,
'price_change_24h': price_change_percent,
'daily_volume': daily_volume,
'daily_volume_btc': daily_volume / BITCOIN_CONFIG['exchange_rate'],
'total_payments': len([p for p in payments.values() if p['status'] == 'confirmed']),
'pending_payments': len([p for p in payments.values() if p['status'] == 'pending'])
}
@router.get("/exchange/wallet/balance")
async def get_wallet_balance_api() -> Dict[str, Any]:
"""Get Bitcoin wallet balance"""
try:
return get_wallet_balance()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/exchange/wallet/info")
async def get_wallet_info_api() -> Dict[str, Any]:
"""Get comprehensive wallet information"""
try:
return get_wallet_info()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
async def monitor_payment(payment_id: str):
"""Monitor payment for confirmation (background task)"""

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python3
"""
Bitcoin Wallet Integration for AITBC Exchange
Uses RPC to connect to Bitcoin Core (or alternative like Block.io)
"""
import os
import json
import requests
from typing import Dict, Optional
# Bitcoin wallet configuration
WALLET_CONFIG = {
# For development, we'll use testnet
'testnet': True,
'rpc_url': 'http://127.0.0.1:18332', # Testnet RPC port
'rpc_user': 'aitbc_rpc',
'rpc_password': 'REDACTED_RPC_PASSWORD',
'wallet_name': 'aitbc_exchange',
'fallback_address': 'tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh' # Testnet address
}
class BitcoinWallet:
def __init__(self):
self.config = WALLET_CONFIG
self.session = requests.Session()
self.session.auth = (self.config['rpc_user'], self.config['rpc_password'])
def get_balance(self) -> float:
"""Get the current Bitcoin balance"""
try:
result = self._rpc_call('getbalance', ["*", 0, False])
if result.get('error') is not None:
print(f"Bitcoin RPC error: {result['error']}")
return 0.0
return result.get('result', 0.0)
except Exception as e:
print(f"Failed to get balance: {e}")
return 0.0
def get_new_address(self) -> str:
"""Generate a new Bitcoin address for deposits"""
try:
result = self._rpc_call('getnewaddress', ["", "bech32"])
if result.get('error') is not None:
print(f"Bitcoin RPC error: {result['error']}")
return self.config['fallback_address']
return result.get('result', self.config['fallback_address'])
except Exception as e:
print(f"Failed to get new address: {e}")
return self.config['fallback_address']
def list_transactions(self, count: int = 10) -> list:
"""List recent transactions"""
try:
result = self._rpc_call('listtransactions', ["*", count, 0, True])
if result.get('error') is not None:
print(f"Bitcoin RPC error: {result['error']}")
return []
return result.get('result', [])
except Exception as e:
print(f"Failed to list transactions: {e}")
return []
def _rpc_call(self, method: str, params: list = None) -> Dict:
"""Make an RPC call to Bitcoin Core"""
if params is None:
params = []
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": method,
"params": params
}
try:
response = self.session.post(
self.config['rpc_url'],
json=payload,
timeout=30
)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"RPC call failed: {e}")
return {"error": str(e)}
# Create a wallet instance
wallet = BitcoinWallet()
# API endpoints for wallet integration
def get_wallet_balance() -> Dict[str, any]:
"""Get wallet balance for API"""
balance = wallet.get_balance()
return {
"balance": balance,
"address": wallet.get_new_address(),
"testnet": wallet.config['testnet']
}
def get_wallet_info() -> Dict[str, any]:
"""Get comprehensive wallet information"""
try:
wallet = BitcoinWallet()
# Test connection to Bitcoin Core
blockchain_info = wallet._rpc_call('getblockchaininfo')
is_connected = blockchain_info.get('error') is None and blockchain_info.get('result') is not None
return {
"balance": wallet.get_balance(),
"address": wallet.get_new_address(),
"transactions": wallet.list_transactions(10),
"testnet": wallet.config['testnet'],
"wallet_type": "Bitcoin Core (Real)" if is_connected else "Bitcoin Core (Disconnected)",
"connected": is_connected,
"blocks": blockchain_info.get('result', {}).get('blocks', 0) if is_connected else 0
}
except Exception as e:
print(f"Error getting wallet info: {e}")
return {
"balance": 0.0,
"address": "tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"transactions": [],
"testnet": True,
"wallet_type": "Bitcoin Core (Error)",
"connected": False,
"blocks": 0
}
if __name__ == "__main__":
# Test the wallet integration
info = get_wallet_info()
print(json.dumps(info, indent=2))