Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions client/src/hooks/useHono.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -110,19 +109,19 @@ export function useEthValuesByAccount() {
}

export function useNetworthTimeSeries() {
const { currency } = useCurrency()
const { data: fiat } = useFiat()

return useQuery({
queryKey: ['networthTimeSeries', currency, fiat],
queryKey: ['networthTimeSeries'],
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),
}))
// Filter to only include entries with usdValue and map to chart format
return json
.filter((item) => item.usdValue != null)
.map((item) => ({
...item,
value: item.usdValue as number,
}))
},
})
}
Expand Down
3 changes: 2 additions & 1 deletion client/src/screens/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function Home() {
<div
className={cn(
'relative hidden w-full',
currency === 'ETH' &&
currency === 'USD' &&
!!networthTimeSeries &&
networthTimeSeries.length > 5 &&
'lg:block'
Expand Down Expand Up @@ -116,6 +116,7 @@ export function Home() {
minute: 'numeric',
})
}}
formatter={(value) => formatCurrency(value as number, 'USD')}
/>
}
/>
Expand Down
21 changes: 20 additions & 1 deletion server/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Division by zero when USDC rate is zero

The usdcRateToEth value is used as a divisor without checking if it's zero or very small. If getRateToEth returns 0 (e.g., if the price oracle returns 0 for an unlisted or problematic token), this would result in Infinity or NaN being stored as usdValue in the database. While unlikely for USDC specifically, there's no guard against this edge case.

Fix in Cursor Fix in Web

} 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()

Expand Down
1 change: 1 addition & 0 deletions server/src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ interface BalanceRow {
interface NetworthRow {
timestamp: ColumnType<Date, never, string>
ethValue: number
usdValue: number | null
}

export type Tables = {
Expand Down
13 changes: 13 additions & 0 deletions server/src/db/migrations/003_usd_networth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Kysely, sql } from 'kysely'

export const up = async (db: Kysely<any>) => {
// Add usdValue column to networth table
await db.schema
.alterTable('networth')
.addColumn('usdValue', 'real')
.execute()
}

export const down = async (db: Kysely<any>) => {
await db.schema.alterTable('networth').dropColumn('usdValue').execute()
}
3 changes: 2 additions & 1 deletion server/src/db/migrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down