hd-wallet-ui 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,8 @@
10
10
  * Revocation: [0x52][0x01][timestamp:4][txhash:32] = 38 bytes
11
11
  */
12
12
 
13
+ import { apiUrl } from './address-derivation.js';
14
+
13
15
  // =============================================================================
14
16
  // Trust Levels (PGP-style)
15
17
  // =============================================================================
@@ -41,6 +43,16 @@ const VERSION = 0x01;
41
43
  // Legacy ASCII prefixes
42
44
  const LEGACY_TRUST_PREFIX = 'TRUST';
43
45
  const LEGACY_REVOKE_PREFIX = 'REVOKE';
46
+ const SOLANA_TRUST_RPC_ENDPOINTS = [
47
+ 'https://solana-rpc.publicnode.com',
48
+ 'https://mainnet.helius-rpc.com/?api-key=1d8740dc-e5f4-421c-b823-e1bad1889eda',
49
+ 'https://api.mainnet-beta.solana.com',
50
+ ];
51
+ const SOLANA_TRUST_MAX_SIGNATURES = 40;
52
+ const SOLANA_TRUST_REQUEST_DELAY_MS = 350;
53
+ const SOLANA_TRUST_UNAVAILABLE_COOLDOWN_MS = 5 * 60 * 1000;
54
+ let _solanaTrustLastRequestAt = 0;
55
+ let _solanaTrustUnavailableUntil = 0;
44
56
 
45
57
  // =============================================================================
46
58
  // Binary Encoding Helpers
