diff --git a/modules/rwallet/components/folk-wallet-viewer.ts b/modules/rwallet/components/folk-wallet-viewer.ts index 1295d11..38f2812 100644 --- a/modules/rwallet/components/folk-wallet-viewer.ts +++ b/modules/rwallet/components/folk-wallet-viewer.ts @@ -800,13 +800,29 @@ class FolkWalletViewer extends HTMLElement { const incoming: any[] = []; const outgoing: any[] = []; const results = data.results || []; + const addr = this.address.toLowerCase(); for (const tx of results) { + // Outgoing: Safe-initiated multisig transactions if (tx.txType === "MULTISIG_TRANSACTION") { outgoing.push(tx); } + // Incoming: external ETH/token transfers to Safe + if (tx.txType === "ETHEREUM_TRANSACTION") { + if (tx.from && tx.value && tx.value !== "0") { + incoming.push({ + type: "ETHER_TRANSFER", + from: tx.from, + to: this.address, + value: tx.value, + executionDate: tx.executionDate, + blockTimestamp: tx.executionDate, + }); + } + } + // Embedded transfers (both tx types may have these) if (tx.transfers) { for (const t of tx.transfers) { - if (t.to?.toLowerCase() === this.address.toLowerCase()) { + if (t.to?.toLowerCase() === addr && t.from?.toLowerCase() !== addr) { incoming.push(t); } } @@ -2606,7 +2622,13 @@ class FolkWalletViewer extends HTMLElement { } const sorted = allBals - .filter(b => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n) + .filter(b => { + const fiat = parseFloat(b.fiatBalance || "0"); + if (fiat > 0.01) return true; + if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true; + if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true; + return false; + }) .sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0")); const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0); @@ -2679,7 +2701,13 @@ class FolkWalletViewer extends HTMLElement { } const sorted = allBals - .filter(b => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n) + .filter(b => { + const fiat = parseFloat(b.fiatBalance || "0"); + if (fiat > 0.01) return true; + if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true; + if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true; + return false; + }) .sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0")); const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0); @@ -2732,8 +2760,9 @@ class FolkWalletViewer extends HTMLElement { for (const ch of chains) { totalChains.add(ch.chainId); for (const b of ch.balances) { - if (parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n) { - grandTotal += parseFloat(b.fiatBalance || "0"); + const fiat = parseFloat(b.fiatBalance || "0"); + if (fiat > 0.01 || (!b.tokenAddress && BigInt(b.balance || "0") > 0n)) { + grandTotal += fiat; totalTokens++; } } @@ -3047,7 +3076,13 @@ class FolkWalletViewer extends HTMLElement { if (unified.length === 0) return '
No token balances found.
'; const sorted = unified - .filter((b) => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n) + .filter((b) => { + const fiat = parseFloat(b.fiatBalance || "0"); + if (fiat > 0.01) return true; + if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true; + if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true; + return false; + }) .sort((a, b) => { const fiatDiff = parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"); if (fiatDiff !== 0) return fiatDiff; @@ -3253,7 +3288,13 @@ class FolkWalletViewer extends HTMLElement { // Aggregate stats across ALL chains (ignoring filter) const allBalances = this.getUnifiedBalances(true); const totalUSD = allBalances.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0); - const totalTokens = allBalances.filter((b) => parseFloat(b.fiatBalance || "0") > 0 || BigInt(b.balance || "0") > 0n).length; + const totalTokens = allBalances.filter((b) => { + const fiat = parseFloat(b.fiatBalance || "0"); + if (fiat > 0.01) return true; + if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true; + if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true; + return false; + }).length; // Build chain buttons with "All" filter const chainButtons = this.detectedChains.map((ch) => { @@ -3305,8 +3346,6 @@ class FolkWalletViewer extends HTMLElement { ` : ""} - ${this.renderViewTabs()} - ${this.activeView === "balances" ? this.renderBalanceTable() + this.renderDefiPositions() + this.renderPaymentActions() : `
@@ -3500,13 +3539,7 @@ class FolkWalletViewer extends HTMLElement { this.addToWatchlist(addr, chain, label); }); - // View tab listeners (skip tour button which has no data-view) - this.shadow.querySelectorAll(".view-tab[data-view]").forEach((tab) => { - tab.addEventListener("click", () => { - const view = (tab as HTMLElement).dataset.view as ViewTab; - this.handleViewTabClick(view); - }); - }); + // View tab listeners no longer needed — shell subnav handles navigation this.shadow.querySelector("#btn-tour")?.addEventListener("click", () => this.startTour()); diff --git a/modules/rwallet/mod.ts b/modules/rwallet/mod.ts index c72b684..8dd9fd9 100644 --- a/modules/rwallet/mod.ts +++ b/modules/rwallet/mod.ts @@ -47,7 +47,8 @@ routes.get("/api/safe/:chainId/:address/balances", async (c) => { fiatBalance: item.fiatBalance || "0", fiatConversion: item.fiatConversion || "0", })); - const enriched = await enrichWithPrices(data, chainId); + const enriched = (await enrichWithPrices(data, chainId)) + .filter(b => BigInt(b.balance || "0") > 0n); c.header("Cache-Control", "public, max-age=30"); return c.json(enriched); }); @@ -1258,13 +1259,17 @@ function renderWallet(spaceSlug: string, initialView?: string) { modules: getModuleInfoList(), theme: "dark", body: ``, - scripts: ``, + scripts: ``, styles: ``, }); } -routes.get("/wallets", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget"))); +routes.get("/budget", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget"))); routes.get("/tokens", (c) => c.html(renderWallet(c.req.param("space") || "demo", "balances"))); +routes.get("/flows", (c) => c.html(renderWallet(c.req.param("space") || "demo", "flows"))); + +// Legacy aliases +routes.get("/wallets", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget"))); routes.get("/transactions", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget"))); routes.get("/", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget"))); @@ -1294,8 +1299,8 @@ export const walletModule: RSpaceModule = { ], acceptsFeeds: ["economic", "governance"], outputPaths: [ - { path: "wallets", name: "Wallets", icon: "💳", description: "Connected Safe wallets and EOA accounts" }, + { path: "budget", name: "Budget", icon: "📊", description: "Budget visualization — balance river timeline" }, { path: "tokens", name: "Token Balances", icon: "🪙", description: "Token balances across chains" }, - { path: "transactions", name: "Transactions", icon: "📜", description: "Transaction history and transfers" }, + { path: "flows", name: "Flows", icon: "🔀", description: "Sankey flow diagram with transaction scrubber" }, ], };