- Remove standalone explorer-web app (README, HTML, package files) - Add /web endpoint to blockchain-explorer for web interface access - Update .gitignore to exclude application backup archives (*.tar.gz, *.zip) - Add backup documentation files to .gitignore (BACKUP_INDEX.md, README.md) - Consolidate explorer functionality into main blockchain-explorer application
615 lines
22 KiB
Python
Executable File
615 lines
22 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Cross-Chain Trading Extension for Multi-Chain Exchange
|
|
Adds cross-chain trading, bridging, and swap functionality
|
|
"""
|
|
|
|
import sqlite3
|
|
import json
|
|
import asyncio
|
|
import httpx
|
|
from datetime import datetime, timedelta
|
|
from typing import Dict, List, Optional, Any
|
|
from fastapi import FastAPI, HTTPException, Query, BackgroundTasks
|
|
from pydantic import BaseModel, Field
|
|
import uuid
|
|
import hashlib
|
|
|
|
# Import the base multi-chain exchange
|
|
from multichain_exchange_api import app, get_db_connection, SUPPORTED_CHAINS
|
|
|
|
# Cross-Chain Models
|
|
class CrossChainSwapRequest(BaseModel):
|
|
from_chain: str = Field(..., regex="^(ait-devnet|ait-testnet)$")
|
|
to_chain: str = Field(..., regex="^(ait-devnet|ait-testnet)$")
|
|
from_token: str = Field(..., min_length=1)
|
|
to_token: str = Field(..., min_length=1)
|
|
amount: float = Field(..., gt=0)
|
|
min_amount: float = Field(..., gt=0)
|
|
user_address: str = Field(..., min_length=1)
|
|
slippage_tolerance: float = Field(default=0.01, ge=0, le=0.1)
|
|
|
|
class BridgeRequest(BaseModel):
|
|
source_chain: str = Field(..., regex="^(ait-devnet|ait-testnet)$")
|
|
target_chain: str = Field(..., regex="^(ait-devnet|ait-testnet)$")
|
|
token: str = Field(..., min_length=1)
|
|
amount: float = Field(..., gt=0)
|
|
recipient_address: str = Field(..., min_length=1)
|
|
|
|
class CrossChainOrder(BaseModel):
|
|
order_type: str = Field(..., regex="^(BUY|SELL)$")
|
|
amount: float = Field(..., gt=0)
|
|
price: float = Field(..., gt=0)
|
|
chain_id: str = Field(..., regex="^(ait-devnet|ait-testnet)$")
|
|
cross_chain: bool = Field(default=True)
|
|
target_chain: Optional[str] = None
|
|
user_address: str = Field(..., min_length=1)
|
|
|
|
# Cross-Chain Database Functions
|
|
def init_cross_chain_tables():
|
|
"""Initialize cross-chain trading tables"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Cross-chain swaps table
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS cross_chain_swaps (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
swap_id TEXT UNIQUE NOT NULL,
|
|
from_chain TEXT NOT NULL,
|
|
to_chain TEXT NOT NULL,
|
|
from_token TEXT NOT NULL,
|
|
to_token TEXT NOT NULL,
|
|
amount REAL NOT NULL,
|
|
min_amount REAL NOT NULL,
|
|
expected_amount REAL NOT NULL,
|
|
actual_amount REAL DEFAULT NULL,
|
|
user_address TEXT NOT NULL,
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'executing', 'completed', 'failed', 'refunded')),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
completed_at TIMESTAMP NULL,
|
|
from_tx_hash TEXT NULL,
|
|
to_tx_hash TEXT NULL,
|
|
bridge_fee REAL DEFAULT 0,
|
|
slippage REAL DEFAULT 0,
|
|
error_message TEXT NULL
|
|
)
|
|
''')
|
|
|
|
# Bridge transactions table
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS bridge_transactions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
bridge_id TEXT UNIQUE NOT NULL,
|
|
source_chain TEXT NOT NULL,
|
|
target_chain TEXT NOT NULL,
|
|
token TEXT NOT NULL,
|
|
amount REAL NOT NULL,
|
|
recipient_address TEXT NOT NULL,
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'locked', 'transferred', 'completed', 'failed')),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
completed_at TIMESTAMP NULL,
|
|
source_tx_hash TEXT NULL,
|
|
target_tx_hash TEXT NULL,
|
|
bridge_fee REAL DEFAULT 0,
|
|
lock_address TEXT NULL,
|
|
error_message TEXT NULL
|
|
)
|
|
''')
|
|
|
|
# Cross-chain liquidity pools
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS cross_chain_pools (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
pool_id TEXT UNIQUE NOT NULL,
|
|
token_a TEXT NOT NULL,
|
|
token_b TEXT NOT NULL,
|
|
chain_a TEXT NOT NULL,
|
|
chain_b TEXT NOT NULL,
|
|
reserve_a REAL DEFAULT 0,
|
|
reserve_b REAL DEFAULT 0,
|
|
total_liquidity REAL DEFAULT 0,
|
|
apr REAL DEFAULT 0,
|
|
fee_rate REAL DEFAULT 0.003,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
# Create indexes
|
|
cursor.execute('CREATE INDEX IF NOT EXISTS idx_swaps_user ON cross_chain_swaps(user_address)')
|
|
cursor.execute('CREATE INDEX IF NOT EXISTS idx_swaps_status ON cross_chain_swaps(status)')
|
|
cursor.execute('CREATE INDEX IF NOT EXISTS idx_swaps_chains ON cross_chain_swaps(from_chain, to_chain)')
|
|
cursor.execute('CREATE INDEX IF NOT EXISTS idx_bridge_status ON bridge_transactions(status)')
|
|
cursor.execute('CREATE INDEX IF NOT EXISTS idx_bridge_chains ON bridge_transactions(source_chain, target_chain)')
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
return True
|
|
except Exception as e:
|
|
print(f"Cross-chain database initialization error: {e}")
|
|
return False
|
|
|
|
# Cross-Chain Liquidity Management
|
|
def get_cross_chain_rate(from_chain: str, to_chain: str, from_token: str, to_token: str) -> Optional[float]:
|
|
"""Get cross-chain exchange rate"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Check if there's a liquidity pool for this pair
|
|
cursor.execute('''
|
|
SELECT reserve_a, reserve_b FROM cross_chain_pools
|
|
WHERE ((chain_a = ? AND chain_b = ? AND token_a = ? AND token_b = ?) OR
|
|
(chain_a = ? AND chain_b = ? AND token_a = ? AND token_b = ?))
|
|
''', (from_chain, to_chain, from_token, to_token, to_chain, from_chain, to_token, from_token))
|
|
|
|
pool = cursor.fetchone()
|
|
if pool:
|
|
reserve_a, reserve_b = pool
|
|
if from_chain == SUPPORTED_CHAINS[from_chain] and reserve_a > 0 and reserve_b > 0:
|
|
return reserve_b / reserve_a
|
|
|
|
# Fallback to 1:1 rate for same tokens
|
|
if from_token == to_token:
|
|
return 1.0
|
|
|
|
# Get rates from individual chains
|
|
rate_a = get_chain_token_price(from_chain, from_token)
|
|
rate_b = get_chain_token_price(to_chain, to_token)
|
|
|
|
if rate_a and rate_b:
|
|
return rate_b / rate_a
|
|
|
|
return None
|
|
except Exception as e:
|
|
print(f"Rate calculation error: {e}")
|
|
return None
|
|
|
|
def get_chain_token_price(chain_id: str, token: str) -> Optional[float]:
|
|
"""Get token price on specific chain"""
|
|
try:
|
|
chain_info = SUPPORTED_CHAINS.get(chain_id)
|
|
if not chain_info or chain_info["status"] != "active":
|
|
return None
|
|
|
|
# Mock price for now - in production, this would call the chain's price oracle
|
|
if token == "AITBC":
|
|
return 1.0
|
|
elif token == "USDC":
|
|
return 1.0
|
|
else:
|
|
return 0.5 # Default fallback
|
|
except:
|
|
return None
|
|
|
|
# Cross-Chain Swap Functions
|
|
async def execute_cross_chain_swap(swap_request: CrossChainSwapRequest) -> Dict[str, Any]:
|
|
"""Execute cross-chain swap"""
|
|
try:
|
|
# Validate chains
|
|
if swap_request.from_chain == swap_request.to_chain:
|
|
raise HTTPException(status_code=400, detail="Cannot swap within same chain")
|
|
|
|
if swap_request.from_chain not in SUPPORTED_CHAINS or swap_request.to_chain not in SUPPORTED_CHAINS:
|
|
raise HTTPException(status_code=400, detail="Unsupported chain")
|
|
|
|
# Get exchange rate
|
|
rate = get_cross_chain_rate(swap_request.from_chain, swap_request.to_chain,
|
|
swap_request.from_token, swap_request.to_token)
|
|
if not rate:
|
|
raise HTTPException(status_code=400, detail="No exchange rate available")
|
|
|
|
# Calculate expected amount
|
|
expected_amount = swap_request.amount * rate * (1 - 0.003) # 0.3% fee
|
|
|
|
# Check slippage
|
|
if expected_amount < swap_request.min_amount:
|
|
raise HTTPException(status_code=400, detail="Insufficient output due to slippage")
|
|
|
|
# Create swap record
|
|
swap_id = str(uuid.uuid4())
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('''
|
|
INSERT INTO cross_chain_swaps
|
|
(swap_id, from_chain, to_chain, from_token, to_token, amount, min_amount, expected_amount, user_address)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
''', (swap_id, swap_request.from_chain, swap_request.to_chain, swap_request.from_token,
|
|
swap_request.to_token, swap_request.amount, swap_request.min_amount, expected_amount,
|
|
swap_request.user_address))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
# Execute swap in background
|
|
asyncio.create_task(process_cross_chain_swap(swap_id))
|
|
|
|
return {
|
|
"success": True,
|
|
"swap_id": swap_id,
|
|
"from_chain": swap_request.from_chain,
|
|
"to_chain": swap_request.to_chain,
|
|
"amount": swap_request.amount,
|
|
"expected_amount": expected_amount,
|
|
"rate": rate,
|
|
"status": "pending"
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Swap execution failed: {str(e)}")
|
|
|
|
async def process_cross_chain_swap(swap_id: str):
|
|
"""Process cross-chain swap in background"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Get swap details
|
|
cursor.execute("SELECT * FROM cross_chain_swaps WHERE swap_id = ?", (swap_id,))
|
|
swap = cursor.fetchone()
|
|
|
|
if not swap:
|
|
return
|
|
|
|
# Update status to executing
|
|
cursor.execute("UPDATE cross_chain_swaps SET status = 'executing' WHERE swap_id = ?", (swap_id,))
|
|
conn.commit()
|
|
|
|
# Step 1: Lock funds on source chain
|
|
from_tx_hash = await lock_funds_on_chain(swap["from_chain"], swap["from_token"],
|
|
swap["amount"], swap["user_address"])
|
|
|
|
if not from_tx_hash:
|
|
cursor.execute('''
|
|
UPDATE cross_chain_swaps SET status = 'failed', error_message = ?
|
|
WHERE swap_id = ?
|
|
''', ("Failed to lock source funds", swap_id))
|
|
conn.commit()
|
|
return
|
|
|
|
# Step 2: Transfer to target chain
|
|
to_tx_hash = await transfer_to_target_chain(swap["to_chain"], swap["to_token"],
|
|
swap["expected_amount"], swap["user_address"])
|
|
|
|
if not to_tx_hash:
|
|
# Refund source chain
|
|
await refund_source_chain(swap["from_chain"], from_tx_hash, swap["user_address"])
|
|
cursor.execute('''
|
|
UPDATE cross_chain_swaps SET status = 'refunded', error_message = ?,
|
|
from_tx_hash = ? WHERE swap_id = ?
|
|
''', ("Target transfer failed, refunded", from_tx_hash, swap_id))
|
|
conn.commit()
|
|
return
|
|
|
|
# Step 3: Complete swap
|
|
actual_amount = await verify_target_transfer(swap["to_chain"], to_tx_hash)
|
|
|
|
cursor.execute('''
|
|
UPDATE cross_chain_swaps SET status = 'completed', actual_amount = ?,
|
|
from_tx_hash = ?, to_tx_hash = ?, completed_at = CURRENT_TIMESTAMP
|
|
WHERE swap_id = ?
|
|
''', (actual_amount, from_tx_hash, to_tx_hash, swap_id))
|
|
conn.commit()
|
|
|
|
conn.close()
|
|
|
|
except Exception as e:
|
|
print(f"Cross-chain swap processing error: {e}")
|
|
|
|
async def lock_funds_on_chain(chain_id: str, token: str, amount: float, user_address: str) -> Optional[str]:
|
|
"""Lock funds on source chain"""
|
|
try:
|
|
chain_info = SUPPORTED_CHAINS[chain_id]
|
|
if chain_info["status"] != "active":
|
|
return None
|
|
|
|
# Mock implementation - in production, this would call the chain's lock function
|
|
lock_tx_hash = f"lock_{uuid.uuid4().hex[:8]}"
|
|
|
|
# Simulate blockchain call
|
|
await asyncio.sleep(1)
|
|
|
|
return lock_tx_hash
|
|
except:
|
|
return None
|
|
|
|
async def transfer_to_target_chain(chain_id: str, token: str, amount: float, user_address: str) -> Optional[str]:
|
|
"""Transfer tokens to target chain"""
|
|
try:
|
|
chain_info = SUPPORTED_CHAINS[chain_id]
|
|
if chain_info["status"] != "active":
|
|
return None
|
|
|
|
# Mock implementation - in production, this would call the chain's mint/transfer function
|
|
transfer_tx_hash = f"transfer_{uuid.uuid4().hex[:8]}"
|
|
|
|
# Simulate blockchain call
|
|
await asyncio.sleep(2)
|
|
|
|
return transfer_tx_hash
|
|
except:
|
|
return None
|
|
|
|
async def refund_source_chain(chain_id: str, lock_tx_hash: str, user_address: str) -> bool:
|
|
"""Refund locked funds on source chain"""
|
|
try:
|
|
chain_info = SUPPORTED_CHAINS[chain_id]
|
|
if chain_info["status"] != "active":
|
|
return False
|
|
|
|
# Mock implementation - in production, this would call the chain's refund function
|
|
await asyncio.sleep(1)
|
|
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
async def verify_target_transfer(chain_id: str, tx_hash: str) -> Optional[float]:
|
|
"""Verify transfer on target chain"""
|
|
try:
|
|
chain_info = SUPPORTED_CHAINS[chain_id]
|
|
if chain_info["status"] != "active":
|
|
return None
|
|
|
|
# Mock implementation - in production, this would verify the actual transaction
|
|
await asyncio.sleep(1)
|
|
|
|
return 100.0 # Mock amount
|
|
except:
|
|
return None
|
|
|
|
# Cross-Chain API Endpoints
|
|
@app.post("/api/v1/cross-chain/swap")
|
|
async def create_cross_chain_swap(swap_request: CrossChainSwapRequest, background_tasks: BackgroundTasks):
|
|
"""Create cross-chain swap"""
|
|
return await execute_cross_chain_swap(swap_request)
|
|
|
|
@app.get("/api/v1/cross-chain/swap/{swap_id}")
|
|
async def get_cross_chain_swap(swap_id: str):
|
|
"""Get cross-chain swap details"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT * FROM cross_chain_swaps WHERE swap_id = ?", (swap_id,))
|
|
swap = cursor.fetchone()
|
|
|
|
conn.close()
|
|
|
|
if not swap:
|
|
raise HTTPException(status_code=404, detail="Swap not found")
|
|
|
|
return dict(swap)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get swap: {str(e)}")
|
|
|
|
@app.get("/api/v1/cross-chain/swaps")
|
|
async def get_cross_chain_swaps(user_address: Optional[str] = None, status: Optional[str] = None):
|
|
"""Get cross-chain swaps"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
query = "SELECT * FROM cross_chain_swaps"
|
|
params = []
|
|
|
|
if user_address:
|
|
query += " WHERE user_address = ?"
|
|
params.append(user_address)
|
|
|
|
if status:
|
|
if user_address:
|
|
query += " AND status = ?"
|
|
else:
|
|
query += " WHERE status = ?"
|
|
params.append(status)
|
|
|
|
query += " ORDER BY created_at DESC"
|
|
|
|
cursor.execute(query, params)
|
|
swaps = [dict(row) for row in cursor.fetchall()]
|
|
|
|
conn.close()
|
|
|
|
return {
|
|
"swaps": swaps,
|
|
"total_swaps": len(swaps)
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get swaps: {str(e)}")
|
|
|
|
@app.post("/api/v1/cross-chain/bridge")
|
|
async def create_bridge_transaction(bridge_request: BridgeRequest, background_tasks: BackgroundTasks):
|
|
"""Create bridge transaction"""
|
|
try:
|
|
if bridge_request.source_chain == bridge_request.target_chain:
|
|
raise HTTPException(status_code=400, detail="Cannot bridge to same chain")
|
|
|
|
bridge_id = str(uuid.uuid4())
|
|
bridge_fee = bridge_request.amount * 0.001 # 0.1% bridge fee
|
|
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('''
|
|
INSERT INTO bridge_transactions
|
|
(bridge_id, source_chain, target_chain, token, amount, recipient_address, bridge_fee)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
''', (bridge_id, bridge_request.source_chain, bridge_request.target_chain,
|
|
bridge_request.token, bridge_request.amount, bridge_request.recipient_address, bridge_fee))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
# Process bridge in background
|
|
asyncio.create_task(process_bridge_transaction(bridge_id))
|
|
|
|
return {
|
|
"success": True,
|
|
"bridge_id": bridge_id,
|
|
"source_chain": bridge_request.source_chain,
|
|
"target_chain": bridge_request.target_chain,
|
|
"amount": bridge_request.amount,
|
|
"bridge_fee": bridge_fee,
|
|
"status": "pending"
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Bridge creation failed: {str(e)}")
|
|
|
|
async def process_bridge_transaction(bridge_id: str):
|
|
"""Process bridge transaction in background"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT * FROM bridge_transactions WHERE bridge_id = ?", (bridge_id,))
|
|
bridge = cursor.fetchone()
|
|
|
|
if not bridge:
|
|
return
|
|
|
|
# Update status
|
|
cursor.execute("UPDATE bridge_transactions SET status = 'locked' WHERE bridge_id = ?", (bridge_id,))
|
|
conn.commit()
|
|
|
|
# Lock on source chain
|
|
source_tx_hash = await lock_funds_on_chain(bridge["source_chain"], bridge["token"],
|
|
bridge["amount"], bridge["recipient_address"])
|
|
|
|
if source_tx_hash:
|
|
# Transfer to target chain
|
|
target_tx_hash = await transfer_to_target_chain(bridge["target_chain"], bridge["token"],
|
|
bridge["amount"], bridge["recipient_address"])
|
|
|
|
if target_tx_hash:
|
|
cursor.execute('''
|
|
UPDATE bridge_transactions SET status = 'completed',
|
|
source_tx_hash = ?, target_tx_hash = ?, completed_at = CURRENT_TIMESTAMP
|
|
WHERE bridge_id = ?
|
|
''', (source_tx_hash, target_tx_hash, bridge_id))
|
|
else:
|
|
cursor.execute('''
|
|
UPDATE bridge_transactions SET status = 'failed', error_message = ?
|
|
WHERE bridge_id = ?
|
|
''', ("Target transfer failed", bridge_id))
|
|
else:
|
|
cursor.execute('''
|
|
UPDATE bridge_transactions SET status = 'failed', error_message = ?
|
|
WHERE bridge_id = ?
|
|
''', ("Source lock failed", bridge_id))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
except Exception as e:
|
|
print(f"Bridge processing error: {e}")
|
|
|
|
@app.get("/api/v1/cross-chain/bridge/{bridge_id}")
|
|
async def get_bridge_transaction(bridge_id: str):
|
|
"""Get bridge transaction details"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT * FROM bridge_transactions WHERE bridge_id = ?", (bridge_id,))
|
|
bridge = cursor.fetchone()
|
|
|
|
conn.close()
|
|
|
|
if not bridge:
|
|
raise HTTPException(status_code=404, detail="Bridge transaction not found")
|
|
|
|
return dict(bridge)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get bridge: {str(e)}")
|
|
|
|
@app.get("/api/v1/cross-chain/rates")
|
|
async def get_cross_chain_rates():
|
|
"""Get cross-chain exchange rates"""
|
|
rates = {}
|
|
|
|
for from_chain in SUPPORTED_CHAINS:
|
|
for to_chain in SUPPORTED_CHAINS:
|
|
if from_chain != to_chain:
|
|
pair_key = f"{from_chain}-{to_chain}"
|
|
rate = get_cross_chain_rate(from_chain, to_chain, "AITBC", "AITBC")
|
|
if rate:
|
|
rates[pair_key] = rate
|
|
|
|
return {
|
|
"rates": rates,
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
@app.get("/api/v1/cross-chain/pools")
|
|
async def get_cross_chain_pools():
|
|
"""Get cross-chain liquidity pools"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT * FROM cross_chain_pools ORDER BY total_liquidity DESC")
|
|
pools = [dict(row) for row in cursor.fetchall()]
|
|
|
|
conn.close()
|
|
|
|
return {
|
|
"pools": pools,
|
|
"total_pools": len(pools)
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get pools: {str(e)}")
|
|
|
|
@app.get("/api/v1/cross-chain/stats")
|
|
async def get_cross_chain_stats():
|
|
"""Get cross-chain trading statistics"""
|
|
try:
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Swap stats
|
|
cursor.execute('''
|
|
SELECT status, COUNT(*) as count, SUM(amount) as volume
|
|
FROM cross_chain_swaps
|
|
GROUP BY status
|
|
''')
|
|
swap_stats = [dict(row) for row in cursor.fetchall()]
|
|
|
|
# Bridge stats
|
|
cursor.execute('''
|
|
SELECT status, COUNT(*) as count, SUM(amount) as volume
|
|
FROM bridge_transactions
|
|
GROUP BY status
|
|
''')
|
|
bridge_stats = [dict(row) for row in cursor.fetchall()]
|
|
|
|
# Total volume
|
|
cursor.execute("SELECT SUM(amount) FROM cross_chain_swaps WHERE status = 'completed'")
|
|
total_volume = cursor.fetchone()[0] or 0
|
|
|
|
conn.close()
|
|
|
|
return {
|
|
"swap_stats": swap_stats,
|
|
"bridge_stats": bridge_stats,
|
|
"total_volume": total_volume,
|
|
"supported_chains": list(SUPPORTED_CHAINS.keys()),
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to get stats: {str(e)}")
|
|
|
|
# Initialize cross-chain tables
|
|
if __name__ == "__main__":
|
|
init_cross_chain_tables()
|
|
print("✅ Cross-chain trading extensions initialized")
|