const app = document.getElementById('app'); let pendingMnemonic = null; // held briefly in renderer memory during onboarding only let accounts = null; async function boot() { const hasKeystore = await window.macu.hasKeystore(); hasKeystore ? renderUnlock() : renderWelcome(); } // ---------- Welcome / choose create vs import ---------- function renderWelcome() { app.innerHTML = `

Welcome to macu

A non-custodial wallet. Your keys are generated and encrypted on this device only — macu never sees them, and there's no account recovery if you lose your recovery phrase and password.

`; document.getElementById('btn-create').onclick = startCreate; document.getElementById('btn-import').onclick = renderImport; } // ---------- Create: generate + show backup phrase ---------- async function startCreate() { pendingMnemonic = await window.macu.generateMnemonic(); renderBackup(); } function renderBackup() { const words = pendingMnemonic.split(' '); app.innerHTML = `

Your recovery phrase

Write these 24 words down in order and store them somewhere safe and offline. Anyone with this phrase can access your funds on every chain — including you, if you lose it.

macu cannot recover this for you. There is no "forgot password" for a recovery phrase.
${words.map((w, i) => `
${i + 1}${w}
`).join('')}
`; document.getElementById('btn-saved').onclick = renderSetPassword; } // ---------- Import: paste existing phrase ---------- function renderImport() { app.innerHTML = `

Import wallet

Enter your existing 12 or 24-word recovery phrase, separated by spaces.

`; document.getElementById('btn-back').onclick = renderWelcome; document.getElementById('btn-continue').onclick = () => { const value = document.getElementById('mnemonic-input').value.trim(); if (value.split(/\s+/).length < 12) { document.getElementById('import-error').textContent = 'That phrase looks too short — check the word count.'; return; } pendingMnemonic = value; renderSetPassword(); }; } // ---------- Set a password to encrypt the phrase at rest ---------- function renderSetPassword() { app.innerHTML = `

Set a password

This encrypts your recovery phrase on this device. You'll need it every time you open macu.

`; document.getElementById('btn-finish').onclick = async () => { const pw1 = document.getElementById('pw1').value; const pw2 = document.getElementById('pw2').value; const errEl = document.getElementById('pw-error'); if (pw1.length < 8) { errEl.textContent = 'Use at least 8 characters.'; return; } if (pw1 !== pw2) { errEl.textContent = 'Passwords do not match.'; return; } try { accounts = await window.macu.createWallet(pendingMnemonic, pw1); pendingMnemonic = null; // drop it from renderer memory as soon as we're done with it renderDashboard(); } catch (e) { errEl.textContent = e.message; } }; } // ---------- Unlock existing keystore ---------- function renderUnlock() { app.innerHTML = `

Welcome back

Enter your password to unlock macu.

`; const tryUnlock = async () => { const pw = document.getElementById('unlock-pw').value; const errEl = document.getElementById('unlock-error'); try { accounts = await window.macu.unlock(pw); renderDashboard(); } catch (e) { errEl.textContent = e.message; } }; document.getElementById('btn-unlock').onclick = tryUnlock; document.getElementById('unlock-pw').addEventListener('keydown', (e) => { if (e.key === 'Enter') tryUnlock(); }); } // ---------- Dashboard ---------- async function renderDashboard() { app.innerHTML = `
macu
${chainCard('Ethereum', accounts.ethereum.address)} ${chainCard('Bitcoin', accounts.bitcoin.address)} ${chainCard('Solana', accounts.solana.address)}

Send ETH

`; document.getElementById('btn-lock').onclick = async () => { await window.macu.lock(); accounts = null; renderUnlock(); }; document.querySelectorAll('.address').forEach((el) => { el.onclick = () => navigator.clipboard.writeText(el.dataset.full); }); document.getElementById('btn-send').onclick = async () => { const to = document.getElementById('send-to').value.trim(); const amt = document.getElementById('send-amt').value.trim(); const statusEl = document.getElementById('send-status'); statusEl.className = 'status-msg'; statusEl.textContent = 'Sending…'; try { const { hash } = await window.macu.sendEth(to, amt); statusEl.className = 'status-msg ok'; statusEl.textContent = `Sent. Tx hash: ${hash}`; } catch (e) { statusEl.className = 'status-msg err'; statusEl.textContent = e.message; } }; loadBalances(); } function chainCard(label, address) { const short = address.length > 14 ? `${address.slice(0, 8)}…${address.slice(-6)}` : address; return `
${label}
${short}
`; } async function loadBalances() { try { const bal = await window.macu.getBalances(); setBalance('ethereum', bal.ethereum, 'ETH'); setBalance('bitcoin', bal.bitcoin, 'BTC'); setBalance('solana', bal.solana, 'SOL'); } catch (e) { console.error(e); } } function setBalance(chain, value, symbol) { const el = document.querySelector(`[data-balance="${chain}"]`); if (!el) return; el.textContent = value === null ? 'Unavailable' : `${Number(value).toFixed(4)} ${symbol}`; } boot();