// Import our WebAssembly module import init, { create_key_space, encrypt_key_space, decrypt_key_space, logout, create_keypair, select_keypair, list_keypairs, keypair_pub_key, create_ethereum_wallet, create_ethereum_wallet_from_name, create_ethereum_wallet_from_private_key, get_ethereum_address, get_ethereum_private_key, format_eth_balance, clear_ethereum_wallets } from '../../pkg/webassembly.js'; // Helper function to convert ArrayBuffer to hex string function bufferToHex(buffer) { return Array.from(new Uint8Array(buffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } // Helper function to convert hex string to Uint8Array function hexToBuffer(hex) { const bytes = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { bytes[i / 2] = parseInt(hex.substr(i, 2), 16); } return bytes; } // IndexedDB setup for Ethereum wallets const DB_NAME = 'EthWalletDB'; const DB_VERSION = 1; const STORE_NAME = 'ethWallets'; // Initialize the database function initDatabase() { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onerror = (event) => { console.error('Error opening Ethereum wallet database:', event.target.error); reject('Error opening database: ' + event.target.error); }; request.onsuccess = (event) => { const db = event.target.result; resolve(db); }; request.onupgradeneeded = (event) => { const db = event.target.result; // Create object store for Ethereum wallets if it doesn't exist if (!db.objectStoreNames.contains(STORE_NAME)) { const store = db.createObjectStore(STORE_NAME, { keyPath: 'address' }); store.createIndex('address', 'address', { unique: true }); } }; }); } // Get database connection function getDB() { return initDatabase(); } // Save Ethereum wallet to IndexedDB async function saveEthWalletToStorage(address, privateKey) { try { const db = await getDB(); return new Promise((resolve, reject) => { const transaction = db.transaction([STORE_NAME], 'readwrite'); const store = transaction.objectStore(STORE_NAME); const wallet = { address: address, privateKey: privateKey, created: new Date() }; const request = store.put(wallet); request.onsuccess = () => { resolve(); }; request.onerror = (event) => { console.error('Error saving Ethereum wallet:', event.target.error); reject('Error saving wallet: ' + event.target.error); }; transaction.oncomplete = () => { db.close(); }; }); } catch (error) { console.error('Database error in saveEthWalletToStorage:', error); } } // Get Ethereum wallet from IndexedDB async function getEthWalletFromStorage(address) { try { const db = await getDB(); return new Promise((resolve, reject) => { const transaction = db.transaction([STORE_NAME], 'readonly'); const store = transaction.objectStore(STORE_NAME); const request = store.get(address); request.onsuccess = (event) => { const wallet = event.target.result; if (wallet) { resolve(wallet.privateKey); } else { resolve(null); } }; request.onerror = (event) => { console.error('Error retrieving Ethereum wallet:', event.target.error); reject('Error retrieving wallet: ' + event.target.error); }; transaction.oncomplete = () => { db.close(); }; }); } catch (error) { console.error('Database error in getEthWalletFromStorage:', error); return null; } } // Session state let selectedKeypair = null; let hasEthereumWallet = false; // Update UI based on login state function updateLoginUI() { const loginStatus = document.getElementById('login-status'); try { // Try to list keypairs to check if logged in const keypairs = list_keypairs(); if (keypairs && keypairs.length > 0) { loginStatus.textContent = 'Status: Logged in'; loginStatus.className = 'status logged-in'; // Update keypairs list updateKeypairsList(); } else { loginStatus.textContent = 'Status: Not logged in. Please login in the Main Crypto Demo page first.'; loginStatus.className = 'status logged-out'; // Hide Ethereum wallet info when logged out document.getElementById('ethereum-wallet-info').classList.add('hidden'); hasEthereumWallet = false; } } catch (e) { loginStatus.textContent = 'Status: Not logged in. Please login in the Main Crypto Demo page first.'; loginStatus.className = 'status logged-out'; // Hide Ethereum wallet info when logged out document.getElementById('ethereum-wallet-info').classList.add('hidden'); hasEthereumWallet = false; } } // Update the keypairs dropdown list function updateKeypairsList() { const selectKeypair = document.getElementById('select-keypair'); // Clear existing options while (selectKeypair.options.length > 1) { selectKeypair.remove(1); } try { // Get keypairs list const keypairs = list_keypairs(); // Add options for each keypair keypairs.forEach(keypairName => { const option = document.createElement('option'); option.value = keypairName; option.textContent = keypairName; selectKeypair.appendChild(option); }); // If there's a selected keypair, select it in the dropdown if (selectedKeypair) { selectKeypair.value = selectedKeypair; } } catch (e) { console.error('Error updating keypairs list:', e); } } // Select a keypair async function performSelectKeypair() { const keypairName = document.getElementById('select-keypair').value; if (!keypairName) { document.getElementById('keypair-management-result').textContent = 'Please select a keypair'; return; } try { // Select keypair const result = select_keypair(keypairName); if (result === 0) { selectedKeypair = keypairName; document.getElementById('keypair-management-result').textContent = `Selected keypair "${keypairName}"`; // Hide Ethereum wallet info when changing keypairs document.getElementById('ethereum-wallet-info').classList.add('hidden'); hasEthereumWallet = false; } else { document.getElementById('keypair-management-result').textContent = `Error selecting keypair: ${result}`; } } catch (e) { document.getElementById('keypair-management-result').textContent = `Error: ${e}`; } } // Create an Ethereum wallet from the selected keypair async function performCreateEthereumWallet() { if (!selectedKeypair) { document.getElementById('ethereum-wallet-result').textContent = 'Please select a keypair first'; return; } try { // Show loading state document.getElementById('ethereum-wallet-result').textContent = 'Creating wallet...'; // Create Ethereum wallet console.log('Creating Ethereum wallet from keypair:', selectedKeypair); const result = create_ethereum_wallet(); console.log('Create Ethereum wallet result:', result); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_address(); console.log('Generated Ethereum address:', address); document.getElementById('ethereum-address-value').textContent = address; // Get and display private key const privateKey = get_ethereum_private_key(); document.getElementById('ethereum-private-key-value').textContent = privateKey; // Show the wallet info document.getElementById('ethereum-wallet-info').classList.remove('hidden'); try { // Save the wallet to IndexedDB console.log('Saving wallet to IndexedDB:', address); await saveEthWalletToStorage(address, privateKey); console.log('Wallet saved successfully'); document.getElementById('ethereum-wallet-result').textContent = 'Successfully created Ethereum wallet'; } catch (saveError) { console.error('Error saving wallet to IndexedDB:', saveError); document.getElementById('ethereum-wallet-result').textContent = 'Wallet created but failed to save to storage'; } } else { document.getElementById('ethereum-wallet-result').textContent = `Error creating Ethereum wallet: ${result}`; } } catch (e) { console.error('Error in performCreateEthereumWallet:', e); document.getElementById('ethereum-wallet-result').textContent = `Error: ${e}`; } } // Create an Ethereum wallet from a name and the selected keypair async function performCreateEthereumWalletFromName() { if (!selectedKeypair) { document.getElementById('ethereum-wallet-result').textContent = 'Please select a keypair first'; return; } const name = document.getElementById('wallet-name').value.trim(); if (!name) { document.getElementById('ethereum-wallet-result').textContent = 'Please enter a name for derivation'; return; } try { // Show loading state document.getElementById('ethereum-wallet-result').textContent = 'Creating wallet...'; // Create Ethereum wallet from name console.log('Creating Ethereum wallet from name:', name); const result = create_ethereum_wallet_from_name(name); console.log('Create Ethereum wallet from name result:', result); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_address(); console.log('Generated Ethereum address:', address); document.getElementById('ethereum-address-value').textContent = address; // Get and display private key const privateKey = get_ethereum_private_key(); document.getElementById('ethereum-private-key-value').textContent = privateKey; // Show the wallet info document.getElementById('ethereum-wallet-info').classList.remove('hidden'); try { // Save the wallet to IndexedDB console.log('Saving wallet to IndexedDB:', address); await saveEthWalletToStorage(address, privateKey); console.log('Wallet saved successfully'); document.getElementById('ethereum-wallet-result').textContent = `Successfully created Ethereum wallet from name "${name}"`; } catch (saveError) { console.error('Error saving wallet to IndexedDB:', saveError); document.getElementById('ethereum-wallet-result').textContent = 'Wallet created but failed to save to storage'; } } else { document.getElementById('ethereum-wallet-result').textContent = `Error creating Ethereum wallet: ${result}`; } } catch (e) { console.error('Error in performCreateEthereumWalletFromName:', e); document.getElementById('ethereum-wallet-result').textContent = `Error: ${e}`; } } // Create an Ethereum wallet from a private key async function performCreateEthereumWalletFromPrivateKey() { const privateKey = document.getElementById('private-key').value.trim(); if (!privateKey) { document.getElementById('ethereum-wallet-result').textContent = 'Please enter a private key'; return; } try { // Show loading state document.getElementById('ethereum-wallet-result').textContent = 'Creating wallet...'; // Create Ethereum wallet from private key console.log('Creating Ethereum wallet from private key'); const result = create_ethereum_wallet_from_private_key(privateKey); console.log('Create Ethereum wallet from private key result:', result); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_address(); console.log('Generated Ethereum address:', address); document.getElementById('ethereum-address-value').textContent = address; // Get and display private key const displayPrivateKey = get_ethereum_private_key(); document.getElementById('ethereum-private-key-value').textContent = displayPrivateKey; // Show the wallet info document.getElementById('ethereum-wallet-info').classList.remove('hidden'); try { // Save the wallet to IndexedDB console.log('Saving wallet to IndexedDB:', address); await saveEthWalletToStorage(address, displayPrivateKey); console.log('Wallet saved successfully'); document.getElementById('ethereum-wallet-result').textContent = 'Successfully imported Ethereum wallet from private key'; } catch (saveError) { console.error('Error saving wallet to IndexedDB:', saveError); document.getElementById('ethereum-wallet-result').textContent = 'Wallet imported but failed to save to storage'; } } else { document.getElementById('ethereum-wallet-result').textContent = `Error importing Ethereum wallet: ${result}`; } } catch (e) { console.error('Error in performCreateEthereumWalletFromPrivateKey:', e); document.getElementById('ethereum-wallet-result').textContent = `Error: ${e}`; } } // Check the balance of an Ethereum address async function checkBalance() { if (!hasEthereumWallet) { document.getElementById('balance-result').textContent = 'Please create an Ethereum wallet first'; return; } try { const address = get_ethereum_address(); document.getElementById('balance-result').textContent = 'Checking balance...'; // Use the Ethereum Web3 API directly from JavaScript const response = await fetch(GNOSIS_RPC_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_getBalance', params: [address, 'latest'], id: 1, }), }); const data = await response.json(); if (data.error) { document.getElementById('balance-result').textContent = `Error: ${data.error.message}`; return; } const balanceHex = data.result; const formattedBalance = format_eth_balance(balanceHex); document.getElementById('balance-result').textContent = `Balance: ${formattedBalance}`; } catch (e) { document.getElementById('balance-result').textContent = `Error: ${e}`; } } // Copy text to clipboard function copyToClipboard(text, successMessage) { navigator.clipboard.writeText(text) .then(() => { alert(successMessage); }) .catch(err => { console.error('Could not copy text: ', err); }); } // Constants const GNOSIS_RPC_URL = "https://rpc.gnosis.gateway.fm"; const GNOSIS_EXPLORER = "https://gnosisscan.io"; async function run() { // Initialize the WebAssembly module await init(); console.log('WebAssembly crypto module initialized!'); // Set up the keypair selection document.getElementById('select-keypair').addEventListener('change', performSelectKeypair); // Set up the Ethereum wallet management document.getElementById('create-ethereum-wallet-button').addEventListener('click', performCreateEthereumWallet); document.getElementById('create-from-name-button').addEventListener('click', performCreateEthereumWalletFromName); document.getElementById('import-private-key-button').addEventListener('click', performCreateEthereumWalletFromPrivateKey); // Set up the copy buttons document.getElementById('copy-address-button').addEventListener('click', () => { const address = document.getElementById('ethereum-address-value').textContent; copyToClipboard(address, 'Ethereum address copied to clipboard!'); }); document.getElementById('copy-private-key-button').addEventListener('click', () => { const privateKey = document.getElementById('ethereum-private-key-value').textContent; copyToClipboard(privateKey, 'Private key copied to clipboard!'); }); // Set up the balance check document.getElementById('check-balance-button').addEventListener('click', checkBalance); // Initialize UI updateLoginUI(); } run().catch(console.error);