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

Binary file not shown.

View File

@@ -19,5 +19,5 @@
"fee_per_byte": 1,
"mint_per_unit": 1000
},
"timestamp": 1766828620
"timestamp": 1767000206
}

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))

View File

@@ -0,0 +1,316 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Exchange - Admin Dashboard</title>
<link rel="stylesheet" href="/assets/css/aitbc.css">
<script src="/assets/js/axios.min.js"></script>
<script src="/assets/js/lucide.js"></script>
<style>
.stat-card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
}
.stat-card:hover {
transform: translateY(-2px);
}
.stat-value {
font-size: 2.5rem;
font-weight: bold;
color: #f97316;
}
.stat-label {
color: #6b7280;
margin-top: 8px;
}
.wallet-balance {
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
padding: 30px;
border-radius: 16px;
margin-bottom: 30px;
}
.wallet-address {
font-family: monospace;
background: rgba(255, 255, 255, 0.2);
padding: 8px 12px;
border-radius: 6px;
display: inline-block;
margin-top: 10px;
}
.payment-list {
max-height: 400px;
overflow-y: auto;
}
.payment-item {
border-left: 4px solid #e5e7eb;
padding: 12px;
margin-bottom: 8px;
background: #f9fafb;
border-radius: 0 8px 8px 0;
}
.payment-item.pending {
border-left-color: #f59e0b;
}
.payment-item.confirmed {
border-left-color: #10b981;
}
.payment-item.expired {
border-left-color: #ef4444;
}
.refresh-btn {
position: fixed;
bottom: 30px;
right: 30px;
width: 60px;
height: 60px;
background: #f97316;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4);
cursor: pointer;
transition: all 0.3s;
}
.refresh-btn:hover {
transform: scale(1.1);
}
.refresh-btn.spinning {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
</head>
<body class="bg-gray-50">
<header class="bg-white shadow-sm border-b">
<div class="bg-yellow-100 text-yellow-800 text-center py-2 text-sm">
⚠️ DEMO MODE - This is simulated data for demonstration purposes
</div>
<div class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<i data-lucide="trending-up" class="w-8 h-8 text-orange-600"></i>
<h1 class="text-2xl font-bold">Exchange Admin Dashboard</h1>
</div>
<div class="flex items-center space-x-4">
<span class="text-sm text-gray-600">Bank Director Portal</span>
<button onclick="logout()" class="text-gray-500 hover:text-gray-700">
<i data-lucide="log-out" class="w-5 h-5"></i>
</button>
</div>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<!-- Bitcoin Wallet Balance -->
<section class="wallet-balance">
<h2 class="text-3xl font-bold mb-4">Bitcoin Wallet</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<div class="text-sm opacity-90">Current Balance</div>
<div class="text-4xl font-bold" id="btcBalance">0.00000000 BTC</div>
</div>
<div>
<div class="text-sm opacity-90 mb-2">Wallet Address</div>
<div class="wallet-address text-sm" id="walletAddress">tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh</div>
</div>
</div>
</section>
<!-- Statistics Grid -->
<section class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="stat-card">
<i data-lucide="coins" class="w-8 h-8 text-orange-600 mb-2"></i>
<div class="stat-value" id="totalAitbcSold">0</div>
<div class="stat-label">Total AITBC Sold</div>
</div>
<div class="stat-card">
<i data-lucide="bitcoin" class="w-8 h-8 text-orange-600 mb-2"></i>
<div class="stat-value" id="totalBtcReceived">0 BTC</div>
<div class="stat-label">Total BTC Received</div>
</div>
<div class="stat-card">
<i data-lucide="users" class="w-8 h-8 text-orange-600 mb-2"></i>
<div class="stat-value" id="totalUsers">0</div>
<div class="stat-label">Total Users</div>
</div>
<div class="stat-card">
<i data-lucide="clock" class="w-8 h-8 text-orange-600 mb-2"></i>
<div class="stat-value" id="pendingPayments">0</div>
<div class="stat-label">Pending Payments</div>
</div>
</section>
<!-- Available AITBC -->
<section class="bg-white rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-bold mb-4 flex items-center">
<i data-lucide="package" class="w-5 h-5 mr-2 text-orange-600"></i>
Available AITBC for Sale
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<div class="text-3xl font-bold text-green-600" id="availableAitbc">10,000,000</div>
<div class="text-sm text-gray-600 mt-1">AITBC tokens available</div>
</div>
<div>
<div class="text-2xl font-semibold text-gray-900" id="estimatedValue">100 BTC</div>
<div class="text-sm text-gray-600 mt-1">Estimated value at current rate</div>
</div>
</div>
</section>
<!-- Recent Payments -->
<section class="bg-white rounded-lg shadow p-6">
<h2 class="text-xl font-bold mb-4 flex items-center">
<i data-lucide="activity" class="w-5 h-5 mr-2 text-orange-600"></i>
Recent Payments
</h2>
<div class="payment-list" id="paymentsList">
<div class="text-gray-500 text-center py-8">Loading payments...</div>
</div>
</section>
</main>
<!-- Refresh Button -->
<div class="refresh-btn" onclick="refreshData()" id="refreshBtn">
<i data-lucide="refresh-cw" class="w-6 h-6"></i>
</div>
<script>
const API_BASE = window.location.origin + '/api';
let refreshInterval;
// Initialize
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
refreshData();
// Auto-refresh every 30 seconds
refreshInterval = setInterval(refreshData, 30000);
});
// Refresh all data
async function refreshData() {
const btn = document.getElementById('refreshBtn');
btn.classList.add('spinning');
try {
await Promise.all([
loadMarketStats(),
loadPayments(),
loadWalletBalance()
]);
} catch (error) {
console.error('Error refreshing data:', error);
} finally {
setTimeout(() => btn.classList.remove('spinning'), 500);
}
}
// Load market statistics
async function loadMarketStats() {
try {
const response = await axios.get(`${API_BASE}/exchange/market-stats`);
const stats = response.data;
document.getElementById('totalAitbcSold').textContent =
(stats.daily_volume || 0).toLocaleString();
document.getElementById('totalBtcReceived').textContent =
(stats.daily_volume_btc || 0).toFixed(8) + ' BTC';
document.getElementById('pendingPayments').textContent =
stats.pending_payments || 0;
// Update available AITBC (for demo, show a large number)
// In production, this would come from a token supply API
const availableAitbc = 10000000; // 10 million tokens
const estimatedValue = availableAitbc * (stats.price || 0.00001);
document.getElementById('availableAitbc').textContent =
availableAitbc.toLocaleString();
document.getElementById('estimatedValue').textContent =
estimatedValue.toFixed(2) + ' BTC';
// Add demo indicator for token supply
const supplyElement = document.getElementById('availableAitbc');
if (!supplyElement.innerHTML.includes('(DEMO)')) {
supplyElement.innerHTML += ' <span style="font-size: 0.5em; opacity: 0.7;">(DEMO)</span>';
}
} catch (error) {
console.error('Error loading market stats:', error);
}
}
// Load recent payments
async function loadPayments() {
try {
// Since there's no endpoint to list all payments, we'll show a message
document.getElementById('paymentsList').innerHTML =
'<div class="text-gray-500 text-center py-8">Payment history requires database implementation</div>';
} catch (error) {
console.error('Error loading payments:', error);
}
}
// Load wallet balance from API
async function loadWalletBalance() {
try {
const response = await axios.get(`${API_BASE}/exchange/wallet/info`);
const wallet = response.data;
document.getElementById('btcBalance').textContent =
wallet.balance.toFixed(8) + ' BTC';
document.getElementById('walletAddress').textContent =
wallet.address;
// Show wallet type
const balanceElement = document.getElementById('btcBalance');
if (wallet.testnet) {
balanceElement.innerHTML += ' <span style="font-size: 0.5em; opacity: 0.7;">(TESTNET)</span>';
}
// Update wallet info section
updateWalletInfo(wallet);
} catch (error) {
console.error('Error loading wallet balance:', error);
// Fallback to demo data
document.getElementById('btcBalance').textContent = '0.00000000 BTC';
document.getElementById('walletAddress').textContent = 'Wallet API unavailable';
}
}
// Update wallet information display
function updateWalletInfo(wallet) {
// Create or update wallet info display
let walletInfo = document.getElementById('walletInfoDisplay');
if (!walletInfo) {
walletInfo = document.createElement('div');
walletInfo.id = 'walletInfoDisplay';
walletInfo.className = 'mt-4 p-4 bg-gray-100 rounded-lg';
document.querySelector('.wallet-balance').appendChild(walletInfo);
}
walletInfo.innerHTML = `
<div class="text-sm">
<div class="mb-2"><strong>Wallet Type:</strong> ${wallet.wallet_type}</div>
<div class="mb-2"><strong>Network:</strong> ${wallet.testnet ? 'Testnet' : 'Mainnet'}</div>
<div><strong>Recent Transactions:</strong> ${wallet.transactions.length}</div>
</div>
`;
}
// Logout
function logout() {
window.location.href = '/Exchange/';
}
</script>
</body>
</html>

View File

