```
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:
@@ -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)"""
|
||||
|
||||
|
||||
134
apps/coordinator-api/src/app/services/bitcoin_wallet.py
Normal file
134
apps/coordinator-api/src/app/services/bitcoin_wallet.py
Normal 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))
|
||||
Reference in New Issue
Block a user