@@ -420,39 +432,80 @@ export async function scanBitcoinTrustTransactions(address) {
420
432
  * Uses RPC to get transactions with memo instructions.
421
433
  */
422
434
  export async function scanSolanaTrustTransactions(address) {
435
+ const isRateLimited = (msg) => {
436
+ const t = (msg || '').toLowerCase();
437
+ return t.includes('429') || t.includes('rate') || t.includes('limit') || t.includes('too many');
438
+ };
439
+ const isEndpointUnavailable = (msg) => {
440
+ const t = (msg || '').toLowerCase();
441
+ return t.includes('403') || t.includes('404') || t.includes('forbidden') || t.includes('not found');
442
+ };
443
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
444
+ const waitForThrottle = async () => {
445
+ const elapsed = Date.now() - _solanaTrustLastRequestAt;
446
+ if (elapsed < SOLANA_TRUST_REQUEST_DELAY_MS) {
447
+ await sleep(SOLANA_TRUST_REQUEST_DELAY_MS - elapsed);
448
+ }
449
+ _solanaTrustLastRequestAt = Date.now();
450
+ };
451
+ const solanaRpcCall = async (method, params) => {
452
+ let lastError = 'Unknown Solana RPC error';
453
+
454
+ for (const endpoint of SOLANA_TRUST_RPC_ENDPOINTS) {
455
+ try {
456
+ await waitForThrottle();
457
+ const response = await fetch(apiUrl(endpoint), {
458
+ method: 'POST',
459
+ headers: { 'Content-Type': 'application/json' },
460
+ body: JSON.stringify({
461
+ jsonrpc: '2.0',
462
+ id: 1,
463
+ method,
464
+ params,
465
+ }),
466
+ });
467
+
468
+ if (!response.ok) {
469
+ lastError = `HTTP ${response.status}`;
470
+ continue;
471
+ }
472
+
473
+ const data = await response.json();
474
+ if (data.error) {
475
+ lastError = data.error.message || 'Solana RPC returned error';
476
+ continue;
477
+ }
478
+
479
+ return { ok: true, result: data.result };
480
+ } catch (e) {
481
+ lastError = e?.message || 'Solana RPC fetch failed';
482
+ }
483
+ }
484
+
485
+ return { ok: false, error: lastError };
486
+ };
487
+
423
488
  try {
424
- const response = await fetch('https://api.mainnet-beta.solana.com', {
425
- method: 'POST',
426
- headers: { 'Content-Type': 'application/json' },
427
- body: JSON.stringify({
428
- jsonrpc: '2.0',
429
- id: 1,
430
- method: 'getSignaturesForAddress',
431
- params: [address, { limit: 100 }],
432
- }),
433
- });
489
+ if (Date.now() < _solanaTrustUnavailableUntil) {
490
+ return [];
491
+ }
434
492
 
435
- if (!response.ok) throw new Error('Failed to fetch Solana signatures');
436
- const data = await response.json();
437
- const signatures = data.result || [];
493
+ const sigResp = await solanaRpcCall('getSignaturesForAddress', [address, { limit: SOLANA_TRUST_MAX_SIGNATURES }]);
494
+ if (!sigResp.ok) {
495
+ if (isRateLimited(sigResp.error) || isEndpointUnavailable(sigResp.error)) {
496
+ _solanaTrustUnavailableUntil = Date.now() + SOLANA_TRUST_UNAVAILABLE_COOLDOWN_MS;
497
+ }
498
+ throw new Error(`Failed to fetch Solana signatures (${sigResp.error})`);
499
+ }
500
+
501
+ const signatures = Array.isArray(sigResp.result) ? sigResp.result : [];
438
502
 
439
503
  const trustTxs = [];
440
504
 
441
505
  for (const sig of signatures) {
442
- const txResponse = await fetch('https://api.mainnet-beta.solana.com', {
443
- method: 'POST',
444
- headers: { 'Content-Type': 'application/json' },
445
- body: JSON.stringify({
446
- jsonrpc: '2.0',
447
- id: 1,
448
- method: 'getTransaction',
449
- params: [sig.signature, { encoding: 'jsonParsed' }],
450
- }),
451
- });
452
-
453
- if (!txResponse.ok) continue;
454
- const txData = await txResponse.json();
455
- const tx = txData.result;
506
+ const txResp = await solanaRpcCall('getTransaction', [sig.signature, { encoding: 'jsonParsed' }]);
507
+ if (!txResp.ok) continue;
508
+ const tx = txResp.result;
456
509
 
457
510
  if (!tx || !tx.meta) continue;
458
511
 
@@ -477,7 +530,7 @@ export async function scanSolanaTrustTransactions(address) {
477
530
 
478
531
  return trustTxs;
479
532
  } catch (err) {
480
- console.error('Solana trust scan failed:', err);
533
+ console.warn('Solana trust scan skipped:', err.message || err);
481
534
  return [];
482
535
  }
483
536
  }
package/src/template.js CHANGED
@@ -6,65 +6,202 @@ export function getModalHTML() {
6
6
  <div class="modal-header"><div class="account-header-info"><div class="account-header-top"><h3>Account</h3><h3 class="account-total-value" id="account-total-value"></h3></div><div class="account-address-row"><span class="account-address-label">xpub</span><code class="account-address-display" id="account-address-display"></code><button class="account-address-copy" id="account-address-copy" title="Copy xpub"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div><button class="modal-close">&times;</button></div>
7
7
  <div class="modal-tabs">
8
8
  <button class="modal-tab active" data-modal-tab="vcard-tab-content">Identity</button>
9
- <button class="modal-tab" data-modal-tab="keys-tab-content">Keys</button>
10
9
  <button class="modal-tab" data-modal-tab="trust-tab-content">Trust Map</button>
11
- <button class="modal-tab" data-modal-tab="bond-tab-content">Bond</button>
12
10
  <button class="modal-tab" data-modal-tab="messaging-tab-content">Messaging</button>
11
+ <button class="modal-tab" data-modal-tab="wallet-tab-content">Wallet</button>
13
12
  </div>
14
13
  <div class="modal-body">
15
- <div id="keys-tab-content" class="modal-tab-content">
16
- <div id="memory-info-box" class="memory-info-box" style="display:none"><div class="memory-info-content"><p><strong>Your keys never leave your device.</strong></p></div><button class="wallet-info-close" id="memory-info-close" title="Close">&times;</button></div>
17
- <div class="xpub-section">
18
- <div class="xpub-header">
19
- <h4 class="section-label">Extended Public Key (xpub)</h4>
20
- <div class="wallet-info-icon-wrap" id="xpub-info-toggle" title="What is an xpub?"><svg viewBox="0 0 16 16"><circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="0.75"/><text x="8" y="8" text-anchor="middle" dominant-baseline="central" font-size="11" fill="currentColor">i</text></svg></div>
21
- <div class="memory-notice-row"><span class="memory-notice-label">Local Storage Only</span><div class="wallet-info-icon-wrap" id="memory-info-toggle" title="What does this mean?"><svg viewBox="0 0 16 16"><circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="0.75"/><text x="8" y="8" text-anchor="middle" dominant-baseline="central" font-size="11" fill="currentColor">i</text></svg></div></div>
14
+ <!-- Wallet Tab -->
15
+ <div id="wallet-tab-content" class="modal-tab-content">
16
+ <!-- Main Wallet View -->
17
+ <div id="wallet-main-view">
18
+ <!-- Portfolio Value (Phantom-style hero) -->
19
+ <div class="ph-portfolio">
20
+ <div class="ph-portfolio-value" id="wallet-bond-value">$0.00</div>
21
+ <div class="ph-portfolio-label">Total Balance</div>
22
+ <div class="ph-portfolio-xpub">
23
+ <code id="wallet-tab-xpub" class="ph-xpub-text truncate"></code>
24
+ <button class="ph-xpub-copy copy-key-btn" data-copy="wallet-tab-xpub" title="Copy xPub"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="wallet-selector-row">
29
+ <div class="wallet-selector-control">
30
+ <select id="wallet-active-select" class="glass-input compact wallet-selector-input"></select>
31
+ <button id="wallet-manage-btn" class="glass-btn small">Manage</button>
32
+ </div>
33
+ </div>
34
+
35
+ <!-- Action Buttons Row -->
36
+ <div class="ph-actions">
37
+ <button class="ph-action-btn" id="wallet-scan-btn">
38
+ <div class="ph-action-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></div>
39
+ <span>Scan</span>
40
+ </button>
41
+ <div class="ph-action-wrap" id="wallet-send-action">
42
+ <button class="ph-action-btn" id="wallet-send-btn">
43
+ <div class="ph-action-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></div>
44
+ <span>Send</span>
45
+ </button>
46
+ <div class="ph-action-menu" id="wallet-send-menu">
47
+ <button class="ph-action-menu-item" type="button" data-chain="BTC">Bitcoin (BTC)</button>
48
+ <button class="ph-action-menu-item" type="button" data-chain="ETH">Ethereum (ETH)</button>
49
+ <button class="ph-action-menu-item" type="button" data-chain="SOL">Solana (SOL)</button>
50
+ </div>
51
+ </div>
52
+ <div class="ph-action-wrap" id="wallet-receive-action">
53
+ <button class="ph-action-btn" id="wallet-receive-btn-main">
54
+ <div class="ph-action-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></div>
55
+ <span>Receive</span>
56
+ </button>
57
+ <div class="ph-action-menu" id="wallet-receive-menu">
58
+ <button class="ph-action-menu-item" type="button" data-chain="BTC">Bitcoin (BTC)</button>
59
+ <button class="ph-action-menu-item" type="button" data-chain="ETH">Ethereum (ETH)</button>
60
+ <button class="ph-action-menu-item" type="button" data-chain="SOL">Solana (SOL)</button>
61
+ </div>
62
+ </div>
63
+ <button class="ph-action-btn" id="wallet-export-btn-main">
64
+ <div class="ph-action-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg></div>
65
+ <span>Export</span>
66
+ </button>
67
+ <button class="ph-action-btn" id="wallet-advanced-btn-main">
68
+ <div class="ph-action-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg></div>
69
+ <span>Advanced</span>
70
+ </button>
71
+ </div>
72
+
73
+ <!-- Scan Status -->
74
+ <div id="wallet-scan-status" class="ph-scan-status" style="display:none;">
75
+ <div class="wallet-scan-spinner"></div>
76
+ <span id="wallet-scan-label">Scanning derivation paths...</span>
22
77
  </div>
23
- <div id="xpub-info-box" class="xpub-info-box" style="display:none"><div class="xpub-info-content"><p><strong>Your xpub is your public identity root.</strong></p></div><button class="wallet-info-close" id="xpub-info-close" title="Close">&times;</button></div>
24
- <div class="key-value-row">
25
- <code id="keys-xpub" class="key-value truncate"></code>
26
- <button class="copy-key-btn" data-copy="keys-xpub" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
78
+
79
+ <!-- Token List -->
80
+ <div id="wallet-accounts-list" class="ph-token-list">
81
+ <div class="ph-token-empty" id="wallet-accounts-empty">
82
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" opacity="0.25">
83
+ <rect x="2" y="6" width="20" height="12" rx="2"/><line x1="2" y1="12" x2="22" y2="12"/>
84
+ </svg>
85
+ <p>No tokens yet</p>
86
+ <p class="ph-token-empty-sub">Log in and tap Scan to discover your accounts</p>
87
+ </div>
27
88
  </div>
28
89
  </div>
29
- <div class="keys-section hd-section">
30
- <h4 class="section-label">HD Wallet Derivation (BIP44)</h4>
31
- <div class="hd-controls-row">
32
- <div class="hd-control-group"><label>Network</label>
33
- <select id="hd-coin" class="glass-select compact">
34
- <option value="0" data-symbol="BTC" data-name="Bitcoin">Bitcoin</option>
35
- <option value="60" data-symbol="ETH" data-name="Ethereum">Ethereum</option>
36
- <option value="501" data-symbol="SOL" data-name="Solana">Solana</option>
37
- <!-- Commented out — BTC/ETH/SOL only for now
38
- <option value="2" data-symbol="LTC" data-name="Litecoin">Litecoin</option>
39
- <option value="145" data-symbol="BCH" data-name="Bitcoin Cash">Bitcoin Cash</option>
40
- <option value="3" data-symbol="DOGE" data-name="Dogecoin">Dogecoin</option>
41
- <option value="118" data-symbol="ATOM" data-name="Cosmos">Cosmos</option>
42
- <option value="330" data-symbol="ALGO" data-name="Algorand">Algorand</option>
43
- <option value="354" data-symbol="DOT" data-name="Polkadot">Polkadot</option>
44
- <option value="1815" data-symbol="ADA" data-name="Cardano">Cardano</option>
45
- <option value="144" data-symbol="XRP" data-name="Ripple">Ripple (XRP)</option>
46
- -->
47
- </select>
90
+
91
+ <!-- Wallets View (replaces main view) -->
92
+ <div id="wallet-wallets-view" class="wallet-overlay-view" style="display:none;">
93
+ <div class="wallet-overlay-header wallet-wallets-header">
94
+ <div class="wallet-overlay-title-row">
95
+ <button id="wallet-wallets-back" class="wallet-back-btn"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Back</button>
96
+ <h4>Wallets</h4>
48
97
  </div>
49
- <div class="hd-control-group"><label>Account</label><input type="number" id="hd-account" class="glass-input compact hd-num-input" value="0" min="0" step="1"></div>
50
- <div class="hd-control-group"><label>Index</label><input type="number" id="hd-index" class="glass-input compact hd-num-input" value="0" min="0" step="1"></div>
98
+ <button id="wallet-new-btn" class="glass-btn small">+ New Wallet</button>
51
99
  </div>
52
- <div id="hd-not-initialized" class="hd-not-initialized" style="display: none;"><p>HD wallet not initialized. Please log in with a password or seed phrase.</p></div>
53
- <div id="derived-result" class="derived-result" style="display: none;">
54
- <div class="hd-key-row"><div class="hd-key-label">Signing</div><div class="hd-key-path"><code id="signing-path">m/44'/0'/0'/0'/0'</code></div><div class="hd-key-value"><code id="signing-pubkey" class="truncate"></code><button class="copy-btn" data-copy="signing-pubkey" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div>
55
- <div class="hd-key-row"><div class="hd-key-label">Encryption</div><div class="hd-key-path"><code id="encryption-path">m/44'/0'/0'/1'/0'</code></div><div class="hd-key-value"><code id="encryption-pubkey" class="truncate"></code><button class="copy-btn" data-copy="encryption-pubkey" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div>
56
- <div class="hd-address-row"><div class="hd-address-info"><span class="crypto-icon" id="derived-icon"></span><span class="crypto-name" id="derived-crypto-name">Bitcoin</span><code id="derived-address" class="hd-address"></code><a id="derived-explorer-link" href="#" target="_blank" class="explorer-link" title="View on Explorer"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg></a></div><div class="qr-section"><canvas id="address-qr" width="64" height="64"></canvas></div></div>
100
+ <div class="wallet-overlay-body">
101
+ <div class="wallet-manage-tabs" role="tablist" aria-label="Wallet status">
102
+ <button id="wallet-manage-tab-active" class="wallet-manage-tab active" type="button">Active</button>
103
+ <button id="wallet-manage-tab-inactive" class="wallet-manage-tab" type="button">Inactive</button>
104
+ </div>
105
+ <div class="settings-group">
106
+ <div id="wallet-list" class="wallet-name-list"></div>
107
+ </div>
57
108
  </div>
58
109
  </div>
59
- <details class="keys-section collapsible-section">
60
- <summary class="section-label collapsible-header"><span>HD Wallet Root</span></summary>
61
- <div class="collapsible-content">
62
- <div class="key-item"><label>Master Public Key (xpub)</label><div class="key-value-row"><code id="wallet-xpub" class="key-value truncate"></code><button class="copy-key-btn" data-copy="wallet-xpub" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
63
- <div class="key-item sensitive"><label>Master Private Key (xprv)</label><div class="key-value-row"><code id="wallet-xprv" class="key-value truncate blurred" data-revealed="false"></code><button class="reveal-key-btn" data-target="wallet-xprv" title="Reveal"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button><button class="copy-key-btn" data-copy="wallet-xprv" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
64
- <div class="key-item sensitive"><label>Seed Phrase (BIP39)</label><div class="key-value-row"><code id="wallet-seed-phrase" class="key-value seed-phrase blurred" data-revealed="false"></code><button class="reveal-key-btn" data-target="wallet-seed-phrase" title="Reveal"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button><button class="copy-key-btn" data-copy="wallet-seed-phrase" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
65
- <div class="export-section"><div class="export-dropdown"><button class="glass-btn small export-btn" id="export-wallet-btn"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Export Wallet</button><div class="export-menu" id="export-menu"><button class="export-option" data-format="mnemonic"><span class="export-label">BIP39 Mnemonic</span></button><button class="export-option" data-format="xpub"><span class="export-label">Extended Public Key</span></button><button class="export-option" data-format="xprv"><span class="export-label">Extended Private Key</span></button></div></div></div>
110
+
111
+ <!-- Export View (replaces main view) -->
112
+ <div id="wallet-export-view" class="wallet-overlay-view" style="display:none;">
113
+ <div class="wallet-overlay-header">
114
+ <button id="wallet-export-back" class="wallet-back-btn"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Back</button>
115
+ <h4>Export Wallet</h4>
66
116
  </div>
67
- </details>
117
+ <div class="wallet-overlay-body wallet-export-body">
118
+ <div class="settings-group">
119
+ <span class="settings-group-label">HD Wallet Root</span>
120
+ <div class="key-item"><label>Master Public Key (xpub)</label><div class="key-value-row"><code id="wallet-xpub" class="key-value truncate"></code><button class="copy-key-btn" data-copy="wallet-xpub" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
121
+ <div class="key-item sensitive"><label>Master Private Key (xprv)</label><div class="key-value-row"><code id="wallet-xprv" class="key-value truncate blurred" data-revealed="false"></code><button class="reveal-key-btn" data-target="wallet-xprv" title="Reveal"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button><button class="copy-key-btn" data-copy="wallet-xprv" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
122
+ <div class="key-item sensitive"><label>Seed Phrase (BIP39)</label><div class="key-value-row"><code id="wallet-seed-phrase" class="key-value seed-phrase blurred" data-revealed="false"></code><button class="reveal-key-btn" data-target="wallet-seed-phrase" title="Reveal"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button><button class="copy-key-btn" data-copy="wallet-seed-phrase" title="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button></div></div>
123
+ </div>
124
+ <div class="settings-group">
125
+ <span class="settings-group-label">Export Format</span>
126
+ <div class="wallet-export-options">
127
+ <button class="export-option export-option-card" data-format="mnemonic"><span class="export-label">BIP39 Mnemonic</span><span class="export-desc">12/24 word recovery phrase</span></button>
128
+ <button class="export-option export-option-card" data-format="xpub"><span class="export-label">Extended Public Key</span><span class="export-desc">Shareable watch-only root</span></button>
129
+ <button class="export-option export-option-card" data-format="xprv"><span class="export-label">Extended Private Key</span><span class="export-desc">Full access master private key</span></button>
130
+ <button class="export-option export-option-card" data-format="hex"><span class="export-label">Raw Seed (Hex)</span><span class="export-desc">Binary seed in hexadecimal</span></button>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+
136
+ <!-- Advanced View (replaces main view) -->
137
+ <div id="wallet-advanced-view" class="wallet-overlay-view" style="display:none;">
138
+ <div class="wallet-overlay-header">
139
+ <button id="wallet-advanced-back" class="wallet-back-btn"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Back</button>
140
+ <h4>Advanced</h4>
141
+ </div>
142
+ <div class="wallet-overlay-body">
143
+ <div class="settings-group">
144
+ <span class="settings-group-label">Advanced</span>
145
+ <div class="settings-custom-path">
146
+ <label>Wallet</label>
147
+ <div class="wallet-selected-path" id="custom-path-wallet-label"></div>
148
+ <label>Chain</label>
149
+ <select id="custom-path-chain" class="glass-input compact"><option value="0">BTC</option><option value="60">ETH</option><option value="501">SOL</option></select>
150
+ <label>Custom Derivation Path</label>
151
+ <div class="custom-path-row">
152
+ <input id="custom-path-input" class="glass-input compact" placeholder="m/44'/0'/0'/0/0">
153
+ <button id="custom-path-add" class="glass-btn small">Add</button>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+
160
+ <!-- Send View (replaces main view) -->
161
+ <div id="wallet-send-view" class="wallet-overlay-view" style="display:none;">
162
+ <div class="wallet-overlay-header">
163
+ <button id="wallet-send-back" class="wallet-back-btn"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Back</button>
164
+ <h4>Send</h4>
165
+ </div>
166
+ <div class="wallet-overlay-body">
167
+ <div id="send-compose-step">
168
+ <div class="send-field-group">
169
+ <label class="send-label">From</label>
170
+ <select id="send-from-account" class="glass-input"></select>
171
+ <div class="send-balance-display">Balance: <span id="send-available-balance">--</span></div>
172
+ </div>
173
+ <div class="send-field-group">
174
+ <label class="send-label">To Address</label>
175
+ <input id="send-to-address" class="glass-input" placeholder="Recipient address" autocomplete="off">
176
+ </div>
177
+ <div class="send-field-group">
178
+ <label class="send-label">Amount</label>
179
+ <div class="send-amount-row">
180
+ <input id="send-amount" class="glass-input" type="number" step="any" min="0" placeholder="0.00">
181
+ <span class="send-currency-label" id="send-currency-label">BTC</span>
182
+ <button id="send-max-btn" class="glass-btn small">Max</button>
183
+ </div>
184
+ <div class="send-fiat-estimate" id="send-fiat-estimate"></div>
185
+ </div>
186
+ <div class="send-fee-display" id="send-fee-section" style="display:none;">
187
+ <span class="send-label">Estimated Fee</span>
188
+ <span id="send-fee-estimate">--</span>
189
+ </div>
190
+ <button id="send-review-btn" class="glass-btn primary full-width" disabled>Review Transaction</button>
191
+ </div>
192
+ <div id="send-review-step" style="display:none;">
193
+ <div class="send-review-card">
194
+ <div class="send-review-row"><span>To</span><code id="send-review-to" class="truncate"></code></div>
195
+ <div class="send-review-row"><span>Amount</span><span id="send-review-amount"></span></div>
196
+ <div class="send-review-row"><span>Network Fee</span><span id="send-review-fee"></span></div>
197
+ <div class="send-review-row send-review-total"><span>Total</span><span id="send-review-total"></span></div>
198
+ </div>
199
+ <button id="send-confirm-btn" class="glass-btn primary full-width">Confirm & Send</button>
200
+ <button id="send-edit-btn" class="glass-btn full-width">Edit</button>
201
+ <div id="send-status" class="send-status" style="display:none;"></div>
202
+ </div>
203
+ </div>
204
+ </div>
68
205
  </div>
69
206
  <div id="vcard-tab-content" class="modal-tab-content active">
70
207
  <div id="vcard-form-view">
@@ -272,34 +409,6 @@ export function getModalHTML() {
272
409
  </div>
273
410
  </div>
274
411
 
275
- <!-- Security Bond Tab -->
276
- <div id="bond-tab-content" class="modal-tab-content">
277
- <div class="bond-intro">
278
- <h4 class="section-label">Trust Proof</h4>
279
- <p>Holding value on your keys signals commitment and reduces Sybil risk. Your total balance across all networks serves as proof of stake in the trust network.</p>
280
- </div>
281
- <div class="bond-networks-grid">
282
- <div class="bond-network-card" id="bond-btc-card">
283
- <div class="bond-net-header"><span class="bond-net-name">Bitcoin</span><span class="bond-net-balance" id="bond-btc-balance">--</span></div>
284
- <a href="#" id="bond-btc-explorer" class="bond-net-address" target="_blank" rel="noopener"><code id="bond-btc-address">--</code></a>
285
- </div>
286
- <div class="bond-network-card" id="bond-eth-card">
287
- <div class="bond-net-header"><span class="bond-net-name">Ethereum</span><span class="bond-net-balance" id="bond-eth-balance">--</span></div>
288
- <a href="#" id="bond-eth-explorer" class="bond-net-address" target="_blank" rel="noopener"><code id="bond-eth-address">--</code></a>
289
- </div>
290
- <div class="bond-network-card" id="bond-sol-card">
291
- <div class="bond-net-header"><span class="bond-net-name">Solana</span><span class="bond-net-balance" id="bond-sol-balance">--</span></div>
292
- <a href="#" id="bond-sol-explorer" class="bond-net-address" target="_blank" rel="noopener"><code id="bond-sol-address">--</code></a>
293
- </div>
294
- <!-- Commented out — BTC/ETH/SOL only for now
295
- <div class="bond-network-card" id="bond-sui-card">...</div>
296
- <div class="bond-network-card" id="bond-monad-card">...</div>
297
- <div class="bond-network-card" id="bond-ada-card">...</div>
298
- <div class="bond-network-card" id="bond-xrp-card">...</div>
299
- -->
300
- </div>
301
- </div>
302
-
303
412
  <!-- Messaging Tab (Encrypt + Decrypt) -->
304
413
  <div id="messaging-tab-content" class="modal-tab-content">
305
414
  <div class="messaging-sub-tabs">