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

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