const fallbackDashboard = {
active_account: {
name: 'Main Wallet',
address: '0x1111111111111111111111111111111111111111',
source: 'SeedPhrase'
},
chains: [
{ id: 1, name: 'Ethereum' },
{ id: 8453, name: 'Base' }
],
balances: [
{ chain_id: 1, symbol: 'ETH', amount: 1.24, usd_value: 4200 },
{ chain_id: 8453, symbol: 'USDC', amount: 1280, usd_value: 1280 }
],
approvals: [
{ chain_id: 1, asset_symbol: 'USDC', spender: '0x2222222222222222222222222222222222222222', allowance: 'unlimited', risk: 'High' }
],
activities: [
{ label: 'Swap ETH → USDC', status: 'Confirmed', chain_id: 1 }
],
settings: {
theme: 'System',
language: 'en',
currency: 'USD',
auto_lock_minutes: 15,
prefer_rabby_over_metamask: true
}
};
const fallbackFeatures = [
['Create/unlock wallet', 'Password, lock/unlock, encrypted local state', 'RuntimeImplemented'],
['Import/create accounts', 'Seed phrase, private key, JSON, watch-only', 'Modeled'],
['Multi-chain networks', 'Built-in, custom RPC, testnet, offline chain flags', 'Modeled'],
['Portfolio dashboard', 'Balances, NFTs, DeFi positions, activity', 'UiPrototype'],
['Dapp provider and permissions', 'Origin/account/chain permissions', 'Modeled'],
['Signing and security previews', 'Typed data/message/transaction previews and risk', 'Modeled'],
['Settings and customization', 'Theme, language, currency, auto-lock, default wallet mode', 'UiPrototype']
];
function money(value) {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value || 0);
}
function shortAddress(address) {
if (!address || address.length < 12) return address || '';
return `${address.slice(0, 6)}…${address.slice(-4)}`;
}
function statusLabel(value) {
if (typeof value === 'string') return value;
if (value && typeof value === 'object') return Object.keys(value)[0] || 'Modeled';
return 'Modeled';
}
async function invokeOrFallback(command, fallback) {
try {
const tauri = window.__TAURI__?.core;
if (!tauri) return fallback;
return await tauri.invoke(command);
} catch (_) {
return fallback;
}
}
function renderDashboard(dashboard) {
const total = dashboard.balances.reduce((sum, token) => sum + token.usd_value, 0);
const highRisk = dashboard.approvals.filter((approval) => ['High', 'Critical'].includes(statusLabel(approval.risk))).length;
document.getElementById('account-address').textContent = shortAddress(dashboard.active_account.address);
document.getElementById('portfolio-total').textContent = money(total);
document.getElementById('hero-total').textContent = money(total);
document.getElementById('chain-count').textContent = dashboard.chains.length;
document.getElementById('risk-count').textContent = highRisk;
document.getElementById('approval-risk').textContent = highRisk;
document.getElementById('token-list').innerHTML = dashboard.balances.map((token) => `
${token.symbol.slice(0, 1)}
${token.symbol}Chain ${token.chain_id}
${money(token.usd_value)}${token.amount}
`).join('');
document.getElementById('approval-list').innerHTML = dashboard.approvals.map((approval) => `
${approval.asset_symbol} allowance${shortAddress(approval.spender)}
${statusLabel(approval.risk)}
`).join('');
document.getElementById('activity-list').innerHTML = dashboard.activities.map((activity) => `
↗${activity.label}${statusLabel(activity.status)} · Chain ${activity.chain_id}
`).join('');
const settings = dashboard.settings;
document.getElementById('settings-summary').innerHTML = [
['Theme', statusLabel(settings.theme)],
['Language', settings.language],
['Currency', settings.currency],
['Auto-lock', `${settings.auto_lock_minutes} min`],
['Default wallet', settings.prefer_rabby_over_metamask ? 'Rabby' : 'Browser default']
].map(([label, value]) => `${label}${value}
`).join('');
}
function renderFeatures(features) {
document.getElementById('wallet-features').innerHTML = features.map((feature) => {
const title = Array.isArray(feature) ? feature[0] : feature.feature;
const acceptance = Array.isArray(feature) ? feature[1] : feature.acceptance;
const status = Array.isArray(feature) ? feature[2] : statusLabel(feature.status);
return `
${status}
${title}
${acceptance}
`;
}).join('');
}
async function saveDemoVault() {
const passphrase = document.getElementById('vault-passphrase').value;
const output = document.getElementById('vault-status');
output.textContent = 'Encrypting demo vault…';
try {
const tauri = window.__TAURI__?.core;
if (!tauri) throw new Error('Tauri bridge unavailable in browser preview');
const status = await tauri.invoke('save_demo_wallet_vault', { passphrase, path: null });
output.textContent = `Encrypted with ${status.cipher} + ${status.kdf}: ${status.path}`;
} catch (error) {
output.textContent = String(error);
}
}
function wireVaultActions() {
const button = document.getElementById('save-vault');
if (button) button.addEventListener('click', saveDemoVault);
}
async function loadAppConfig() {
return invokeOrFallback('load_app_config', { theme_id: 'rabby-light', restore_workspace: true, profiles: [], shortcuts: [] });
}
async function saveSettings() {
const theme = document.getElementById('theme-select').value;
const output = document.getElementById('settings-status');
output.textContent = 'Saving settings…';
try {
const tauri = window.__TAURI__?.core;
if (!tauri) throw new Error('Tauri bridge unavailable in browser preview');
const config = await loadAppConfig();
config.theme_id = theme;
const saved = await tauri.invoke('save_app_config', { config, path: null });
output.textContent = `Saved ${saved.theme_id}`;
} catch (error) {
output.textContent = String(error);
}
}
function wireSettingsActions() {
const button = document.getElementById('save-settings');
if (button) button.addEventListener('click', saveSettings);
}
async function runLocalTerminalCommand() {
const command = document.getElementById('terminal-command').value;
const output = document.getElementById('terminal-output');
output.textContent = 'Running…';
try {
const tauri = window.__TAURI__?.core;
if (!tauri) throw new Error('Tauri bridge unavailable in browser preview');
const result = await tauri.invoke('run_local_command', { command, cwd: null });
output.textContent = [
`$ ${command}`,
`exit ${result.exit_code}`,
result.stdout ? `stdout:\n${result.stdout}` : '',
result.stderr ? `stderr:\n${result.stderr}` : ''
].filter(Boolean).join('\n');
} catch (error) {
output.textContent = String(error);
}
}
function wireTerminalActions() {
const button = document.getElementById('run-terminal');
if (button) button.addEventListener('click', runLocalTerminalCommand);
}
async function boot() {
const [dashboard, features] = await Promise.all([
invokeOrFallback('wallet_dashboard', fallbackDashboard),
invokeOrFallback('wallet_mvp_summary', fallbackFeatures)
]);
renderDashboard(dashboard);
renderFeatures(features);
wireVaultActions();
wireSettingsActions();
wireTerminalActions();
}
boot();