diff --git a/client/src/hooks/useHono.ts b/client/src/hooks/useHono.ts
index 73cd896..88d27e4 100644
--- a/client/src/hooks/useHono.ts
+++ b/client/src/hooks/useHono.ts
@@ -2,7 +2,6 @@ import { useQuery } from '@tanstack/react-query'
import { hc } from 'hono/client'
import { Client } from 'server/hc'
-import { useCurrency } from './useCurrency'
import { useQueues } from './useQueues'
const url = new URL(window.location.origin)
@@ -109,20 +108,21 @@ export function useEthValuesByAccount() {
})
}
-export function useNetworthTimeSeries() {
- const { currency } = useCurrency()
- const { data: fiat } = useFiat()
-
+export function useNetworthTimeSeries(currency: string | undefined) {
return useQuery({
- queryKey: ['networthTimeSeries', currency, fiat],
+ queryKey: ['networthTimeSeries', currency],
queryFn: async () => {
const res = await honoClient.balances.networth.$get()
const json = await res.json()
- return json.map((item) => ({
- ...item,
- value: item.ethValue / (fiat?.getRate(currency) ?? 1),
- }))
+ // For ETH: all records are valid (they all have ethValue)
+ // For USD: only records with usdValue are valid
+ return json
+ .filter((item) => currency === 'ETH' || item.usdValue != null)
+ .map((item) => ({
+ ...item,
+ value: currency === 'ETH' ? item.ethValue : (item.usdValue as number),
+ }))
},
})
}
diff --git a/client/src/screens/Home.tsx b/client/src/screens/Home.tsx
index 9fb630b..5019e08 100644
--- a/client/src/screens/Home.tsx
+++ b/client/src/screens/Home.tsx
@@ -32,7 +32,7 @@ export function Home() {
const { currency } = useCurrency()
const { data: fiat } = useFiat()
const ethValuesByAccount = useEthValuesByAccount()
- const { data: networthTimeSeries } = useNetworthTimeSeries()
+ const { data: networthTimeSeries } = useNetworthTimeSeries(currency)
return (
<>
@@ -58,13 +58,15 @@ export function Home() {
})()}
- Total value
+
+ Total value
+
5 &&
'lg:block'
@@ -116,6 +118,9 @@ export function Home() {
minute: 'numeric',
})
}}
+ formatter={(value) =>
+ formatCurrency(value as number, currency ?? 'USD')
+ }
/>
}
/>
diff --git a/server/src/app.ts b/server/src/app.ts
index 5bf7eb8..bb3643d 100644
--- a/server/src/app.ts
+++ b/server/src/app.ts
@@ -7,6 +7,7 @@ import { serveStatic } from 'hono/bun'
import { api } from './api'
import { db } from './db'
import { addCheckBalanceTasksToQueue } from './handlers/balances'
+import { getRateToEth } from './price'
import { erc20Queue } from './queues/workers/erc20'
import { ethQueue } from './queues/workers/eth'
@@ -38,10 +39,28 @@ new Cron('0 */12 * * *', async () => {
return
}
+ const ethValue = balances.ethValue ?? 0
+
+ // Get the current ETH/USD rate (USDC rate to ETH, inverted)
+ let usdValue: number | null = null
+ try {
+ const usdcRateToEth = await getRateToEth({
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on mainnet
+ decimals: 6,
+ chainId: 1,
+ })
+ // Convert ETH value to USD: ethValue / usdcRateToEth
+ // (usdcRateToEth is how much ETH 1 USDC is worth, so we divide)
+ usdValue = ethValue / usdcRateToEth
+ } catch (error) {
+ console.error('Failed to get USD rate for networth snapshot:', error)
+ }
+
await db
.insertInto('networth')
.values({
- ethValue: balances.ethValue ?? 0,
+ ethValue,
+ usdValue,
})
.execute()
diff --git a/server/src/db/index.ts b/server/src/db/index.ts
index 9d11d5b..41caf8e 100644
--- a/server/src/db/index.ts
+++ b/server/src/db/index.ts
@@ -48,6 +48,7 @@ interface BalanceRow {
interface NetworthRow {
timestamp: ColumnType
ethValue: number
+ usdValue: number | null
}
export type Tables = {
diff --git a/server/src/db/migrations/003_usd_networth.ts b/server/src/db/migrations/003_usd_networth.ts
new file mode 100644
index 0000000..18a3c63
--- /dev/null
+++ b/server/src/db/migrations/003_usd_networth.ts
@@ -0,0 +1,13 @@
+import { Kysely, sql } from 'kysely'
+
+export const up = async (db: Kysely) => {
+ // Add usdValue column to networth table
+ await db.schema
+ .alterTable('networth')
+ .addColumn('usdValue', 'real')
+ .execute()
+}
+
+export const down = async (db: Kysely) => {
+ await db.schema.alterTable('networth').dropColumn('usdValue').execute()
+}
diff --git a/server/src/db/migrator.ts b/server/src/db/migrator.ts
index bbe24de..ff8309a 100644
--- a/server/src/db/migrator.ts
+++ b/server/src/db/migrator.ts
@@ -6,8 +6,9 @@ import type { MigrationProvider } from 'kysely'
// in both dev mode and single-file executable mode.
import * as m1 from './migrations/001_initial_migrations'
import * as m2 from './migrations/002_erc4626'
+import * as m3 from './migrations/003_usd_networth'
-const migrations = [m1, m2]
+const migrations = [m1, m2, m3]
export const migrator: MigrationProvider = {
async getMigrations() {