OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-wallet-desktop commits / a620877

Fix: unified Ethereum view - better loading, send modal display, error resilience
Deployment: testing (hyper-wallet-desktop-test) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
a6208778b3e380c4f9b7b0cfa95049b40d7c0227
by plankatron <fleeky@gmail.com> · 2026-01-30T01:57:09.000Z

Changed files (3) +102 -24

.claude/deployment-history.json +10 -0
……@@ -0,0 +1,10 @@
1{
2 "mode": "testing",
3 "channel": "hyper-wallet-desktop-test",
4 "branch": "testing",
5 "version": "unknown",
6 "pear_key": "pear://unknown",
7 "deployed_at": "2026-01-29T20:47:59-05:00",
8 "commit_message": "USDT refactor: unified Ethereum view, Bitcoin sync fix, Alchemy token support",
9 "tmux": "pear-seed:5"
10}
desktop/wallet.js +79 -20
……@@ -1746,7 +1746,21 @@ async function loadCurrentBalance() {
17461746// Load unified Ethereum balances (ETH + USDT + USDC)
17471747async function loadEthereumBalances() {
17481748 const container = document.getElementById('wallet-balance-display')
1749 container.innerHTML = '<div class="spinner"></div>'
1749
1750 // Show loading with asset placeholders
1751 container.innerHTML = `
1752 <div class="unified-balance">
1753 <div class="total-value">
1754 <span class="total-usd">Loading...</span>
1755 <span class="total-label">Total Balance</span>
1756 </div>
1757 <div class="asset-list">
1758 <div class="asset-row"><span class="asset-icon">Ξ</span><span class="asset-name">ETH</span><span class="asset-balance">...</span></div>
1759 <div class="asset-row"><span class="asset-icon">₮</span><span class="asset-name">USDT</span><span class="asset-balance">...</span></div>
1760 <div class="asset-row"><span class="asset-icon">$</span><span class="asset-name">USDC</span><span class="asset-balance">...</span></div>
1761 </div>
1762 </div>
1763 `
17501764
17511765 try {
17521766 const res = await authFetch(`/api/balances/ethereum`)
……@@ -1759,20 +1773,29 @@ async function loadEthereumBalances() {
17591773
17601774 const { balances } = data
17611775
1762 const ethAmount = Number(balances.eth.balance) / 1e18
1763 const usdtAmount = Number(balances.usdt.balance) / 1e6
1764 const usdcAmount = Number(balances.usdc.balance) / 1e6
1776 // Handle missing balances gracefully
1777 const ethBalance = balances?.eth?.balance || '0'
1778 const usdtBalance = balances?.usdt?.balance || '0'
1779 const usdcBalance = balances?.usdc?.balance || '0'
17651780
1766 const ethUsd = ethAmount * (prices.ethereum || 0)
1767 const usdtUsd = usdtAmount * (prices.tether || 1)
1768 const usdcUsd = usdcAmount * (prices['usd-coin'] || 1)
1781 const ethAmount = Number(ethBalance) / 1e18
1782 const usdtAmount = Number(usdtBalance) / 1e6
1783 const usdcAmount = Number(usdcBalance) / 1e6
1784
1785 // Use testnet-appropriate USD values (show 0 for testnet)
1786 const isTestnet = selectedNetwork === 'testnet'
1787 const ethUsd = isTestnet ? 0 : ethAmount * (prices.ethereum || 0)
1788 const usdtUsd = isTestnet ? 0 : usdtAmount * (prices.tether || 1)
1789 const usdcUsd = isTestnet ? 0 : usdcAmount * (prices['usd-coin'] || 1)
17691790 const totalUsd = ethUsd + usdtUsd + usdcUsd
17701791
1792 const totalDisplay = isTestnet ? 'Testnet' : formatUSD(totalUsd)
1793
17711794 container.innerHTML = `
17721795 <div class="unified-balance">
17731796 <div class="total-value">
1774 <span class="total-usd">${formatUSD(totalUsd)}</span>
1775 <span class="total-label">Total Balance</span>
1797 <span class="total-usd">${totalDisplay}</span>
1798 <span class="total-label">${isTestnet ? 'Sepolia Testnet' : 'Total Balance'}</span>
17761799 </div>
17771800
17781801 <div class="asset-list">
……@@ -1781,7 +1804,7 @@ async function loadEthereumBalances() {
17811804 <span class="asset-icon">Ξ</span>
17821805 <span class="asset-name">ETH</span>
17831806 <span class="asset-balance">${ethAmount.toFixed(6)}</span>
1784 <span class="asset-usd">${formatUSD(ethUsd)}</span>
1807 <span class="asset-usd">${isTestnet ? '' : formatUSD(ethUsd)}</span>
17851808 </div>
17861809
17871810 <div class="asset-row ${selectedAsset === 'usdt' ? 'selected' : ''}"
……@@ -1789,7 +1812,7 @@ async function loadEthereumBalances() {
17891812 <span class="asset-icon">₮</span>
17901813 <span class="asset-name">USDT</span>
17911814 <span class="asset-balance">${usdtAmount.toFixed(2)}</span>
1792 <span class="asset-usd">${formatUSD(usdtUsd)}</span>
1815 <span class="asset-usd">${isTestnet ? '' : formatUSD(usdtUsd)}</span>
17931816 </div>
17941817
17951818 <div class="asset-row ${selectedAsset === 'usdc' ? 'selected' : ''}"
……@@ -1797,20 +1820,25 @@ async function loadEthereumBalances() {
17971820 <span class="asset-icon">$</span>
17981821 <span class="asset-name">USDC</span>
17991822 <span class="asset-balance">${usdcAmount.toFixed(2)}</span>
1800 <span class="asset-usd">${formatUSD(usdcUsd)}</span>
1823 <span class="asset-usd">${isTestnet ? '' : formatUSD(usdcUsd)}</span>
18011824 </div>
18021825 </div>
18031826
18041827 ${ethAmount < 0.001 ? `
18051828 <div class="gas-warning">
1806 ⚠️ Low ETH balance - needed for gas fees
1829 ⚠️ Low ETH - needed for gas fees to send tokens
18071830 </div>
18081831 ` : ''}
18091832 </div>
18101833 `
18111834 } catch (err) {
18121835 console.error('Load balances error:', err)
1813 container.innerHTML = '<span class="error">Failed to load balances</span>'
1836 container.innerHTML = `
1837 <div class="unified-balance">
1838 <div class="error">Failed to load balances</div>
1839 <button onclick="loadEthereumBalances()" class="btn-secondary">Retry</button>
1840 </div>
1841 `
18141842 }
18151843}
18161844
……@@ -2686,12 +2714,36 @@ function closeTxDetails() {
26862714async function showSend(chain) {
26872715 currentSendChain = chain
26882716 const modal = document.getElementById('send-modal')
2689 const chainName = chain.charAt(0).toUpperCase() + chain.slice(1)
2717
2718 // Get proper display name for chain/token
2719 let displayName, unit, decimals
2720 if (chain === 'ethereum-usdt') {
2721 displayName = 'USDT'
2722 unit = 'USDT'
2723 decimals = 6
2724 } else if (chain === 'ethereum-usdc') {
2725 displayName = 'USDC'
2726 unit = 'USDC'
2727 decimals = 6
2728 } else if (chain === 'ethereum') {
2729 displayName = 'Ethereum'
2730 unit = 'ETH'
2731 decimals = 18
2732 } else if (chain === 'bitcoin') {
2733 displayName = 'Bitcoin'
2734 unit = 'sats'
2735 decimals = 0
2736 } else {
2737 displayName = chain.charAt(0).toUpperCase() + chain.slice(1)
2738 unit = chain
2739 decimals = 18
2740 }
2741
26902742 const networkLabel = selectedNetwork === 'testnet'
2691 ? (chain === 'ethereum' ? 'Sepolia' : 'Testnet')
2743 ? (chain.startsWith('ethereum') ? 'Sepolia' : 'Testnet')
26922744 : 'Mainnet'
26932745
2694 document.getElementById('send-chain').textContent = `${chainName} (${networkLabel})`
2746 document.getElementById('send-chain').textContent = `${displayName} (${networkLabel})`
26952747
26962748 // Reset form
26972749 document.getElementById('send-to').value = ''
……@@ -2712,9 +2764,16 @@ async function showSend(chain) {
27122764 const data = await res.json()
27132765 currentBalance = Number(data.balance)
27142766
2715 const unit = chain === 'bitcoin' ? 'sats' : 'wei'
2716 document.getElementById('send-amount-helper').textContent =
2717 `Balance: ${currentBalance.toLocaleString()} ${unit}`
2767 // Format balance based on decimals
2768 let balanceDisplay
2769 if (chain === 'bitcoin') {
2770 balanceDisplay = `${currentBalance.toLocaleString()} sats`
2771 } else if (decimals === 6) {
2772 balanceDisplay = `${(currentBalance / 1e6).toFixed(2)} ${unit}`
2773 } else {
2774 balanceDisplay = `${(currentBalance / 1e18).toFixed(6)} ${unit}`
2775 }
2776 document.getElementById('send-amount-helper').textContent = `Balance: ${balanceDisplay}`
27182777 } catch (err) {
27192778 console.error('Failed to load balance:', err)
27202779 document.getElementById('send-amount-helper').textContent = 'Balance: unavailable'
wallet-server.cjs +13 -4
……@@ -460,11 +460,20 @@ const routes = {
460460 const account = await wdk.getAccount('ethereum', accountIndex)
461461 const address = await account.getAddress()
462462
463 // Fetch all balances in parallel
463 // Fetch balances with error handling for each
464 const fetchBalance = async (fn, label) => {
465 try {
466 return await fn()
467 } catch (err) {
468 console.error(`Failed to fetch ${label} balance:`, err.message)
469 return BigInt(0)
470 }
471 }
472
464473 const [ethBalance, usdtBalance, usdcBalance] = await Promise.all([
465 account.getBalance(),
466 account.getTokenBalance(TOKEN_CONTRACTS['ethereum-usdt'].testnet),
467 account.getTokenBalance(TOKEN_CONTRACTS['ethereum-usdc'].testnet)
474 fetchBalance(() => account.getBalance(), 'ETH'),
475 fetchBalance(() => account.getTokenBalance(TOKEN_CONTRACTS['ethereum-usdt'].testnet), 'USDT'),
476 fetchBalance(() => account.getTokenBalance(TOKEN_CONTRACTS['ethereum-usdc'].testnet), 'USDC')
468477 ])
469478
470479 sendJSON(res, {