// 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; } // LocalStorage functions for key spaces const STORAGE_PREFIX = 'crypto_space_'; const ETH_WALLET_PREFIX = 'eth_wallet_'; // Save encrypted space to localStorage function saveSpaceToStorage(spaceName, encryptedData) { localStorage.setItem(`${STORAGE_PREFIX}${spaceName}`, encryptedData); } // Get encrypted space from localStorage function getSpaceFromStorage(spaceName) { return localStorage.getItem(`${STORAGE_PREFIX}${spaceName}`); } // Save Ethereum wallet to localStorage function saveEthWalletToStorage(address, privateKey) { localStorage.setItem(`${ETH_WALLET_PREFIX}${address}`, privateKey); } // Get Ethereum wallet from localStorage function getEthWalletFromStorage(address) { return localStorage.getItem(`${ETH_WALLET_PREFIX}${address}`); } // Session state let isLoggedIn = false; let currentSpace = null; let selectedKeypair = null; let hasEthereumWallet = false; // Update UI based on login state function updateLoginUI() { const loginForm = document.getElementById('login-form'); const logoutForm = document.getElementById('logout-form'); const loginStatus = document.getElementById('login-status'); const currentSpaceName = document.getElementById('current-space-name'); if (isLoggedIn) { loginForm.classList.add('hidden'); logoutForm.classList.remove('hidden'); loginStatus.textContent = 'Status: Logged in'; loginStatus.className = 'status logged-in'; currentSpaceName.textContent = currentSpace; } else { loginForm.classList.remove('hidden'); logoutForm.classList.add('hidden'); loginStatus.textContent = 'Status: Not logged in'; loginStatus.className = 'status logged-out'; currentSpaceName.textContent = ''; // 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); } } // Login to a space async function performLogin() { const spaceName = document.getElementById('space-name').value.trim(); const password = document.getElementById('space-password').value; if (!spaceName || !password) { document.getElementById('space-result').textContent = 'Please enter both space name and password'; return; } try { // Get encrypted space from localStorage const encryptedSpace = getSpaceFromStorage(spaceName); if (!encryptedSpace) { document.getElementById('space-result').textContent = `Space "${spaceName}" not found`; return; } // Decrypt the space const result = decrypt_key_space(encryptedSpace, password); if (result === 0) { isLoggedIn = true; currentSpace = spaceName; updateLoginUI(); updateKeypairsList(); document.getElementById('space-result').textContent = `Successfully logged in to space "${spaceName}"`; } else { document.getElementById('space-result').textContent = `Error logging in: ${result}`; } } catch (e) { document.getElementById('space-result').textContent = `Error: ${e}`; } } // Create a new space async function performCreateSpace() { const spaceName = document.getElementById('space-name').value.trim(); const password = document.getElementById('space-password').value; if (!spaceName || !password) { document.getElementById('space-result').textContent = 'Please enter both space name and password'; return; } // Check if space already exists if (getSpaceFromStorage(spaceName)) { document.getElementById('space-result').textContent = `Space "${spaceName}" already exists`; return; } try { // Create new space const result = create_key_space(spaceName); if (result === 0) { // Encrypt and save the space const encryptedSpace = encrypt_key_space(password); saveSpaceToStorage(spaceName, encryptedSpace); isLoggedIn = true; currentSpace = spaceName; updateLoginUI(); updateKeypairsList(); document.getElementById('space-result').textContent = `Successfully created space "${spaceName}"`; } else { document.getElementById('space-result').textContent = `Error creating space: ${result}`; } } catch (e) { document.getElementById('space-result').textContent = `Error: ${e}`; } } // Logout from current space function performLogout() { logout(); clear_ethereum_wallets(); isLoggedIn = false; currentSpace = null; selectedKeypair = null; hasEthereumWallet = false; updateLoginUI(); document.getElementById('space-result').textContent = 'Logged out successfully'; } // Create a new keypair async function performCreateKeypair() { if (!isLoggedIn) { document.getElementById('keypair-management-result').textContent = 'Please login first'; return; } const keypairName = document.getElementById('keypair-name').value.trim(); if (!keypairName) { document.getElementById('keypair-management-result').textContent = 'Please enter a keypair name'; return; } try { // Create new keypair const result = create_keypair(keypairName); if (result === 0) { document.getElementById('keypair-management-result').textContent = `Successfully created keypair "${keypairName}"`; // Update keypairs list updateKeypairsList(); // Select the new keypair selectedKeypair = keypairName; document.getElementById('select-keypair').value = keypairName; // Save the updated space to localStorage saveCurrentSpace(); } else { document.getElementById('keypair-management-result').textContent = `Error creating keypair: ${result}`; } } catch (e) { document.getElementById('keypair-management-result').textContent = `Error: ${e}`; } } // Select a keypair async function performSelectKeypair() { if (!isLoggedIn) { document.getElementById('keypair-management-result').textContent = 'Please login first'; return; } 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}`; } } // Save the current space to localStorage function saveCurrentSpace() { if (!isLoggedIn || !currentSpace) return; try { const password = document.getElementById('space-password').value; if (!password) { console.error('Password not available for saving space'); return; } const encryptedSpace = encrypt_key_space(password); saveSpaceToStorage(currentSpace, encryptedSpace); } catch (e) { console.error('Error saving space:', e); } } // Create an Ethereum wallet from the selected keypair async function performCreateEthereumWallet() { if (!isLoggedIn) { document.getElementById('ethereum-wallet-result').textContent = 'Please login first'; return; } if (!selectedKeypair) { document.getElementById('ethereum-wallet-result').textContent = 'Please select a keypair first'; return; } try { // Create Ethereum wallet const result = create_ethereum_wallet(); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_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'); // Save the wallet to localStorage saveEthWalletToStorage(address, privateKey); document.getElementById('ethereum-wallet-result').textContent = 'Successfully created Ethereum wallet'; // Save the updated space to localStorage saveCurrentSpace(); } else { document.getElementById('ethereum-wallet-result').textContent = `Error creating Ethereum wallet: ${result}`; } } catch (e) { document.getElementById('ethereum-wallet-result').textContent = `Error: ${e}`; } } // Create an Ethereum wallet from a name and the selected keypair async function performCreateEthereumWalletFromName() { if (!isLoggedIn) { document.getElementById('ethereum-wallet-result').textContent = 'Please login first'; return; } 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 { // Create Ethereum wallet from name const result = create_ethereum_wallet_from_name(name); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_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'); // Save the wallet to localStorage saveEthWalletToStorage(address, privateKey); document.getElementById('ethereum-wallet-result').textContent = `Successfully created Ethereum wallet from name "${name}"`; // Save the updated space to localStorage saveCurrentSpace(); } else { document.getElementById('ethereum-wallet-result').textContent = `Error creating Ethereum wallet: ${result}`; } } catch (e) { document.getElementById('ethereum-wallet-result').textContent = `Error: ${e}`; } } // Create an Ethereum wallet from a private key async function performCreateEthereumWalletFromPrivateKey() { if (!isLoggedIn) { document.getElementById('ethereum-wallet-result').textContent = 'Please login first'; return; } const privateKey = document.getElementById('private-key').value.trim(); if (!privateKey) { document.getElementById('ethereum-wallet-result').textContent = 'Please enter a private key'; return; } try { // Create Ethereum wallet from private key const result = create_ethereum_wallet_from_private_key(privateKey); if (result === 0) { hasEthereumWallet = true; // Get and display Ethereum address const address = get_ethereum_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'); // Save the wallet to localStorage saveEthWalletToStorage(address, displayPrivateKey); document.getElementById('ethereum-wallet-result').textContent = 'Successfully imported Ethereum wallet from private key'; // Save the updated space to localStorage saveCurrentSpace(); } else { document.getElementById('ethereum-wallet-result').textContent = `Error importing Ethereum wallet: ${result}`; } } catch (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 login/space management document.getElementById('login-button').addEventListener('click', performLogin); document.getElementById('create-space-button').addEventListener('click', performCreateSpace); document.getElementById('logout-button').addEventListener('click', performLogout); // Set up the keypair management document.getElementById('create-keypair-button').addEventListener('click', performCreateKeypair); 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);