@@ -4,10 +4,12 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Trade Exchange - Buy AITBC with Bitcoin</title>
<base href="/Exchange/">
<link rel="stylesheet" href="/assets/css/aitbc.css">
<script src="/assets/js/axios.min.js"></script>
<script src="/assets/js/lucide.js"></script>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<link rel="stylesheet" href="/assets/css/aitbc.css?v=20241229-1305">
<script src="/assets/js/axios.min.js?v=20241229-1305"></script>
<script src="/assets/js/lucide.js?v=20241229-1305"></script>
<style>
.gradient-bg {
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
@@ -91,7 +93,7 @@
</div>
<div class="flex items-center space-x-2">
<span class="text-gray-600 dark:text-gray-400">24h Volume:</span>
<span class="font-semibold text-gray-900 dark:text-white">1,234 AITBC</span>
<span class="font-semibold text-gray-900 dark:text-white" id="dailyVolume">Loading...</span>
</div>
</div>
<div class="text-sm text-gray-500 dark:text-gray-400">
@@ -479,56 +481,101 @@
// Connect Wallet
async function connectWallet() {
try {
// For demo, create a new wallet
const walletId = 'wallet-' + Math.random().toString(36).substr(2, 9);
const address = 'aitbc1' + walletId + 'x'.repeat(40 - walletId.length);
// Real wallet mode - connect to extension
if (typeof window.aitbcWallet === 'undefined') {
showToast('AITBC Wallet extension not found. Please install it first.', 'error');
return;
}
// Login or register user
const response = await axios.post(`${API_BASE}/users/login`, {
wallet_address: address
});
// Request connection to wallet extension
const response = await window.aitbcWallet.connect();
const user = response.data;
currentUser = user;
sessionToken = user.session_token;
walletAddress = address;
// Update UI
document.getElementById('aitbcAddress').textContent = address;
document.getElementById('userUsername').textContent = user.username;
document.getElementById('userId').textContent = user.user_id;
document.getElementById('userCreated').textContent = new Date(user.created_at).toLocaleDateString();
// Update navigation
document.getElementById('navConnectBtn').classList.add('hidden');
document.getElementById('navUserInfo').classList.remove('hidden');
document.getElementById('navUsername').textContent = user.username;
// Show trade form, hide connect prompt
document.getElementById('tradeConnectPrompt').classList.add('hidden');
document.getElementById('tradeForm').classList.remove('hidden');
// Show profile, hide login prompt
document.getElementById('notLoggedIn').classList.add('hidden');
document.getElementById('userProfile').classList.remove('hidden');
showToast('Wallet connected: ' + address.substring(0, 20) + '...');
// Load user balance
await loadUserBalance();
if (response.success) {
walletAddress = response.address;
// Login or register user with real wallet
const loginResponse = await axios.post(`${API_BASE}/users/login`, {
wallet_address: walletAddress
});
const user = loginResponse.data;
currentUser = user;
sessionToken = user.session_token;
// Update UI
updateWalletUI(user);
showToast(`Connected to AITBC Wallet: ${walletAddress.substring(0, 20)}...`);
// Load real balance
await loadUserBalance();
} else {
showToast('Failed to connect to wallet: ' + response.error, 'error');
}
} catch (error) {
console.error('Failed to connect wallet:', error);
showToast('Failed to connect wallet', 'error');
console.error('Error details:', JSON.stringify(error, null, 2));
const errorMsg = error.message || error.error || error.toString() || 'Unknown error';
showToast('Failed to connect wallet: ' + errorMsg, 'error');
}
}
// Update Wallet UI (helper function)
function updateWalletUI(user) {
document.getElementById('aitbcAddress').textContent = walletAddress;
document.getElementById('userUsername').textContent = user.username;
document.getElementById('userId').textContent = user.user_id;
document.getElementById('userCreated').textContent = new Date(user.created_at).toLocaleDateString();
// Update navigation
document.getElementById('navConnectBtn').classList.add('hidden');
document.getElementById('navUserInfo').classList.remove('hidden');
document.getElementById('navUsername').textContent = user.username;
// Show trade form, hide connect prompt
document.getElementById('tradeConnectPrompt').classList.add('hidden');
document.getElementById('tradeForm').classList.remove('hidden');
// Show profile, hide login prompt
document.getElementById('notLoggedIn').classList.add('hidden');
document.getElementById('userProfile').classList.remove('hidden');
}
// Update Prices
function updatePrices() {
// Simulate price updates
const variation = (Math.random() - 0.5) * 0.000001;
const newPrice = EXCHANGE_RATE + variation;
document.getElementById('aitbcBtcPrice').textContent = newPrice.toFixed(5);
document.getElementById('lastUpdated').textContent = 'Just now';
// Fetch real market data
fetchMarketData();
}
// Fetch real market data
async function fetchMarketData() {
try {
// Get market stats from API
const response = await axios.get(`${API_BASE}/exchange/market-stats`);
const stats = response.data;
// Update price
if (stats.price) {
document.getElementById('aitbcBtcPrice').textContent = stats.price.toFixed(5);
}
// Update volume
if (stats.daily_volume > 0) {
document.getElementById('dailyVolume').textContent =
stats.daily_volume.toLocaleString() + ' AITBC';
} else {
document.getElementById('dailyVolume').textContent = '0 AITBC';
}
// Update last updated time
document.getElementById('lastUpdated').textContent = new Date().toLocaleTimeString();
} catch (error) {
// Fallback if API is not available
const variation = (Math.random() - 0.5) * 0.000001;
const newPrice = EXCHANGE_RATE + variation;
document.getElementById('aitbcBtcPrice').textContent = newPrice.toFixed(5);
document.getElementById('dailyVolume').textContent = 'API unavailable';
document.getElementById('lastUpdated').textContent = new Date().toLocaleTimeString();
}
}
// Currency Conversion
@@ -552,7 +599,7 @@
btcInput.value = aitbcInput.value;
aitbcInput.value = temp;
updateAITBCFromBTC();
updateAITBCAmount();
}
// Create Payment Request
@@ -735,6 +782,9 @@
document.getElementById('aitbcBalance').textContent = aitbcBalance.toFixed(2);
} catch (error) {
console.error('Failed to load balance:', error);
// Set demo balance for testing
aitbcBalance = 1000;
document.getElementById('aitbcBalance').textContent = aitbcBalance.toFixed(2) + ' AITBC';
}
}
@@ -884,5 +934,10 @@
}, 3000);
}
</script>
<!-- Admin Access (hidden) -->
<div style="position: fixed; bottom: 10px; left: 10px; opacity: 0.3; font-size: 12px;">
<a href="/Exchange/admin/" style="color: #666;">Admin</a>
</div>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

74
deploy-exchange.sh Executable file
View File

