Skip to content

Support Stablesat (USD) in Numo - Receive funds in multiple units #264

@Delgado74

Description

@Delgado74

Problem

Numo POS currently only handles satoshis (SAT). However, mints like Cuba Bitcoin (mint.cubabitcoin.org) implement stablesat, allowing funds to be managed in SAT and USD.

The specific problem: When a user attempts to receive funds in USD (stablesat) from a mint that supports it:

  • Funds are NOT added to the balance
  • Do not appear in the history
  • Tokens are rejected or silently lost

Note: The fiat currency (USD) shown in Numo is only price reference, not separate accounts. Payment is received in SAT or Stablesat according to the mint configuration.

Current Situation

Token Reception in Numo

Numo does have the token reception functionality implemented (CashuPaymentHelper.redeemToken()), but it's limited to SAT tokens only.

Numo uses the CDK library (org.cashudevkit:cdk-kotlin:0.15.1), which already supports multiple units (CurrencyUnit.Sat, CurrencyUnit.Usd). The problem is in Numo's code that has CurrencyUnit.Sat hardcoded.

In CashuPaymentHelper.kt:345-347:

if (cdkToken.unit() != CurrencyUnit.Sat) {
    throw RedemptionException("Unsupported token unit: ${cdkToken.unit()}")
}

And at line 352:

val mintWallet = wallet.getWallet(mintUrl, CurrencyUnit.Sat)

The problem is:

  • Unit detection exists (cdkToken.unit())
  • But it's explicitly rejected if not SAT
  • Uses CurrencyUnit.Sat hardcoded when getting the wallet

Example of the Problem

User tries to send $10 USD from Cuba Bitcoin to Numo:
→ CashuPaymentHelper detects it's USD unit
→ Throws exception "Unsupported token unit: USD"
→ The $10 USD are NOT added to balance
→ Do NOT appear in payment history
→ User loses their funds

Feasibility Analysis

✅ Implementation is feasible. The CDK library (org.cashudevkit:cdk-kotlin:0.15.1) already supports multiple units. The problem is only in Numo's code that has CurrencyUnit.Sat hardcoded in several places.

The Cuba Bitcoin mint already has USD implemented and working.

Proposed Solution

Implement per-unit fund reception in Numo:

Architecture

Concept Implementation
Wallet per unit Each mintUrl:unit combination has its own balance
Example cubabitcoin.org → SAT account, USD account
Automatic detection Use keyset_id to identify the unit of the received token
Dual display Show SAT balance and USD balance separately

Benefits

  1. Funds received correctly: USD tokens are credited to the corresponding account
  2. Complete history: All received payments are recorded with their original unit
  3. Clear display: The user knows exactly how much they have in each unit

Technical Implementation

Fix in CashuPaymentHelper

  1. ndef/CashuPaymentHelper.kt
    • Change validation to allow USD (currently rejects with "Unsupported token unit")
    • Use cdkToken.unit() instead of hardcoded CurrencyUnit.Sat
    • Current code at lines 345-352:
      // CURRENT (incorrect):
      if (cdkToken.unit() != CurrencyUnit.Sat) {
          throw RedemptionException("Unsupported token unit: ${cdkToken.unit()}")
      }
      val mintWallet = wallet.getWallet(mintUrl, CurrencyUnit.Sat)
      
      // SHOULD BE:
      val tokenUnit = cdkToken.unit()
      val mintWallet = wallet.getWallet(mintUrl, tokenUnit)

Changes in CashuWalletManager

  1. core/cashu/CashuWalletManager.kt

    • Create/get wallets with appropriate CurrencyUnit for each unit
    • Maintain separate balances: getBalanceForMintUnit(mintUrl, unit)
  2. payment/LightningMintHandler.kt

    • Create mint quotes with the correct CurrencyUnit according to active unit
  3. payment/SwapToLightningMintManager.kt

    • Use destination mint's CurrencyUnit when processing swaps

UI Changes

  1. ui/components/PosUiCoordinator.kt

    • Show dual balances: ₿ SAT | $ USD
    • Allow selecting active unit for payments
  2. core/data/model/PaymentHistoryEntry.kt (partially implemented)

    • Ensure unit and entryUnit are saved correctly

Compatible Mints

Mint Supported Units Status
mint.cubabitcoin.org SAT, USD ✅ Verified and working

Current Status

~30% of the infrastructure is already in place:

  • ✅ Mint unit detection (NUT-04)
  • ✅ Unit selector in MintDetailsActivity
  • ✅ Fields unit and entryUnit in PaymentHistoryEntry
  • AmountDisplayManager with activeUnit
  • 🔄 Pending: Implement reception and separate balances

Files to Modify

Priority File Main Change
Critical ndef/CashuPaymentHelper.kt Allow USD, use token's unit
Critical core/cashu/CashuWalletManager.kt Create/get wallets by CurrencyUnit
Critical payment/LightningMintHandler.kt Use correct CurrencyUnit in mintQuote
Critical payment/SwapToLightningMintManager.kt Use destination mint's CurrencyUnit
Important ui/components/PosUiCoordinator.kt Show dual balances in UI

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions