Skip to content

Conversation

krrish-sehgal
Copy link
Contributor

fixes: #84

Database Schema Decision: Handling Fiat Currency Precision in ZapPlanner

Hi,

I've been working on fixing decimal amount handling in ZapPlanner and discovered a critical architectural inconsistency if we handle the decimal places in fiat currecy just by parseFloat everywhere.

Current Problem:

  • Users enter fiat amounts like $2.21 USD
  • Backend converts to satoshis: $2.21 → 4235.67 sats
  • Database stores: amount: 4236 (Int), currency: "USD"Inconsistent!
  • Payment logic treats stored amount as fiat, causing massive overcharging

Two Architectural Approaches:

Option A: Change Schema to Float

model Subscription {
  amount   Float  // Store 4235.67 (exact satoshis)
  currency String // Store "SATS" (always)
}

Pros: Preserves exact precision, no rounding errors
Cons: Float precision issues, performance impact, breaks Lightning/Bitcoin conventions (whole satoshis)

Option B: Keep Int Schema + Enhanced Storage

model Subscription {
  sats_amount           Int     // 4236 (rounded satoshis)  
  originalAmount   String? // "2.21" (user input)
  originalCurrency String? // "USD" (user selection)
}

Pros: Follows Bitcoin standards, better performance, maintains payment precision
Cons: Additional fields, slight complexity

Current Implementation:

I've temporarily fixed this bug by storing currency: "SATS" to prevent double-conversion, but this loses the original currency information.

What's your recommendation on the long-term architecture?

@rolznz
Copy link
Contributor

rolznz commented Sep 23, 2025

@krrish-sehgal

Current Problem:
Users enter fiat amounts like $2.21 USD
Backend converts to satoshis: $2.21 → 4235.67 sats
Database stores: amount: 4236 (Int), currency: "USD" ← Inconsistent!
Payment logic treats stored amount as fiat, causing massive overcharging

Can you point to where this happens in the code?

Also that conversion is completely wrong. 2.21 should be more like 2000 sats.

I see this $2.21 USD is saved as 2 in the database.

So I think currently there is no massive overcharging?

@rolznz
Copy link
Contributor

rolznz commented Sep 23, 2025

@krrish-sehgal unfortunately we can't just store the sats amount when the user enters an amount in a fiat currency. It breaks the whole point of setting a fiat amount - to have a fixed amount in fiat and pay a dynamic amount in sats for each subscription payment.

I see this is a bit more complicated than expected as it might require a database migration. I'll mark this PR as draft for now

@rolznz rolznz marked this pull request as draft September 23, 2025 06:38
@krrish-sehgal
Copy link
Contributor Author

krrish-sehgal commented Sep 23, 2025

@krrish-sehgal

Current Problem:
Users enter fiat amounts like $2.21 USD
Backend converts to satoshis: $2.21 → 4235.67 sats
Database stores: amount: 4236 (Int), currency: "USD" ← Inconsistent!
Payment logic treats stored amount as fiat, causing massive overcharging

Can you point to where this happens in the code?

Also that conversion is completely wrong. 2.21 should be more like 2000 sats.

I see this $2.21 USD is saved as 2 in the database.

So I think currently there is no massive overcharging?

My bad here, from current problem I mean , the challenge I identified while fixing the bug. (As i used currency type as sats to make it consistent and didn't created a new migration)

Ref:

const subscription = await prismaClient.subscription.create({
data: {
amount: Math.round(satoshi),
currency: SATS_CURRENCY, // Always store as SATS since amount is in sats
recipientLightningAddress:
createSubscriptionRequest.recipientLightningAddress,
message: createSubscriptionRequest.message,

@krrish-sehgal
Copy link
Contributor Author

@rolznz , maybe we can go with Option B: Keep Int Schema + Enhanced Storage , here.
That would still require a migration though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Usd decimals are removed
2 participants