From 86f30a216cdd82d9fd8bde88fdebf0fbcd468b71 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Mon, 1 Dec 2025 21:43:46 +0100 Subject: [PATCH] fix: crypto amount calculation logic with max decimals (#2697) * fix: crypto amount calculation logic with max decimals * refactor: remove `_setCryptoNumMaximumFractionDigits` and `_cryptoNumberFormat` to simplify `OutputBase` logic --- cw_core/lib/crypto_currency.dart | 17 +++++++++-- lib/view_model/send/output.dart | 52 +++++--------------------------- 2 files changed, 21 insertions(+), 48 deletions(-) diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index b35531b72..68066b12a 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -1,6 +1,9 @@ import 'package:cw_core/currency.dart'; import 'package:cw_core/enumerable_item.dart'; import 'package:collection/collection.dart'; +import 'package:cw_core/parse_fixed.dart'; + +import 'format_fixed.dart'; class CryptoCurrency extends EnumerableItem with Serializable implements Currency { const CryptoCurrency({ @@ -394,7 +397,15 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen @override String toString() => title; - bool titleAndTagEqual(CryptoCurrency other) { - return title == other.title && tag == other.tag; - } + bool titleAndTagEqual(CryptoCurrency other) => title == other.title && tag == other.tag; + + /// Format the raw amount into its decimal representation eg. turn Sats into Bitcoin + String formatAmount(BigInt amount, {int? fractionalDigits, bool trimZeros = true}) => + formatFixed(amount, decimals, fractionalDigits: fractionalDigits, trimZeros: trimZeros); + + /// Parse the [value] and turn it into the smallest denomination eg. turn Bitcoin into Sats + BigInt parseAmount(String value) => parseFixed(value, decimals); + + /// Try parsing the [value] and turn it into the smallest denomination eg. turn Bitcoin into Sats + BigInt? tryParseAmount(String value) => tryParseFixed(value, decimals); } diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index 0badd16df..c2e69dfcb 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -19,7 +19,6 @@ import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cake_wallet/monero/monero.dart'; @@ -42,8 +41,7 @@ class Output = OutputBase with _$Output; abstract class OutputBase with Store { OutputBase( this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler) - : _cryptoNumberFormat = NumberFormat(cryptoNumberPattern), - key = UniqueKey(), + : key = UniqueKey(), sendAll = false, cryptoAmount = '', cryptoFullBalance = '', @@ -53,7 +51,6 @@ abstract class OutputBase with Store { extractedAddress = '', estimatedFee = '0.0', parsedAddress = ParsedAddress(addresses: []) { - _setCryptoNumMaximumFractionDigits(); autorun((_) { final status = _wallet.syncStatus; printV("Sync status changed to $status. Recalculating fees"); @@ -289,7 +286,6 @@ abstract class OutputBase with Store { WalletBase, TransactionInfo> _wallet; final SettingsStore _settingsStore; final FiatConversionStore _fiatConversationStore; - final NumberFormat _cryptoNumberFormat; @action void setSendAll(String fullBalance) { @@ -302,7 +298,6 @@ abstract class OutputBase with Store { void updateWallet( WalletBase, TransactionInfo> newWallet) { _wallet = newWallet; - _setCryptoNumMaximumFractionDigits(); } @action @@ -355,11 +350,12 @@ abstract class OutputBase with Store { @action void _updateCryptoAmount() { try { - final crypto = double.parse(fiatAmount.replaceAll(',', '.')) / - _fiatConversationStore.prices[cryptoCurrencyHandler()]!; - final cryptoAmountTmp = _cryptoNumberFormat.format(crypto); - if (cryptoAmount != cryptoAmountTmp) { - cryptoAmount = cryptoAmountTmp; + final crypto = (double.parse(fiatAmount.replaceAll(',', '.')) / + _fiatConversationStore.prices[cryptoCurrencyHandler()]!) + .toStringAsFixed(cryptoCurrencyHandler().decimals); + + if (cryptoAmount != crypto) { + cryptoAmount = crypto; } } catch (e) { cryptoAmount = ''; @@ -375,40 +371,6 @@ abstract class OutputBase with Store { return fields; } - void _setCryptoNumMaximumFractionDigits() { - var maximumFractionDigits = 0; - - switch (_wallet.type) { - case WalletType.monero: - case WalletType.ethereum: - case WalletType.polygon: - case WalletType.base: - case WalletType.arbitrum: - case WalletType.solana: - case WalletType.tron: - case WalletType.haven: - case WalletType.zano: - case WalletType.nano: - case WalletType.decred: - maximumFractionDigits = 12; - break; - case WalletType.bitcoin: - case WalletType.litecoin: - case WalletType.bitcoinCash: - case WalletType.dogecoin: - maximumFractionDigits = 8; - break; - case WalletType.wownero: - maximumFractionDigits = 11; - break; - case WalletType.none: - case WalletType.banano: - break; - } - - _cryptoNumberFormat.maximumFractionDigits = maximumFractionDigits; - } - Future fetchParsedAddress(BuildContext context) async { final domain = address; final currency = cryptoCurrencyHandler();