@@ -0,0 +1,74 @@
#!/bin/bash
# Deploy AITBC Trade Exchange to the server
set -e
SERVER="root@10.1.223.93"
EXCHANGE_DIR="/root/aitbc/apps/trade-exchange"
echo "🚀 Deploying AITBC Trade Exchange"
echo "=================================="
echo "Server: $SERVER"
echo ""
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Test SSH connection
print_status "Testing SSH connection..."
ssh $SERVER "hostname && ip a show eth0 | grep inet"
# Copy updated files
print_status "Copying updated Exchange files..."
scp /home/oib/windsurf/aitbc/apps/trade-exchange/index.html $SERVER:$EXCHANGE_DIR/
scp /home/oib/windsurf/aitbc/apps/trade-exchange/server.py $SERVER:$EXCHANGE_DIR/
# Ensure assets are available
print_status "Ensuring assets directory exists..."
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets"
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/css"
ssh $SERVER "mkdir -p /var/www/aitbc.bubuit.net/assets/js"
# Copy assets if they don't exist
print_status "Copying assets if needed..."
if ! ssh $SERVER "test -f /var/www/aitbc.bubuit.net/assets/css/aitbc.css"; then
scp -r /home/oib/windsurf/aitbc/assets/* $SERVER:/var/www/aitbc.bubuit.net/assets/
fi
# Restart the exchange service
print_status "Restarting Trade Exchange service..."
ssh $SERVER "systemctl restart aitbc-exchange"
# Wait for service to start
print_status "Waiting for service to start..."
sleep 5
# Check service status
print_status "Checking service status..."
ssh $SERVER "systemctl status aitbc-exchange --no-pager -l | head -10"
# Test the endpoint
print_status "Testing Exchange endpoint..."
ssh $SERVER "curl -s http://127.0.0.1:3002/ | head -c 100"
echo ""
echo ""
print_status "✅ Exchange deployment complete!"
echo ""
echo "📋 URLs:"
echo " 🌐 IP: http://10.1.223.93/Exchange"
echo " 🔒 Domain: https://aitbc.bubuit.net/Exchange"
echo ""
echo "🔍 To check logs:"
echo " ssh $SERVER 'journalctl -u aitbc-exchange -f'"

77
extensions/README.md Normal file
View File

@@ -0,0 +1,77 @@
# AITBC Browser Wallet Extensions
This directory contains browser wallet extensions for AITBC, supporting both Chrome and Firefox browsers.
## Quick Start
### For Chrome/Brave/Edge Users
1. Navigate to `aitbc-wallet/` folder
2. Follow the installation instructions in `aitbc-wallet/README.md`
### For Firefox Users
1. Navigate to `aitbc-wallet-firefox/` folder
2. Follow the installation instructions in `aitbc-wallet-firefox/README.md`
## Using the Extensions
1. Install the appropriate extension for your browser
2. Navigate to the AITBC Trade Exchange: https://aitbc.bubuit.net/Exchange
3. Toggle from "Demo Mode" to "Real Mode"
4. Click "Connect AITBC Wallet"
5. Create a new account or import an existing one
6. Approve the connection request
## Features
- ✅ Cross-browser support (Chrome, Firefox, Edge, Brave)
- ✅ Secure local key storage
- ✅ dApp connection management
- ✅ Transaction signing
- ✅ Message signing
- ✅ Balance tracking
- ✅ Account management (create/import)
## Security Best Practices
1. **Never share your private key** - It's the key to your funds
2. **Keep backups** - Save your private key in a secure location
3. **Verify URLs** - Always check you're on aitbc.bubuit.net
4. **Use strong passwords** - Protect your browser with a strong password
5. **Keep updated** - Keep your browser and extension updated
## Development
Both extensions share most of their code:
- `injected.js` - Provides the wallet API to dApps
- `popup.html/js` - Wallet user interface
- `content.js` - Communicates between the extension and dApps
The main differences are:
- Chrome uses Manifest V3
- Firefox uses Manifest V2 (required for full functionality)
- Different background script architectures
## Architecture
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ dApp Page │────▶│ Content Script │────▶│ Background Script│
│ (Exchange UI) │ │ (bridge) │ │ (wallet logic) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
▲ │
│ ▼
┌──────────────────┐ ┌─────────────────┐
│ Injected Script │ │ Extension UI │
│ (window.aitbcWallet)│ │ (popup.html) │
└──────────────────┘ └─────────────────┘
```
## Support
For issues or questions:
1. Check the individual README files for your browser
2. Create an issue in the repository
3. Join our community discussions

View File

@@ -0,0 +1,133 @@
# AITBC Wallet Extension for Firefox
A Firefox browser extension that provides AITBC wallet functionality for interacting with the AITBC Trade Exchange and other dApps.
## Differences from Chrome Version
This version is specifically built for Firefox with the following differences:
- Uses Manifest V2 (Firefox still requires V2 for full functionality)
- Uses `browser_action` instead of `action` (V2 syntax)
- Uses `chrome.runtime.connect()` for background script communication
- Background script uses persistent connections via ports
## Installation
### Development Installation
1. Clone this repository
2. Open Firefox and navigate to `about:debugging`
3. Click "This Firefox" in the left sidebar
4. Click "Load Temporary Add-on..."
5. Select the `manifest.json` file from the `aitbc-wallet-firefox` folder
### Production Installation
The extension will be published to the Firefox Add-on Store (AMO). Installation instructions will be available once published.
## Usage
The usage is identical to the Chrome version:
1. Install the AITBC Wallet extension
2. Navigate to https://aitbc.bubuit.net/Exchange
3. Toggle the switch from "Demo Mode" to "Real Mode"
4. Click "Connect AITBC Wallet"
5. Approve the connection request in the popup
## Features
- **Wallet Management**: Create new accounts or import existing private keys
- **Secure Storage**: Private keys are stored locally in Firefox's storage
- **dApp Integration**: Connect to AITBC Trade Exchange and other supported dApps
- **Transaction Signing**: Sign transactions and messages securely
- **Balance Tracking**: View your AITBC token balance
## API Reference
The extension injects a `window.aitbcWallet` object into supported dApps with the following methods:
### `aitbcWallet.connect()`
Connect the dApp to the wallet.
```javascript
const response = await aitbcWallet.connect();
console.log(response.address); // User's AITBC address
```
### `aitbcWallet.getAccount()`
Get the current account address.
```javascript
const address = await aitbcWallet.getAccount();
```
### `aitbcWallet.getBalance(address)`
Get the AITBC balance for an address.
```javascript
const balance = await aitbcWallet.getBalance('aitbc1...');
console.log(balance.amount); // Balance in AITBC
```
### `aitbcWallet.sendTransaction(to, amount, data)`
Send AITBC tokens to another address.
```javascript
const tx = await aitbcWallet.sendTransaction('aitbc1...', 100);
console.log(tx.hash); // Transaction hash
```
### `aitbcWallet.signMessage(message)`
Sign a message with the private key.
```javascript
const signature = await aitbcWallet.signMessage('Hello AITBC!');
```
## Security Considerations
- Private keys are stored locally in Firefox's storage
- Always verify you're on the correct domain before connecting
- Never share your private key with anyone
- Keep your browser and extension updated
## Development
To modify the extension:
1. Make changes to the source files
2. Go to `about:debugging` in Firefox
3. Find "AITBC Wallet" and click "Reload"
4. Test your changes
## File Structure
```
aitbc-wallet-firefox/
├── manifest.json # Extension configuration (Manifest V2)
├── background.js # Background script for wallet operations
├── content.js # Content script for dApp communication
├── injected.js # Script injected into dApps
├── popup.html # Extension popup UI
├── popup.js # Popup logic
├── icons/ # Extension icons
└── README.md # This file
```
## Firefox-Specific Notes
- Firefox requires Manifest V2 for extensions that use content scripts in this manner
- The `browser_action` API is used instead of the newer `action` API
- Background scripts use port-based communication for better performance
- Storage APIs use `chrome.storage` which is compatible with Firefox
## Troubleshooting
### Extension not loading
- Ensure you're loading the `manifest.json` file, not the folder
- Check the Browser Console for error messages (`Ctrl+Shift+J`)
### dApp connection not working
- Refresh the dApp page after installing/updating the extension
- Check that the site is in the `matches` pattern in manifest.json
- Look for errors in the Browser Console
### Permission errors
- Firefox may show additional permission prompts
- Make sure to allow all requested permissions when installing

View File

@@ -0,0 +1,160 @@
// Background script for Firefox extension
// Handles messages from content scripts and manages wallet state
let currentPort = null;
// Listen for connection from content script
browser.runtime.onConnect.addListener(function(port) {
if (port.name === "aitbc-wallet") {
currentPort = port;
port.onMessage.addListener(function(request) {
handleWalletRequest(request, port);
});
port.onDisconnect.addListener(function() {
currentPort = null;
});
}
});
// Handle wallet requests from dApps
async function handleWalletRequest(request, port) {
const { method, params, id } = request;
try {
switch (method) {
case 'connect':
const response = await handleConnect(request);
port.postMessage({ id, result: response });
break;
case 'accounts':
const accounts = await getAccounts();
port.postMessage({ id, result: accounts });
break;
case 'getBalance':
const balance = await getBalance(params.address);
port.postMessage({ id, result: balance });
break;
case 'sendTransaction':
const txResult = await sendTransaction(params);
port.postMessage({ id, result: txResult });
break;
case 'signMessage':
const signature = await signMessage(params.message);
port.postMessage({ id, result: signature });
break;
default:
port.postMessage({ id, error: 'Unknown method: ' + method });
}
} catch (error) {
port.postMessage({ id, error: error.message });
}
}
// Handle connection request from dApp
async function handleConnect(request) {
// Get current account
const result = await browser.storage.local.get(['currentAccount']);
if (!result.currentAccount) {
throw new Error('No account found. Please create or import an account first.');
}
// For now, auto-approve connections from aitbc.bubuit.net
if (request.origin && (request.origin === 'https://aitbc.bubuit.net' || request.origin.includes('aitbc.bubuit.net'))) {
return {
success: true,
address: result.currentAccount.address
};
}
// For debugging, let's allow localhost too
if (request.origin && request.origin.includes('localhost')) {
return {
success: true,
address: result.currentAccount.address
};
}
// For other sites, would show a connection dialog
throw new Error(`Connection not allowed for origin: ${request.origin}`);
}
// Get all accounts
async function getAccounts() {
const result = await browser.storage.local.get(['accounts']);
const accounts = result.accounts || [];
return accounts.map(acc => acc.address);
}
// Get balance for an address
async function getBalance(address) {
// In a real implementation, this would query the blockchain
// For demo, return stored balance
const result = await browser.storage.local.get(['accounts']);
const accounts = result.accounts || [];
const account = accounts.find(acc => acc.address === address);
return {
address: address,
balance: account ? account.balance || 0 : 0,
symbol: 'AITBC'
};
}
// Send transaction
async function sendTransaction(params) {
// In a real implementation, this would create, sign, and broadcast a transaction
const { to, amount, data } = params;
// Get current account
const result = await browser.storage.local.get(['currentAccount']);
const account = result.currentAccount;
if (!account) {
throw new Error('No account connected');
}
// Confirm transaction
const confirmed = confirm(`Send ${amount} AITBC to ${to}?\n\nFrom: ${account.address}`);
if (!confirmed) {
throw new Error('Transaction rejected');
}
// Return mock transaction hash
return {
hash: '0x' + Array.from(crypto.getRandomValues(new Uint8Array(32)), b => b.toString(16).padStart(2, '0')).join(''),
status: 'pending'
};
}
// Sign message
async function signMessage(message) {
// Get current account
const result = await browser.storage.local.get(['currentAccount']);
const account = result.currentAccount;
if (!account) {
throw new Error('No account connected');
}
// Confirm signing
const confirmed = confirm(`Sign the following message?\n\n"${message}"\n\nAccount: ${account.address}`);
if (!confirmed) {
throw new Error('Message signing rejected');
}
// In a real implementation, this would sign with the private key
// For demo, return a mock signature
const encoder = new TextEncoder();
const data = encoder.encode(message + account.privateKey);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('');
}

View File

@@ -0,0 +1,42 @@
// Content script for AITBC Wallet Firefox extension
(function() {
// Inject the wallet API into the page
const script = document.createElement('script');
script.src = browser.runtime.getURL('injected.js');
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
// Create a port to background script
const port = browser.runtime.connect({ name: "aitbc-wallet" });
// Listen for messages from the injected script
window.addEventListener('message', function(event) {
// Only accept messages from our own window
if (event.source !== window) return;
if (event.data.type && event.data.type === 'AITBC_WALLET_REQUEST') {
// Add origin to the request
const requestWithOrigin = {
...event.data,
origin: window.location.origin
};
// Forward the request to the background script
port.postMessage(requestWithOrigin);
}
});
// Listen for responses from background script
port.onMessage.addListener(function(response) {
// Send the response back to the page
window.postMessage({
type: 'AITBC_WALLET_RESPONSE',
id: response.id,
response: {
result: response.result,
error: response.error
}
}, '*');
});
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

View File

@@ -0,0 +1,13 @@
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#ff9500;stop-opacity:1" />
<stop offset="100%" style="stop-color:#ff6611;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="128" height="128" rx="20" fill="url(#grad)"/>
<text x="64" y="45" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="white" text-anchor="middle">AITBC</text>
<path d="M30 60 L98 60 L90 75 L38 75 Z" fill="white" opacity="0.9"/>
<path d="M35 80 L93 80 L85 95 L43 95 Z" fill="white" opacity="0.7"/>
<circle cx="64" cy="105" r="8" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 729 B

View File

@@ -0,0 +1,113 @@
// Injected script that provides the AITBC wallet API to the dApp
(function() {
// Create the wallet API object
const aitbcWallet = {
// Check if wallet is available
isAvailable: function() {
return true;
},
// Connect to wallet
connect: async function() {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
// Send request to content script
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: 'connect'
}, '*');
// Listen for response
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
console.log('Wallet response received:', event.data);
if (event.data.response && event.data.response.error) {
reject(new Error(event.data.response.error));
} else if (event.data.response && event.data.response.result) {
resolve(event.data.response.result);
} else if (event.data.response) {
resolve(event.data.response);
} else {
reject(new Error('Invalid response from wallet'));
}
}
};
window.addEventListener('message', messageHandler);
// Timeout after 30 seconds
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Connection timeout'));
}, 30000);
});
},
// Get account address
getAccount: async function() {
const accounts = await this.request({ method: 'accounts' });
return accounts[0];
},
// Get balance
getBalance: async function(address) {
return this.request({ method: 'getBalance', params: { address } });
},
// Send transaction
sendTransaction: async function(to, amount, data = null) {
return this.request({
method: 'sendTransaction',
params: { to, amount, data }
});
},
// Sign message
signMessage: async function(message) {
return this.request({ method: 'signMessage', params: { message } });
},
// Generic request method
request: async function(payload) {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: payload.method,
params: payload.params || {}
}, '*');
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response && event.data.response.error) {
reject(new Error(event.data.response.error));
} else if (event.data.response) {
resolve(event.data.response);
} else {
reject(new Error('Invalid response from wallet'));
}
}
};
window.addEventListener('message', messageHandler);
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Request timeout'));
}, 30000);
});
}
};
// Inject the wallet API into the window object
window.aitbcWallet = aitbcWallet;
// Fire an event to notify the dApp that the wallet is ready
window.dispatchEvent(new Event('aitbcWalletReady'));
})();

View File

@@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Install AITBC Wallet for Firefox</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #ff9500 0%, #ff6611 100%);
color: white;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 20px;
}
.install-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 40px;
text-align: center;
max-width: 500px;
width: 100%;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}
.logo {
width: 80px;
height: 80px;
background: white;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-weight: bold;
color: #ff6611;
margin: 0 auto 30px;
}
h1 {
font-size: 2.5em;
margin-bottom: 20px;
}
.install-button {
display: inline-block;
background: white;
color: #ff6611;
padding: 16px 40px;
border-radius: 50px;
font-size: 18px;
font-weight: bold;
text-decoration: none;
transition: all 0.3s ease;
margin: 20px 0;
}
.install-button:hover {
transform: scale(1.05);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.install-steps {
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
padding: 20px;
margin: 20px 0;
text-align: left;
}
.install-steps h3 {
margin-top: 0;
margin-bottom: 15px;
text-align: center;
}
.install-steps ol {
margin: 0;
padding-left: 20px;
}
.install-steps li {
margin-bottom: 10px;
line-height: 1.5;
}
.install-steps code {
background: rgba(0, 0, 0, 0.3);
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
}
.features {
text-align: left;
margin: 30px 0;
}
.feature {
display: flex;
align-items: center;
margin: 10px 0;
}
.feature::before {
content: "✓";
display: inline-block;
width: 20px;
height: 20px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
text-align: center;
line-height: 20px;
margin-right: 10px;
flex-shrink: 0;
}
.note {
font-size: 14px;
opacity: 0.8;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="install-card">
<div class="logo">AITBC</div>
<h1>AITBC Wallet</h1>
<p>The secure wallet for AITBC tokens</p>
<a href="/assets/aitbc-wallet-firefox-v1.0.5.xpi" class="install-button" download>
Download XPI File
</a>
<div class="install-steps">
<h3>Installation Steps:</h3>
<ol>
<li>Download the XPI file using the button above</li>
<li>Open Firefox and type <code>about:debugging</code> in the address bar</li>
<li>Click "This Firefox" on the left</li>
<li>Click "Load Temporary Add-on..."</li>
<li>Select the downloaded XPI file</li>
</ol>
</div>
<div class="features">
<div class="feature">Secure local key storage</div>
<div class="feature">One-click dApp connection</div>
<div class="feature">Transaction signing</div>
<div class="feature">Balance tracking</div>
</div>
<p class="note">
After installation, click the AITBC icon in your toolbar to create or import a wallet.
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,46 @@
{
"manifest_version": 2,
"name": "AITBC Wallet",
"version": "1.0.0",
"description": "AITBC Browser Wallet for trading and managing AITBC tokens",
"permissions": [
"storage",
"activeTab"
],
"content_scripts": [
{
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"browser_action": {
"default_popup": "popup.html",
"default_title": "AITBC Wallet",
"default_icon": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
},
"web_accessible_resources": [
"injected.js"
],
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
}
}

View File

@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 350px;
padding: 20px;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.logo {
width: 40px;
height: 40px;
margin-right: 10px;
background: white;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #f97316;
}
.wallet-info {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.address {
font-family: monospace;
font-size: 12px;
word-break: break-all;
margin: 5px 0;
}
.balance {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.actions {
display: flex;
flex-direction: column;
gap: 10px;
}
button {
background: white;
color: #f97316;
border: none;
padding: 10px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.transactions {
margin-top: 20px;
max-height: 200px;
overflow-y: auto;
}
.tx-item {
background: rgba(255, 255, 255, 0.1);
padding: 8px;
border-radius: 4px;
margin-bottom: 5px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">AITBC</div>
<h1>Wallet</h1>
</div>
<div class="wallet-info">
<div>Account Address:</div>
<select id="accountSelector" style="width: 100%; margin: 5px 0; padding: 5px; background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.3); color: white; border-radius: 4px;">
<option value="">No accounts</option>
</select>
<div class="address" id="accountAddress">Not connected</div>
<div class="balance" id="balance">0 AITBC</div>
</div>
<div class="actions">
<button id="createAccountBtn">Create New Account</button>
<button id="importAccountBtn">Import Private Key</button>
<button id="sendTokensBtn">Send Tokens</button>
<button id="receiveTokensBtn">Receive Tokens</button>
<button id="viewOnExplorerBtn">View on Explorer</button>
</div>
<div class="transactions">
<h3>Recent Transactions</h3>
<div id="transactionList">
<div class="tx-item">No transactions yet</div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,315 @@
// Popup script for AITBC Wallet extension
let currentAccount = null;
let accounts = [];
// Load wallet data on popup open
document.addEventListener('DOMContentLoaded', async function() {
await loadWalletData();
updateUI();
// Check for pending connection request
const pending = await browser.storage.local.get(['pendingConnection']);
if (pending.pendingConnection) {
showConnectionDialog(pending.pendingConnection);
}
// Add event listeners
document.getElementById('createAccountBtn').addEventListener('click', createAccount);
document.getElementById('importAccountBtn').addEventListener('click', importAccount);
document.getElementById('sendTokensBtn').addEventListener('click', sendTokens);
document.getElementById('receiveTokensBtn').addEventListener('click', receiveTokens);
document.getElementById('viewOnExplorerBtn').addEventListener('click', viewOnExplorer);
document.getElementById('accountSelector').addEventListener('change', switchAccount);
});
// Load wallet data from storage
async function loadWalletData() {
const result = await browser.storage.local.get(['accounts', 'currentAccount']);
accounts = result.accounts || [];
currentAccount = result.currentAccount || null;
}
// Save wallet data to storage
async function saveWalletData() {
await browser.storage.local.set({
accounts: accounts,
currentAccount: currentAccount
});
}
// Update UI with current wallet state
function updateUI() {
const addressEl = document.getElementById('accountAddress');
const balanceEl = document.getElementById('balance');
const selectorEl = document.getElementById('accountSelector');
// Update account selector
selectorEl.innerHTML = '';
if (accounts.length === 0) {
const option = document.createElement('option');
option.value = '';
option.textContent = 'No accounts';
selectorEl.appendChild(option);
} else {
accounts.forEach((account, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = `Account ${index + 1} - ${account.address.substring(0, 20)}...`;
if (currentAccount && currentAccount.address === account.address) {
option.selected = true;
}
selectorEl.appendChild(option);
});
}
// Update current account display
if (currentAccount) {
addressEl.textContent = currentAccount.address;
balanceEl.textContent = `${currentAccount.balance || 0} AITBC`;
} else {
addressEl.textContent = 'Not connected';
balanceEl.textContent = '0 AITBC';
}
}
// Show connection dialog
function showConnectionDialog(pendingConnection) {
const dialog = document.createElement('div');
dialog.className = 'connection-dialog';
dialog.innerHTML = `
<div class="dialog-content">
<h3>Connection Request</h3>
<p>${pendingConnection.origin} wants to connect to your AITBC Wallet</p>
<p class="address">Address: ${pendingConnection.address}</p>
<div class="dialog-buttons">
<button id="approveConnection" class="approve-btn">Approve</button>
<button id="rejectConnection" class="reject-btn">Reject</button>
</div>
</div>
`;
// Add styles for the dialog
const style = document.createElement('style');
style.textContent = `
.connection-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.dialog-content {
background: white;
color: black;
padding: 20px;
border-radius: 8px;
max-width: 300px;
text-align: center;
}
.dialog-content h3 {
margin-top: 0;
}
.dialog-content .address {
font-family: monospace;
font-size: 12px;
word-break: break-all;
background: #f0f0f0;
padding: 5px;
border-radius: 4px;
margin: 10px 0;
}
.dialog-buttons {
display: flex;
gap: 10px;
justify-content: center;
margin-top: 20px;
}
.approve-btn {
background: #28a745;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.reject-btn {
background: #dc3545;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
`;
document.head.appendChild(style);
document.body.appendChild(dialog);
// Handle button clicks
document.getElementById('approveConnection').addEventListener('click', async () => {
await browser.storage.local.set({
connectionResponse: {
id: pendingConnection.id,
approved: true
}
});
await browser.storage.local.remove(['pendingConnection']);
dialog.remove();
style.remove();
});
document.getElementById('rejectConnection').addEventListener('click', async () => {
await browser.storage.local.set({
connectionResponse: {
id: pendingConnection.id,
approved: false
}
});
await browser.storage.local.remove(['pendingConnection']);
dialog.remove();
style.remove();
});
}
// Switch to a different account
async function switchAccount() {
const selectorEl = document.getElementById('accountSelector');
const selectedIndex = parseInt(selectorEl.value);
if (isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= accounts.length) {
return;
}
currentAccount = accounts[selectedIndex];
await saveWalletData();
updateUI();
}
// Create a new account
async function createAccount() {
// Generate a new private key and address
const privateKey = generatePrivateKey();
const address = await generateAddress(privateKey);
const newAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(newAccount);
currentAccount = newAccount;
await saveWalletData();
updateUI();
alert('New account created! Please save your private key securely.');
}
// Import account from private key
async function importAccount() {
const privateKey = prompt('Enter your private key:');
if (!privateKey) return;
try {
const address = await generateAddress(privateKey);
// Check if account already exists
const existing = accounts.find(a => a.address === address);
if (existing) {
currentAccount = existing;
} else {
currentAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(currentAccount);
}
await saveWalletData();
updateUI();
alert('Account imported successfully!');
} catch (error) {
alert('Invalid private key!');
}
}
// Send tokens
async function sendTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
const to = prompt('Send to address:');
const amount = prompt('Amount:');
if (!to || !amount) return;
// In a real implementation, this would create and sign a transaction
alert(`Would send ${amount} AITBC to ${to}`);
}
// Receive tokens
function receiveTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
alert(`Your receiving address:\n${currentAccount.address}`);
}
// View on explorer
function viewOnExplorer() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
browser.tabs.create({ url: `https://aitbc.bubuit.net/explorer/?address=${currentAccount.address}` });
}
// Generate a random private key (demo only)
function generatePrivateKey() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
// Generate address from private key (demo only)
async function generateAddress(privateKey) {
// In a real implementation, this would derive the address from the private key
// using the appropriate cryptographic algorithm
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(privateKey));
return 'aitbc1' + Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('').substring(0, 40);
}
// Listen for connection requests from dApps
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.method === 'connect') {
// Show connection dialog
const connected = confirm(`Allow this site to connect to your AITBC Wallet?`);
if (connected && currentAccount) {
sendResponse({
success: true,
address: currentAccount.address
});
} else {
sendResponse({
success: false,
error: 'User rejected connection'
});
}
}
return true; // Keep the message channel open for async response
});

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,133 @@
# AITBC Wallet Extension for Firefox
A Firefox browser extension that provides AITBC wallet functionality for interacting with the AITBC Trade Exchange and other dApps.
## Differences from Chrome Version
This version is specifically built for Firefox with the following differences:
- Uses Manifest V2 (Firefox still requires V2 for full functionality)
- Uses `browser_action` instead of `action` (V2 syntax)
- Uses `chrome.runtime.connect()` for background script communication
- Background script uses persistent connections via ports
## Installation
### Development Installation
1. Clone this repository
2. Open Firefox and navigate to `about:debugging`
3. Click "This Firefox" in the left sidebar
4. Click "Load Temporary Add-on..."
5. Select the `manifest.json` file from the `aitbc-wallet-firefox` folder
### Production Installation
The extension will be published to the Firefox Add-on Store (AMO). Installation instructions will be available once published.
## Usage
The usage is identical to the Chrome version:
1. Install the AITBC Wallet extension
2. Navigate to https://aitbc.bubuit.net/Exchange
3. Toggle the switch from "Demo Mode" to "Real Mode"
4. Click "Connect AITBC Wallet"
5. Approve the connection request in the popup
## Features
- **Wallet Management**: Create new accounts or import existing private keys
- **Secure Storage**: Private keys are stored locally in Firefox's storage
- **dApp Integration**: Connect to AITBC Trade Exchange and other supported dApps
- **Transaction Signing**: Sign transactions and messages securely
- **Balance Tracking**: View your AITBC token balance
## API Reference
The extension injects a `window.aitbcWallet` object into supported dApps with the following methods:
### `aitbcWallet.connect()`
Connect the dApp to the wallet.
```javascript
const response = await aitbcWallet.connect();
console.log(response.address); // User's AITBC address
```
### `aitbcWallet.getAccount()`
Get the current account address.
```javascript
const address = await aitbcWallet.getAccount();
```
### `aitbcWallet.getBalance(address)`
Get the AITBC balance for an address.
```javascript
const balance = await aitbcWallet.getBalance('aitbc1...');
console.log(balance.amount); // Balance in AITBC
```
### `aitbcWallet.sendTransaction(to, amount, data)`
Send AITBC tokens to another address.
```javascript
const tx = await aitbcWallet.sendTransaction('aitbc1...', 100);
console.log(tx.hash); // Transaction hash
```
### `aitbcWallet.signMessage(message)`
Sign a message with the private key.
```javascript
const signature = await aitbcWallet.signMessage('Hello AITBC!');
```
## Security Considerations
- Private keys are stored locally in Firefox's storage
- Always verify you're on the correct domain before connecting
- Never share your private key with anyone
- Keep your browser and extension updated
## Development
To modify the extension:
1. Make changes to the source files
2. Go to `about:debugging` in Firefox
3. Find "AITBC Wallet" and click "Reload"
4. Test your changes
## File Structure
```
aitbc-wallet-firefox/
├── manifest.json # Extension configuration (Manifest V2)
├── background.js # Background script for wallet operations
├── content.js # Content script for dApp communication
├── injected.js # Script injected into dApps
├── popup.html # Extension popup UI
├── popup.js # Popup logic
├── icons/ # Extension icons
└── README.md # This file
```
## Firefox-Specific Notes
- Firefox requires Manifest V2 for extensions that use content scripts in this manner
- The `browser_action` API is used instead of the newer `action` API
- Background scripts use port-based communication for better performance
- Storage APIs use `chrome.storage` which is compatible with Firefox
## Troubleshooting
### Extension not loading
- Ensure you're loading the `manifest.json` file, not the folder
- Check the Browser Console for error messages (`Ctrl+Shift+J`)
### dApp connection not working
- Refresh the dApp page after installing/updating the extension
- Check that the site is in the `matches` pattern in manifest.json
- Look for errors in the Browser Console
### Permission errors
- Firefox may show additional permission prompts
- Make sure to allow all requested permissions when installing

View File

@@ -0,0 +1,153 @@
// Background script for Firefox extension
// Handles messages from content scripts and manages wallet state
let currentPort = null;
// Listen for connection from content script
chrome.runtime.onConnect.addListener(function(port) {
if (port.name === "aitbc-wallet") {
currentPort = port;
port.onMessage.addListener(function(request) {
handleWalletRequest(request, port);
});
port.onDisconnect.addListener(function() {
currentPort = null;
});
}
});
// Handle wallet requests from dApps
async function handleWalletRequest(request, port) {
const { method, params, id } = request;
try {
switch (method) {
case 'connect':
const response = await handleConnect();
port.postMessage({ id, result: response });
break;
case 'accounts':
const accounts = await getAccounts();
port.postMessage({ id, result: accounts });
break;
case 'getBalance':
const balance = await getBalance(params.address);
port.postMessage({ id, result: balance });
break;
case 'sendTransaction':
const txResult = await sendTransaction(params);
port.postMessage({ id, result: txResult });
break;
case 'signMessage':
const signature = await signMessage(params.message);
port.postMessage({ id, result: signature });
break;
default:
port.postMessage({ id, error: 'Unknown method: ' + method });
}
} catch (error) {
port.postMessage({ id, error: error.message });
}
}
// Handle connection request from dApp
async function handleConnect() {
// Get current account
const result = await chrome.storage.local.get(['currentAccount']);
if (!result.currentAccount) {
throw new Error('No account found. Please create or import an account first.');
}
// Show connection prompt (in a real implementation, this would show a proper UI)
const connected = confirm(`Allow this site to connect to your AITBC Wallet?\n\nAddress: ${result.currentAccount.address}`);
if (!connected) {
throw new Error('User rejected connection');
}
return {
success: true,
address: result.currentAccount.address
};
}
// Get all accounts
async function getAccounts() {
const result = await chrome.storage.local.get(['accounts']);
const accounts = result.accounts || [];
return accounts.map(acc => acc.address);
}
// Get balance for an address
async function getBalance(address) {
// In a real implementation, this would query the blockchain
// For demo, return stored balance
const result = await chrome.storage.local.get(['accounts']);
const accounts = result.accounts || [];
const account = accounts.find(acc => acc.address === address);
return {
address: address,
balance: account ? account.balance || 0 : 0,
symbol: 'AITBC'
};
}
// Send transaction
async function sendTransaction(params) {
// In a real implementation, this would create, sign, and broadcast a transaction
const { to, amount, data } = params;
// Get current account
const result = await chrome.storage.local.get(['currentAccount']);
const account = result.currentAccount;
if (!account) {
throw new Error('No account connected');
}
// Confirm transaction
const confirmed = confirm(`Send ${amount} AITBC to ${to}?\n\nFrom: ${account.address}`);
if (!confirmed) {
throw new Error('Transaction rejected');
}
// Return mock transaction hash
return {
hash: '0x' + Array.from(crypto.getRandomValues(new Uint8Array(32)), b => b.toString(16).padStart(2, '0')).join(''),
status: 'pending'
};
}
// Sign message
async function signMessage(message) {
// Get current account
const result = await chrome.storage.local.get(['currentAccount']);
const account = result.currentAccount;
if (!account) {
throw new Error('No account connected');
}
// Confirm signing
const confirmed = confirm(`Sign the following message?\n\n"${message}"\n\nAccount: ${account.address}`);
if (!confirmed) {
throw new Error('Message signing rejected');
}
// In a real implementation, this would sign with the private key
// For demo, return a mock signature
const encoder = new TextEncoder();
const data = encoder.encode(message + account.privateKey);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('');
}

View File

@@ -0,0 +1,35 @@
// Content script for AITBC Wallet Firefox extension
(function() {
// Inject the wallet API into the page
const script = document.createElement('script');
script.src = chrome.runtime.getURL('injected.js');
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
// Create a port to background script
const port = chrome.runtime.connect({ name: "aitbc-wallet" });
// Listen for messages from the injected script
window.addEventListener('message', function(event) {
// Only accept messages from our own window
if (event.source !== window) return;
if (event.data.type && event.data.type === 'AITBC_WALLET_REQUEST') {
// Forward the request to the background script
port.postMessage(event.data);
}
});
// Listen for responses from background script
port.onMessage.addListener(function(response) {
// Send the response back to the page
window.postMessage({
type: 'AITBC_WALLET_RESPONSE',
id: response.id,
result: response.result,
error: response.error
}, '*');
});
})();

View File

@@ -0,0 +1,106 @@
// Injected script that provides the AITBC wallet API to the dApp
(function() {
// Create the wallet API object
const aitbcWallet = {
// Check if wallet is available
isAvailable: function() {
return true;
},
// Connect to wallet
connect: async function() {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
// Send request to content script
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: 'connect'
}, '*');
// Listen for response
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
// Timeout after 30 seconds
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Connection timeout'));
}, 30000);
});
},
// Get account address
getAccount: async function() {
const accounts = await this.request({ method: 'accounts' });
return accounts[0];
},
// Get balance
getBalance: async function(address) {
return this.request({ method: 'getBalance', params: { address } });
},
// Send transaction
sendTransaction: async function(to, amount, data = null) {
return this.request({
method: 'sendTransaction',
params: { to, amount, data }
});
},
// Sign message
signMessage: async function(message) {
return this.request({ method: 'signMessage', params: { message } });
},
// Generic request method
request: async function(payload) {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: payload.method,
params: payload.params || {}
}, '*');
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Request timeout'));
}, 30000);
});
}
};
// Inject the wallet API into the window object
window.aitbcWallet = aitbcWallet;
// Fire an event to notify the dApp that the wallet is ready
window.dispatchEvent(new Event('aitbcWalletReady'));
})();

View File

@@ -0,0 +1,46 @@
{
"manifest_version": 2,
"name": "AITBC Wallet",
"version": "1.0.0",
"description": "AITBC Browser Wallet for trading and managing AITBC tokens",
"permissions": [
"storage",
"activeTab"
],
"content_scripts": [
{
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"browser_action": {
"default_popup": "popup.html",
"default_title": "AITBC Wallet",
"default_icon": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
},
"web_accessible_resources": [
["injected.js"]
],
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
}
}

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 350px;
padding: 20px;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.logo {
width: 40px;
height: 40px;
margin-right: 10px;
background: white;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #f97316;
}
.wallet-info {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.address {
font-family: monospace;
font-size: 12px;
word-break: break-all;
margin: 5px 0;
}
.balance {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.actions {
display: flex;
flex-direction: column;
gap: 10px;
}
button {
background: white;
color: #f97316;
border: none;
padding: 10px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.transactions {
margin-top: 20px;
max-height: 200px;
overflow-y: auto;
}
.tx-item {
background: rgba(255, 255, 255, 0.1);
padding: 8px;
border-radius: 4px;
margin-bottom: 5px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">AITBC</div>
<h1>Wallet</h1>
</div>
<div class="wallet-info">
<div>Account Address:</div>
<div class="address" id="accountAddress">Not connected</div>
<div class="balance" id="balance">0 AITBC</div>
</div>
<div class="actions">
<button onclick="createAccount()">Create New Account</button>
<button onclick="importAccount()">Import Private Key</button>
<button onclick="sendTokens()">Send Tokens</button>
<button onclick="receiveTokens()">Receive Tokens</button>
<button onclick="viewOnExplorer()">View on Explorer</button>
</div>
<div class="transactions">
<h3>Recent Transactions</h3>
<div id="transactionList">
<div class="tx-item">No transactions yet</div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,162 @@
// Popup script for AITBC Wallet extension
let currentAccount = null;
let accounts = [];
// Load wallet data on popup open
document.addEventListener('DOMContentLoaded', async function() {
await loadWalletData();
updateUI();
});
// Load wallet data from storage
async function loadWalletData() {
const result = await chrome.storage.local.get(['accounts', 'currentAccount']);
accounts = result.accounts || [];
currentAccount = result.currentAccount || null;
}
// Save wallet data to storage
async function saveWalletData() {
await chrome.storage.local.set({
accounts: accounts,
currentAccount: currentAccount
});
}
// Update UI with current wallet state
function updateUI() {
const addressEl = document.getElementById('accountAddress');
const balanceEl = document.getElementById('balance');
if (currentAccount) {
addressEl.textContent = currentAccount.address;
balanceEl.textContent = `${currentAccount.balance || 0} AITBC`;
} else {
addressEl.textContent = 'Not connected';
balanceEl.textContent = '0 AITBC';
}
}
// Create a new account
async function createAccount() {
// Generate a new private key and address
const privateKey = generatePrivateKey();
const address = await generateAddress(privateKey);
const newAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(newAccount);
currentAccount = newAccount;
await saveWalletData();
updateUI();
alert('New account created! Please save your private key securely.');
}
// Import account from private key
async function importAccount() {
const privateKey = prompt('Enter your private key:');
if (!privateKey) return;
try {
const address = await generateAddress(privateKey);
// Check if account already exists
const existing = accounts.find(a => a.address === address);
if (existing) {
currentAccount = existing;
} else {
currentAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(currentAccount);
}
await saveWalletData();
updateUI();
alert('Account imported successfully!');
} catch (error) {
alert('Invalid private key!');
}
}
// Send tokens
async function sendTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
const to = prompt('Send to address:');
const amount = prompt('Amount:');
if (!to || !amount) return;
// In a real implementation, this would create and sign a transaction
alert(`Would send ${amount} AITBC to ${to}`);
}
// Receive tokens
function receiveTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
alert(`Your receiving address:\n${currentAccount.address}`);
}
// View on explorer
function viewOnExplorer() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
chrome.tabs.create({ url: `https://aitbc.bubuit.net/explorer/address/${currentAccount.address}` });
}
// Generate a random private key (demo only)
function generatePrivateKey() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
// Generate address from private key (demo only)
async function generateAddress(privateKey) {
// In a real implementation, this would derive the address from the private key
// using the appropriate cryptographic algorithm
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(privateKey));
return 'aitbc1' + Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('').substring(0, 40);
}
// Listen for connection requests from dApps
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.method === 'connect') {
// Show connection dialog
const connected = confirm(`Allow this site to connect to your AITBC Wallet?`);
if (connected && currentAccount) {
sendResponse({
success: true,
address: currentAccount.address
});
} else {
sendResponse({
success: false,
error: 'User rejected connection'
});
}
}
return true; // Keep the message channel open for async response
});

View File

@@ -0,0 +1,112 @@
# AITBC Browser Wallet Extension
A browser extension that provides AITBC wallet functionality for interacting with the AITBC Trade Exchange and other dApps.
## Features
- **Wallet Management**: Create new accounts or import existing private keys
- **Secure Storage**: Private keys are stored locally in the browser
- **dApp Integration**: Connect to AITBC Trade Exchange and other supported dApps
- **Transaction Signing**: Sign transactions and messages securely
- **Balance Tracking**: View your AITBC token balance
## Installation
### Development Installation
1. Clone this repository
2. Open Chrome and navigate to `chrome://extensions/`
3. Enable "Developer mode" in the top right
4. Click "Load unpacked"
5. Select the `aitbc-wallet` folder
### Production Installation
The extension will be published to the Chrome Web Store. Installation instructions will be available once published.
## Usage
### Connecting to the Exchange
1. Install the AITBC Wallet extension
2. Navigate to https://aitbc.bubuit.net/Exchange
3. Toggle the switch from "Demo Mode" to "Real Mode"
4. Click "Connect AITBC Wallet"
5. Approve the connection request in the popup
### Managing Accounts
1. Click the AITBC Wallet icon in your browser toolbar
2. Use "Create New Account" to generate a new wallet
3. Use "Import Private Key" to restore an existing wallet
4. **Important**: Save your private key securely! It cannot be recovered if lost.
## API Reference
The extension injects a `window.aitbcWallet` object into supported dApps with the following methods:
### `aitbcWallet.connect()`
Connect the dApp to the wallet.
```javascript
const response = await aitbcWallet.connect();
console.log(response.address); // User's AITBC address
```
### `aitbcWallet.getAccount()`
Get the current account address.
```javascript
const address = await aitbcWallet.getAccount();
```
### `aitbcWallet.getBalance(address)`
Get the AITBC balance for an address.
```javascript
const balance = await aitbcWallet.getBalance('aitbc1...');
console.log(balance.amount); // Balance in AITBC
```
### `aitbcWallet.sendTransaction(to, amount, data)`
Send AITBC tokens to another address.
```javascript
const tx = await aitbcWallet.sendTransaction('aitbc1...', 100);
console.log(tx.hash); // Transaction hash
```
### `aitbcWallet.signMessage(message)`
Sign a message with the private key.
```javascript
const signature = await aitbcWallet.signMessage('Hello AITBC!');
```
## Security Considerations
- Private keys are stored locally in Chrome's storage
- Always verify you're on the correct domain before connecting
- Never share your private key with anyone
- Keep your browser and extension updated
## Development
To modify the extension:
1. Make changes to the source files
2. Go to `chrome://extensions/`
3. Click the refresh button on the AITBC Wallet card
4. Test your changes
## File Structure
```
aitbc-wallet/
├── manifest.json # Extension configuration
├── content.js # Content script for dApp communication
├── injected.js # Script injected into dApps
├── popup.html # Extension popup UI
├── popup.js # Popup logic
├── icons/ # Extension icons
└── README.md # This file
```
## Support
For issues or feature requests, please create an issue in the repository.

Binary file not shown.

View File

@@ -0,0 +1,28 @@
// Content script for AITBC Wallet extension
(function() {
// Inject the wallet API into the page
const script = document.createElement('script');
script.src = chrome.runtime.getURL('injected.js');
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
// Listen for messages from the injected script
window.addEventListener('message', function(event) {
// Only accept messages from our own window
if (event.source !== window) return;
if (event.data.type && event.data.type === 'AITBC_WALLET_REQUEST') {
// Forward the request to the background script
chrome.runtime.sendMessage(event.data, function(response) {
// Send the response back to the page
window.postMessage({
type: 'AITBC_WALLET_RESPONSE',
id: event.data.id,
response: response
}, '*');
});
}
});
})();

View File

@@ -0,0 +1,106 @@
// Injected script that provides the AITBC wallet API to the dApp
(function() {
// Create the wallet API object
const aitbcWallet = {
// Check if wallet is available
isAvailable: function() {
return true;
},
// Connect to wallet
connect: async function() {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
// Send request to content script
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: 'connect'
}, '*');
// Listen for response
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
// Timeout after 30 seconds
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Connection timeout'));
}, 30000);
});
},
// Get account address
getAccount: async function() {
const accounts = await this.request({ method: 'accounts' });
return accounts[0];
},
// Get balance
getBalance: async function(address) {
return this.request({ method: 'getBalance', params: { address } });
},
// Send transaction
sendTransaction: async function(to, amount, data = null) {
return this.request({
method: 'sendTransaction',
params: { to, amount, data }
});
},
// Sign message
signMessage: async function(message) {
return this.request({ method: 'signMessage', params: { message } });
},
// Generic request method
request: async function(payload) {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: payload.method,
params: payload.params || {}
}, '*');
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Request timeout'));
}, 30000);
});
}
};
// Inject the wallet API into the window object
window.aitbcWallet = aitbcWallet;
// Fire an event to notify the dApp that the wallet is ready
window.dispatchEvent(new Event('aitbcWalletReady'));
})();

View File

@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Install AITBC Wallet for Chrome</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #4285f4 0%, #1a73e8 100%);
color: white;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 20px;
}
.install-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 40px;
text-align: center;
max-width: 500px;
width: 100%;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}
.logo {
width: 80px;
height: 80px;
background: white;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-weight: bold;
color: #1a73e8;
margin: 0 auto 30px;
}
h1 {
font-size: 2.5em;
margin-bottom: 20px;
}
.steps {
text-align: left;
margin: 30px 0;
background: rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 10px;
}
.step {
display: flex;
align-items: flex-start;
margin: 15px 0;
}
.step-number {
background: white;
color: #1a73e8;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 15px;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-title {
font-weight: bold;
margin-bottom: 5px;
}
.step-desc {
font-size: 14px;
opacity: 0.9;
}
.download-button {
display: inline-block;
background: white;
color: #1a73e8;
padding: 16px 40px;
border-radius: 50px;
font-size: 18px;
font-weight: bold;
text-decoration: none;
transition: all 0.3s ease;
margin: 20px 0;
}
.download-button:hover {
transform: scale(1.05);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.code {
background: rgba(0, 0, 0, 0.2);
padding: 5px 10px;
border-radius: 5px;
font-family: monospace;
font-size: 14px;
}
</style>
</head>
<body>
<div class="install-card">
<div class="logo">AITBC</div>
<h1>AITBC Wallet</h1>
<p>The secure wallet for AITBC tokens</p>
<a href="aitbc-wallet.zip" class="download-button">
Download Extension
</a>
<div class="steps">
<div class="step">
<div class="step-number">1</div>
<div class="step-content">
<div class="step-title">Download the extension</div>
<div class="step-desc">Click the download button above</div>
</div>
</div>
<div class="step">
<div class="step-number">2</div>
<div class="step-content">
<div class="step-title">Open Chrome Extensions</div>
<div class="step-desc">Navigate to <span class="code">chrome://extensions/</span></div>
</div>
</div>
<div class="step">
<div class="step-number">3</div>
<div class="step-content">
<div class="step-title">Enable Developer Mode</div>
<div class="step-desc">Toggle the switch in the top right</div>
</div>
</div>
<div class="step">
<div class="step-number">4</div>
<div class="step-content">
<div class="step-title">Load Extension</div>
<div class="step-desc">Click "Load unpacked" and select the extracted folder</div>
</div>
</div>
</div>
<p style="font-size: 14px; opacity: 0.8; margin-top: 20px;">
Chrome requires developer mode for security. This ensures you know exactly what you're installing.
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,32 @@
{
"manifest_version": 3,
"name": "AITBC Wallet",
"version": "1.0.0",
"description": "AITBC Browser Wallet for trading and managing AITBC tokens",
"permissions": [
"storage",
"activeTab"
],
"content_scripts": [
{
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"action": {
"default_popup": "popup.html",
"default_title": "AITBC Wallet"
},
"web_accessible_resources": [
{
"resources": ["injected.js"],
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"]
}
],
"icons": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 350px;
padding: 20px;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.logo {
width: 40px;
height: 40px;
margin-right: 10px;
background: white;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #f97316;
}
.wallet-info {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.address {
font-family: monospace;
font-size: 12px;
word-break: break-all;
margin: 5px 0;
}
.balance {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.actions {
display: flex;
flex-direction: column;
gap: 10px;
}
button {
background: white;
color: #f97316;
border: none;
padding: 10px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.transactions {
margin-top: 20px;
max-height: 200px;
overflow-y: auto;
}
.tx-item {
background: rgba(255, 255, 255, 0.1);
padding: 8px;
border-radius: 4px;
margin-bottom: 5px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">AITBC</div>
<h1>Wallet</h1>
</div>
<div class="wallet-info">
<div>Account Address:</div>
<div class="address" id="accountAddress">Not connected</div>
<div class="balance" id="balance">0 AITBC</div>
</div>
<div class="actions">
<button onclick="createAccount()">Create New Account</button>
<button onclick="importAccount()">Import Private Key</button>
<button onclick="sendTokens()">Send Tokens</button>
<button onclick="receiveTokens()">Receive Tokens</button>
<button onclick="viewOnExplorer()">View on Explorer</button>
</div>
<div class="transactions">
<h3>Recent Transactions</h3>
<div id="transactionList">
<div class="tx-item">No transactions yet</div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,162 @@
// Popup script for AITBC Wallet extension
let currentAccount = null;
let accounts = [];
// Load wallet data on popup open
document.addEventListener('DOMContentLoaded', async function() {
await loadWalletData();
updateUI();
});
// Load wallet data from storage
async function loadWalletData() {
const result = await chrome.storage.local.get(['accounts', 'currentAccount']);
accounts = result.accounts || [];
currentAccount = result.currentAccount || null;
}
// Save wallet data to storage
async function saveWalletData() {
await chrome.storage.local.set({
accounts: accounts,
currentAccount: currentAccount
});
}
// Update UI with current wallet state
function updateUI() {
const addressEl = document.getElementById('accountAddress');
const balanceEl = document.getElementById('balance');
if (currentAccount) {
addressEl.textContent = currentAccount.address;
balanceEl.textContent = `${currentAccount.balance || 0} AITBC`;
} else {
addressEl.textContent = 'Not connected';
balanceEl.textContent = '0 AITBC';
}
}
// Create a new account
async function createAccount() {
// Generate a new private key and address
const privateKey = generatePrivateKey();
const address = await generateAddress(privateKey);
const newAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(newAccount);
currentAccount = newAccount;
await saveWalletData();
updateUI();
alert('New account created! Please save your private key securely.');
}
// Import account from private key
async function importAccount() {
const privateKey = prompt('Enter your private key:');
if (!privateKey) return;
try {
const address = await generateAddress(privateKey);
// Check if account already exists
const existing = accounts.find(a => a.address === address);
if (existing) {
currentAccount = existing;
} else {
currentAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(currentAccount);
}
await saveWalletData();
updateUI();
alert('Account imported successfully!');
} catch (error) {
alert('Invalid private key!');
}
}
// Send tokens
async function sendTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
const to = prompt('Send to address:');
const amount = prompt('Amount:');
if (!to || !amount) return;
// In a real implementation, this would create and sign a transaction
alert(`Would send ${amount} AITBC to ${to}`);
}
// Receive tokens
function receiveTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
alert(`Your receiving address:\n${currentAccount.address}`);
}
// View on explorer
function viewOnExplorer() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
chrome.tabs.create({ url: `https://aitbc.bubuit.net/explorer/address/${currentAccount.address}` });
}
// Generate a random private key (demo only)
function generatePrivateKey() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
// Generate address from private key (demo only)
async function generateAddress(privateKey) {
// In a real implementation, this would derive the address from the private key
// using the appropriate cryptographic algorithm
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(privateKey));
return 'aitbc1' + Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('').substring(0, 40);
}
// Listen for connection requests from dApps
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.method === 'connect') {
// Show connection dialog
const connected = confirm(`Allow this site to connect to your AITBC Wallet?`);
if (connected && currentAccount) {
sendResponse({
success: true,
address: currentAccount.address
});
} else {
sendResponse({
success: false,
error: 'User rejected connection'
});
}
}
return true; // Keep the message channel open for async response
});

BIN
extensions/aitbc-wallet.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,112 @@
# AITBC Browser Wallet Extension
A browser extension that provides AITBC wallet functionality for interacting with the AITBC Trade Exchange and other dApps.
## Features
- **Wallet Management**: Create new accounts or import existing private keys
- **Secure Storage**: Private keys are stored locally in the browser
- **dApp Integration**: Connect to AITBC Trade Exchange and other supported dApps
- **Transaction Signing**: Sign transactions and messages securely
- **Balance Tracking**: View your AITBC token balance
## Installation
### Development Installation
1. Clone this repository
2. Open Chrome and navigate to `chrome://extensions/`
3. Enable "Developer mode" in the top right
4. Click "Load unpacked"
5. Select the `aitbc-wallet` folder
### Production Installation
The extension will be published to the Chrome Web Store. Installation instructions will be available once published.
## Usage
### Connecting to the Exchange
1. Install the AITBC Wallet extension
2. Navigate to https://aitbc.bubuit.net/Exchange
3. Toggle the switch from "Demo Mode" to "Real Mode"
4. Click "Connect AITBC Wallet"
5. Approve the connection request in the popup
### Managing Accounts
1. Click the AITBC Wallet icon in your browser toolbar
2. Use "Create New Account" to generate a new wallet
3. Use "Import Private Key" to restore an existing wallet
4. **Important**: Save your private key securely! It cannot be recovered if lost.
## API Reference
The extension injects a `window.aitbcWallet` object into supported dApps with the following methods:
### `aitbcWallet.connect()`
Connect the dApp to the wallet.
```javascript
const response = await aitbcWallet.connect();
console.log(response.address); // User's AITBC address
```
### `aitbcWallet.getAccount()`
Get the current account address.
```javascript
const address = await aitbcWallet.getAccount();
```
### `aitbcWallet.getBalance(address)`
Get the AITBC balance for an address.
```javascript
const balance = await aitbcWallet.getBalance('aitbc1...');
console.log(balance.amount); // Balance in AITBC
```
### `aitbcWallet.sendTransaction(to, amount, data)`
Send AITBC tokens to another address.
```javascript
const tx = await aitbcWallet.sendTransaction('aitbc1...', 100);
console.log(tx.hash); // Transaction hash
```
### `aitbcWallet.signMessage(message)`
Sign a message with the private key.
```javascript
const signature = await aitbcWallet.signMessage('Hello AITBC!');
```
## Security Considerations
- Private keys are stored locally in Chrome's storage
- Always verify you're on the correct domain before connecting
- Never share your private key with anyone
- Keep your browser and extension updated
## Development
To modify the extension:
1. Make changes to the source files
2. Go to `chrome://extensions/`
3. Click the refresh button on the AITBC Wallet card
4. Test your changes
## File Structure
```
aitbc-wallet/
├── manifest.json # Extension configuration
├── content.js # Content script for dApp communication
├── injected.js # Script injected into dApps
├── popup.html # Extension popup UI
├── popup.js # Popup logic
├── icons/ # Extension icons
└── README.md # This file
```
## Support
For issues or feature requests, please create an issue in the repository.

View File

@@ -0,0 +1,28 @@
// Content script for AITBC Wallet extension
(function() {
// Inject the wallet API into the page
const script = document.createElement('script');
script.src = chrome.runtime.getURL('injected.js');
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
// Listen for messages from the injected script
window.addEventListener('message', function(event) {
// Only accept messages from our own window
if (event.source !== window) return;
if (event.data.type && event.data.type === 'AITBC_WALLET_REQUEST') {
// Forward the request to the background script
chrome.runtime.sendMessage(event.data, function(response) {
// Send the response back to the page
window.postMessage({
type: 'AITBC_WALLET_RESPONSE',
id: event.data.id,
response: response
}, '*');
});
}
});
})();

View File

@@ -0,0 +1,106 @@
// Injected script that provides the AITBC wallet API to the dApp
(function() {
// Create the wallet API object
const aitbcWallet = {
// Check if wallet is available
isAvailable: function() {
return true;
},
// Connect to wallet
connect: async function() {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
// Send request to content script
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: 'connect'
}, '*');
// Listen for response
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
// Timeout after 30 seconds
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Connection timeout'));
}, 30000);
});
},
// Get account address
getAccount: async function() {
const accounts = await this.request({ method: 'accounts' });
return accounts[0];
},
// Get balance
getBalance: async function(address) {
return this.request({ method: 'getBalance', params: { address } });
},
// Send transaction
sendTransaction: async function(to, amount, data = null) {
return this.request({
method: 'sendTransaction',
params: { to, amount, data }
});
},
// Sign message
signMessage: async function(message) {
return this.request({ method: 'signMessage', params: { message } });
},
// Generic request method
request: async function(payload) {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString();
window.postMessage({
type: 'AITBC_WALLET_REQUEST',
id: requestId,
method: payload.method,
params: payload.params || {}
}, '*');
const messageHandler = function(event) {
if (event.data.type === 'AITBC_WALLET_RESPONSE' && event.data.id === requestId) {
window.removeEventListener('message', messageHandler);
if (event.data.response.error) {
reject(new Error(event.data.response.error));
} else {
resolve(event.data.response);
}
}
};
window.addEventListener('message', messageHandler);
setTimeout(() => {
window.removeEventListener('message', messageHandler);
reject(new Error('Request timeout'));
}, 30000);
});
}
};
// Inject the wallet API into the window object
window.aitbcWallet = aitbcWallet;
// Fire an event to notify the dApp that the wallet is ready
window.dispatchEvent(new Event('aitbcWalletReady'));
})();

View File

@@ -0,0 +1,32 @@
{
"manifest_version": 3,
"name": "AITBC Wallet",
"version": "1.0.0",
"description": "AITBC Browser Wallet for trading and managing AITBC tokens",
"permissions": [
"storage",
"activeTab"
],
"content_scripts": [
{
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"action": {
"default_popup": "popup.html",
"default_title": "AITBC Wallet"
},
"web_accessible_resources": [
{
"resources": ["injected.js"],
"matches": ["https://aitbc.bubuit.net/*", "http://localhost:3002/*"]
}
],
"icons": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 350px;
padding: 20px;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.logo {
width: 40px;
height: 40px;
margin-right: 10px;
background: white;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #f97316;
}
.wallet-info {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.address {
font-family: monospace;
font-size: 12px;
word-break: break-all;
margin: 5px 0;
}
.balance {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.actions {
display: flex;
flex-direction: column;
gap: 10px;
}
button {
background: white;
color: #f97316;
border: none;
padding: 10px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.transactions {
margin-top: 20px;
max-height: 200px;
overflow-y: auto;
}
.tx-item {
background: rgba(255, 255, 255, 0.1);
padding: 8px;
border-radius: 4px;
margin-bottom: 5px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">AITBC</div>
<h1>Wallet</h1>
</div>
<div class="wallet-info">
<div>Account Address:</div>
<div class="address" id="accountAddress">Not connected</div>
<div class="balance" id="balance">0 AITBC</div>
</div>
<div class="actions">
<button onclick="createAccount()">Create New Account</button>
<button onclick="importAccount()">Import Private Key</button>
<button onclick="sendTokens()">Send Tokens</button>
<button onclick="receiveTokens()">Receive Tokens</button>
<button onclick="viewOnExplorer()">View on Explorer</button>
</div>
<div class="transactions">
<h3>Recent Transactions</h3>
<div id="transactionList">
<div class="tx-item">No transactions yet</div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,162 @@
// Popup script for AITBC Wallet extension
let currentAccount = null;
let accounts = [];
// Load wallet data on popup open
document.addEventListener('DOMContentLoaded', async function() {
await loadWalletData();
updateUI();
});
// Load wallet data from storage
async function loadWalletData() {
const result = await chrome.storage.local.get(['accounts', 'currentAccount']);
accounts = result.accounts || [];
currentAccount = result.currentAccount || null;
}
// Save wallet data to storage
async function saveWalletData() {
await chrome.storage.local.set({
accounts: accounts,
currentAccount: currentAccount
});
}
// Update UI with current wallet state
function updateUI() {
const addressEl = document.getElementById('accountAddress');
const balanceEl = document.getElementById('balance');
if (currentAccount) {
addressEl.textContent = currentAccount.address;
balanceEl.textContent = `${currentAccount.balance || 0} AITBC`;
} else {
addressEl.textContent = 'Not connected';
balanceEl.textContent = '0 AITBC';
}
}
// Create a new account
async function createAccount() {
// Generate a new private key and address
const privateKey = generatePrivateKey();
const address = await generateAddress(privateKey);
const newAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(newAccount);
currentAccount = newAccount;
await saveWalletData();
updateUI();
alert('New account created! Please save your private key securely.');
}
// Import account from private key
async function importAccount() {
const privateKey = prompt('Enter your private key:');
if (!privateKey) return;
try {
const address = await generateAddress(privateKey);
// Check if account already exists
const existing = accounts.find(a => a.address === address);
if (existing) {
currentAccount = existing;
} else {
currentAccount = {
address: address,
privateKey: privateKey,
balance: 0,
created: new Date().toISOString()
};
accounts.push(currentAccount);
}
await saveWalletData();
updateUI();
alert('Account imported successfully!');
} catch (error) {
alert('Invalid private key!');
}
}
// Send tokens
async function sendTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
const to = prompt('Send to address:');
const amount = prompt('Amount:');
if (!to || !amount) return;
// In a real implementation, this would create and sign a transaction
alert(`Would send ${amount} AITBC to ${to}`);
}
// Receive tokens
function receiveTokens() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
alert(`Your receiving address:\n${currentAccount.address}`);
}
// View on explorer
function viewOnExplorer() {
if (!currentAccount) {
alert('Please create or import an account first!');
return;
}
chrome.tabs.create({ url: `https://aitbc.bubuit.net/explorer/address/${currentAccount.address}` });
}
// Generate a random private key (demo only)
function generatePrivateKey() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
// Generate address from private key (demo only)
async function generateAddress(privateKey) {
// In a real implementation, this would derive the address from the private key
// using the appropriate cryptographic algorithm
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(privateKey));
return 'aitbc1' + Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join('').substring(0, 40);
}
// Listen for connection requests from dApps
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.method === 'connect') {
// Show connection dialog
const connected = confirm(`Allow this site to connect to your AITBC Wallet?`);
if (connected && currentAccount) {
sendResponse({
success: true,
address: currentAccount.address
});
} else {
sendResponse({
success: false,
error: 'User rejected connection'
});
}
}
return true; // Keep the message channel open for async response
});

21
scripts/return_testnet_btc.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
# Script to return testnet Bitcoin
RETURN_ADDRESS="tb1qerzrlxcfu24davlur5sqmgzzgsal6wusda40er"
echo "Checking balance..."
BALANCE=$(bitcoin-cli -testnet -rpcwallet=aitbc_exchange getbalance)
if [ "$(echo "$BALANCE > 0" | bc)" -eq 1 ]; then
echo "Current balance: $BALANCE BTC"
echo "Sending to return address: $RETURN_ADDRESS"
# Calculate amount to send (balance minus small fee)
SEND_AMOUNT=$(echo "$BALANCE - 0.00001" | bc)
TXID=$(bitcoin-cli -testnet -rpcwallet=aitbc_exchange sendtoaddress "$RETURN_ADDRESS" "$SEND_AMOUNT")
echo "Transaction sent! TXID: $TXID"
echo "Explorer: https://blockstream.info/testnet/tx/$TXID"
else
echo "No Bitcoin to return. Current balance: $BALANCE BTC"
fi

View File

@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Browser Wallet - Redirecting...</title>
<script>
// Immediate redirect
window.location.replace('/docs/browser-wallet.html');
</script>
<noscript>
<meta http-equiv="refresh" content="0; url=/docs/browser-wallet.html">
</noscript>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.redirect-message {
text-align: center;
padding: 40px;
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
backdrop-filter: blur(10px);
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
a {
color: white;
text-decoration: underline;
}
</style>
</head>
<body>
<div class="redirect-message">
<div class="spinner"></div>
<h1>AITBC Browser Wallet</h1>
<p>Redirecting to the installation page...</p>
<p>If you're not redirected automatically, <a href="/docs/browser-wallet.html">click here</a>.</p>
</div>
</body>
</html>

View File

@@ -509,6 +509,10 @@
<i class="fas fa-exchange-alt"></i>
<span>Trade Exchange</span>
</a>
<a href="browser-wallet.html" class="link-item">
<i class="fas fa-wallet"></i>
<span>Browser Wallet</span>
</a>
<a href="https://gitea.bubuit.net/oib/aitbc" class="link-item">
<i class="fab fa-git-alt"></i>
<span>Source Code</span>

View File

@@ -0,0 +1,416 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITBC Browser Wallet - Secure Crypto Wallet</title>
<link rel="stylesheet" href="/assets/css/aitbc.css">
<script src="/assets/js/lucide.js"></script>
<style>
.hero-gradient {
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
}
.feature-card {
transition: all 0.3s ease;
border: 1px solid #e5e7eb;
}
.feature-card:hover {
transform: translateY(-4px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
.browser-button {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 16px 32px;
border-radius: 12px;
font-size: 18px;
font-weight: 600;
transition: all 0.3s ease;
text-decoration: none;
color: white;
}
.browser-button:hover {
transform: scale(1.05);
}
.chrome-button {
background: linear-gradient(135deg, #4285f4 0%, #1a73e8 100%);
}
.firefox-button {
background: linear-gradient(135deg, #ff9500 0%, #ff6611 100%);
}
.step-number {
width: 40px;
height: 40px;
background: #f97316;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
flex-shrink: 0;
}
.code-block {
background: #1e293b;
color: #e2e8f0;
padding: 16px;
border-radius: 8px;
font-family: monospace;
overflow-x: auto;
}
.security-icon {
width: 64px;
height: 64px;
margin: 0 auto 16px;
}
</style>
</head>
<body class="bg-gray-50">
<!-- Header -->
<header class="hero-gradient text-white">
<nav class="container mx-auto px-4 py-6">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<i data-lucide="wallet" class="w-8 h-8"></i>
<span class="text-2xl font-bold">AITBC</span>
</div>
<div class="flex items-center space-x-6">
<a href="/docs/" class="hover:text-orange-200 transition">Documentation</a>
<a href="/Exchange/" class="hover:text-orange-200 transition">Exchange</a>
<a href="/explorer/" class="hover:text-orange-200 transition">Explorer</a>
</div>
</div>
</nav>
<div class="container mx-auto px-4 py-20 text-center">
<h1 class="text-5xl font-bold mb-6">AITBC Browser Wallet</h1>
<p class="text-xl mb-8 max-w-2xl mx-auto">
The most secure way to store, send, and receive AITBC tokens.
Connect to the AITBC Trade Exchange with just one click.
</p>
<div class="flex justify-center gap-6 flex-wrap">
<a href="/chrome-wallet/install.html" class="browser-button chrome-button">
<i data-lucide="chrome" class="w-6 h-6"></i>
Install for Chrome
</a>
<a href="/firefox-wallet/install.html" class="browser-button firefox-button">
<i data-lucide="globe" class="w-6 h-6"></i>
Install for Firefox
</a>
</div>
</div>
</header>
<!-- Features Section -->
<section class="py-20">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Why Choose AITBC Wallet?</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="feature-card bg-white p-8 rounded-xl text-center">
<i data-lucide="shield" class="security-icon text-orange-600"></i>
<h3 class="text-xl font-semibold mb-4">Bank-Grade Security</h3>
<p class="text-gray-600">
Your private keys never leave your device.
Encrypted locally with military-grade security.
</p>
</div>
<div class="feature-card bg-white p-8 rounded-xl text-center">
<i data-lucide="link" class="security-icon text-orange-600"></i>
<h3 class="text-xl font-semibold mb-4">Seamless dApp Integration</h3>
<p class="text-gray-600">
Connect to any AITBC-powered dApp with a single click.
No more copying and pasting addresses.
</p>
</div>
<div class="feature-card bg-white p-8 rounded-xl text-center">
<i data-lucide="zap" class="security-icon text-orange-600"></i>
<h3 class="text-xl font-semibold mb-4">Lightning Fast</h3>
<p class="text-gray-600">
Built for performance.
Instant transactions and real-time balance updates.
</p>
</div>
</div>
</div>
</section>
<!-- Chrome Installation -->
<section id="chrome-install" class="py-20 bg-gray-100">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Install for Chrome / Edge / Brave</h2>
<div class="max-w-3xl mx-auto">
<div class="bg-white rounded-xl p-8 shadow-lg">
<h3 class="text-2xl font-semibold mb-6 flex items-center">
<i data-lucide="chrome" class="w-8 h-8 mr-3"></i>
Chrome Installation Steps
</h3>
<div class="space-y-6">
<div class="flex gap-4">
<div class="step-number">1</div>
<div>
<h4 class="font-semibold mb-2">Download the Extension</h4>
<p class="text-gray-600 mb-4">
Download the AITBC Wallet extension files to your computer.
</p>
<a href="/assets/aitbc-wallet.zip" class="inline-flex items-center gap-2 bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition">
<i data-lucide="download" class="w-5 h-5"></i>
Download Chrome Extension
</a>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">2</div>
<div>
<h4 class="font-semibold mb-2">Open Chrome Extensions</h4>
<p class="text-gray-600 mb-4">
Open Chrome and navigate to the extensions page:
</p>
<div class="code-block">chrome://extensions/</div>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">3</div>
<div>
<h4 class="font-semibold mb-2">Enable Developer Mode</h4>
<p class="text-gray-600 mb-4">
Toggle the "Developer mode" switch in the top right corner.
</p>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">4</div>
<div>
<h4 class="font-semibold mb-2">Load Extension</h4>
<p class="text-gray-600 mb-4">
Click "Load unpacked" and select the <code>aitbc-wallet</code> folder.
</p>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">5</div>
<div>
<h4 class="font-semibold mb-2">Start Using!</h4>
<p class="text-gray-600">
Click the AITBC Wallet icon in your toolbar to create or import an account.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Firefox Installation -->
<section id="firefox-install" class="py-20">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Install for Firefox</h2>
<div class="max-w-3xl mx-auto">
<div class="bg-white rounded-xl p-8 shadow-lg">
<h3 class="text-2xl font-semibold mb-6 flex items-center">
<i data-lucide="globe" class="w-8 h-8 mr-3 text-orange-600"></i>
Firefox Installation Steps
</h3>
<div class="space-y-6">
<div class="flex gap-4">
<div class="step-number">1</div>
<div>
<h4 class="font-semibold mb-2">Visit Install Page</h4>
<p class="text-gray-600 mb-4">
Click the button below to go to the Firefox installation page.
</p>
<a href="/firefox-wallet/install.html" class="inline-flex items-center gap-2 bg-orange-600 text-white px-6 py-3 rounded-lg hover:bg-orange-700 transition">
<i data-lucide="download" class="w-5 h-5"></i>
Install Firefox Extension
</a>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">2</div>
<div>
<h4 class="font-semibold mb-2">Click "Add to Firefox"</h4>
<p class="text-gray-600">
On the install page, click the "Add to Firefox" button to install the extension.
</p>
</div>
</div>
<div class="flex gap-4">
<div class="step-number">3</div>
<div>
<h4 class="font-semibold mb-2">Start Using!</h4>
<p class="text-gray-600">
The AITBC Wallet will appear in your toolbar with an orange icon. Click to create your first account!
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Usage Guide -->
<section class="py-20 bg-gray-100">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Using Your AITBC Wallet</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-5xl mx-auto">
<div class="bg-white p-8 rounded-xl">
<h3 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="plus-circle" class="w-6 h-6 mr-2 text-green-600"></i>
Create a New Wallet
</h3>
<ol class="space-y-2 text-gray-600">
<li>1. Click the AITBC Wallet icon</li>
<li>2. Select "Create New Account"</li>
<li>3. Securely save your private key</li>
<li>4. Your wallet is ready!</li>
</ol>
</div>
<div class="bg-white p-8 rounded-xl">
<h3 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="download" class="w-6 h-6 mr-2 text-blue-600"></i>
Import Existing Wallet
</h3>
<ol class="space-y-2 text-gray-600">
<li>1. Click the AITBC Wallet icon</li>
<li>2. Select "Import Private Key"</li>
<li>3. Enter your private key</li>
<li>4. Access your restored wallet</li>
</ol>
</div>
<div class="bg-white p-8 rounded-xl">
<h3 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="link" class="w-6 h-6 mr-2 text-purple-600"></i>
Connect to Exchange
</h3>
<ol class="space-y-2 text-gray-600">
<li>1. Visit <a href="/Exchange/" class="text-blue-600 hover:underline">AITBC Exchange</a></li>
<li>2. Toggle to "Real Mode"</li>
<li>3. Click "Connect AITBC Wallet"</li>
<li>4. Approve the connection</li>
</ol>
</div>
<div class="bg-white p-8 rounded-xl">
<h3 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="send" class="w-6 h-6 mr-2 text-orange-600"></i>
Send & Receive Tokens
</h3>
<ol class="space-y-2 text-gray-600">
<li>1. Click "Send" to transfer tokens</li>
<li>2. Click "Receive" to get your address</li>
<li>3. All transactions require confirmation</li>
<li>4. View history in the wallet</li>
</ol>
</div>
</div>
</div>
</section>
<!-- Security Tips -->
<section class="py-20">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Security Best Practices</h2>
<div class="max-w-3xl mx-auto">
<div class="bg-red-50 border border-red-200 rounded-xl p-8">
<h3 class="text-xl font-semibold mb-6 text-red-800 flex items-center">
<i data-lucide="alert-triangle" class="w-6 h-6 mr-2"></i>
Important Security Reminders
</h3>
<ul class="space-y-4 text-gray-700">
<li class="flex items-start">
<i data-lucide="shield" class="w-5 h-5 mr-3 mt-0.5 text-red-600 flex-shrink-0"></i>
<span><strong>Never share your private key</strong> - Anyone with your private key has full control of your funds</span>
</li>
<li class="flex items-start">
<i data-lucide="file-text" class="w-5 h-5 mr-3 mt-0.5 text-red-600 flex-shrink-0"></i>
<span><strong>Backup your private key</strong> - Write it down and store it in a secure, offline location</span>
</li>
<li class="flex items-start">
<i data-lucide="globe" class="w-5 h-5 mr-3 mt-0.5 text-red-600 flex-shrink-0"></i>
<span><strong>Verify URLs</strong> - Always ensure you're on aitbc.bubuit.net before connecting</span>
</li>
<li class="flex items-start">
<i data-lucide="lock" class="w-5 h-5 mr-3 mt-0.5 text-red-600 flex-shrink-0"></i>
<span><strong>Use a password manager</strong> - Protect your browser with a strong, unique password</span>
</li>
<li class="flex items-start">
<i data-lucide="refresh-cw" class="w-5 h-5 mr-3 mt-0.5 text-red-600 flex-shrink-0"></i>
<span><strong>Keep updated</strong> - Regularly update your browser and the wallet extension</span>
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-gray-900 text-white py-12">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div>
<h4 class="text-lg font-semibold mb-4">AITBC Wallet</h4>
<p class="text-gray-400">
The secure browser wallet for AITBC tokens
</p>
</div>
<div>
<h4 class="text-lg font-semibold mb-4">Quick Links</h4>
<ul class="space-y-2 text-gray-400">
<li><a href="/Exchange/" class="hover:text-white transition">Trade Exchange</a></li>
<li><a href="/explorer/" class="hover:text-white transition">Block Explorer</a></li>
<li><a href="/docs/" class="hover:text-white transition">Documentation</a></li>
</ul>
</div>
<div>
<h4 class="text-lg font-semibold mb-4">Support</h4>
<p class="text-gray-400">
Need help? Check our documentation or create an issue on GitHub.
</p>
</div>
</div>
<div class="border-t border-gray-800 mt-8 pt-8 text-center text-gray-400">
<p>&copy; 2025 AITBC. All rights reserved.</p>
</div>
</div>
</footer>
<script>
// Initialize Lucide icons
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
});
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
</script>
</body>
</html>

Binary file not shown.

Binary file not shown.