Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import type { IconName } from '@goodwidget/ui'
import type { GdCreditEntry } from '../../backendTypes'
import { formatUsdMicro } from '../../quoteMath'
import { formatGAmount, formatGWeiAmount, formatUsdMicroAmount } from '../../format'
import { formatExactGAmount, formatExactGWeiAmount, formatUsdMicroAmount } from '../../format'
import { compactButtonProps } from '../shared/styles'
import type {
AiCreditsHistoryActions,
Expand Down Expand Up @@ -69,7 +69,7 @@ function formatEntryGAmount(gdAmountWei: string): string | null {
try {
const amountWei = BigInt(gdAmountWei || '0')
if (amountWei <= 0n) return null
return formatGWeiAmount(amountWei)
return formatExactGWeiAmount(amountWei)
} catch {
return null
}
Expand Down Expand Up @@ -185,7 +185,7 @@ function sumFilteredGdWei(entries: GdCreditEntry[]): bigint {
}

function formatAccumulatedG(amountWei: bigint): string {
return formatGAmount(Number(amountWei) / 1e18)
return formatExactGAmount(Number(amountWei) / 1e18)
}

function formatShortDate(dateValue: string): string {
Expand Down
25 changes: 18 additions & 7 deletions packages/ai-credits-widget/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
* History cards.
*
* G$ — comma-grouped with up to 2 decimals and trailing zeros dropped
* (`10,000 G$`, `36,550.55 G$`); compact notation only from 1M up
* (`1.2M G$`) so whale balances cannot blow out a card.
* (`950.5 G$`); compact notation with 1 decimal from 1K up
* (`1.3K G$`, `21.2K G$`, `1.2M G$`) so large balances cannot blow out
* a card. Vault minimums and History stay exact (`21,190.79 G$`).
* US$ — always 2 decimals behind a single `US$` symbol (`US$1.30`); a positive
* amount that would round to zero renders as `<US$0.01`, so small
* credits never read as nothing.
*/

/** Above this, G$ amounts switch to compact notation to protect the layout. */
const G_COMPACT_FROM = 1_000_000
const G_COMPACT_FROM = 1_000

/** Smallest US$ amount that still rounds up to a visible cent. */
const USD_MIN_VISIBLE = 0.005
Expand All @@ -26,7 +27,7 @@ const gGrouped = new Intl.NumberFormat('en-US', {

const gCompact = new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 2,
maximumFractionDigits: 1,
})

const usdGrouped = new Intl.NumberFormat('en-US', {
Expand Down Expand Up @@ -69,11 +70,21 @@ export function isGValueCompacted(amount: string | number): boolean {
return Number.isFinite(value) && value >= G_COMPACT_FROM
}

/** Bare G$ number with no compacting, for minimums and history where every digit matters. */
export function formatExactGValue(amount: string | number): string {
const value = toNumber(amount)
if (!Number.isFinite(value) || value <= 0) return '0'
if (value < 0.01) return '<0.01'
return gGrouped.format(value)
}

/** Full G$ amount with no compacting, for tooltips behind a compacted value. */
export function formatExactGAmount(amount: string | number): string {
const value = toNumber(amount)
if (!Number.isFinite(value) || value <= 0) return '0 G$'
return `${gGrouped.format(value)} G$`
return `${formatExactGValue(amount)} G$`
}

export function formatExactGWeiAmount(amountWei: bigint | string): string {
return formatExactGAmount(weiToNumber(amountWei))
}

export function formatGWeiValue(amountWei: bigint | string): string {
Expand Down
10 changes: 5 additions & 5 deletions packages/ai-credits-widget/src/vaultMinimums.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gToWei, parseGAmount, formatUsdDisplay, quoteDepositPrincipalUsd, quoteStreamPrincipalUsd } from './quoteMath'
import { formatGValue } from './format'
import { formatExactGValue } from './format'
import type { AiCreditsQuote } from './widgetRuntimeContract'
import { parseAbi, type Address, type PublicClient } from 'viem'

Expand All @@ -22,15 +22,15 @@ export function formatMinGDisplay(amountWei: bigint): string {
if (!Number.isFinite(raw) || raw <= 0) return '0'
// Minimums always round up, so the displayed figure is never below the
// amount the vault actually accepts.
if (raw >= 1000) return formatGValue(Math.ceil(raw))
if (raw >= 10) return formatGValue(Math.ceil(raw * 10) / 10)
return formatGValue(Math.ceil(raw * 100) / 100)
if (raw >= 1000) return formatExactGValue(Math.ceil(raw))
if (raw >= 10) return formatExactGValue(Math.ceil(raw * 10) / 10)
return formatExactGValue(Math.ceil(raw * 100) / 100)
}

export function formatMinGDisplayLocale(amountG: string): string {
const value = parseGAmount(amountG)
if (value <= 0) return amountG
if (value >= 1000) return formatGValue(Math.ceil(value))
if (value >= 1000) return formatExactGValue(Math.ceil(value))
return amountG
}

Expand Down
Loading