mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Merge branch 'dev' into cw-1497-transaction-history-improved-layout
# Conflicts: # lib/new-ui/widgets/coins_page/assets_history/history_section.dart # lib/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart
This commit is contained in:
@@ -17,6 +17,8 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/bridge_transfers_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/amount/amount_sanitizer.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
@@ -130,18 +132,18 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
}
|
||||
|
||||
@computed
|
||||
String get tokenBalanceFormatted {
|
||||
if (selectedToken == null) return "0.00";
|
||||
|
||||
return amountParsingProxy.getDisplayCryptoStringFromBigInt(
|
||||
selectedTokenBalance, selectedToken!,
|
||||
);
|
||||
}
|
||||
String get tokenBalanceFormatted {
|
||||
if (selectedToken == null) return "0.00";
|
||||
|
||||
return amountParsingProxy.asDisplayString(
|
||||
Money(selectedTokenBalance, selectedToken!),
|
||||
);
|
||||
}
|
||||
|
||||
@computed
|
||||
String get amountDisplayFormatted {
|
||||
if (selectedToken == null) return "0.00";
|
||||
|
||||
|
||||
return amountParsingProxy.getDisplayCryptoAmount(
|
||||
amount.replaceAll(',', '.'),
|
||||
selectedToken!,
|
||||
@@ -174,10 +176,8 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
String get quoteNativeFee {
|
||||
if (quote == null) return '—';
|
||||
|
||||
return amountParsingProxy.getDisplayCryptoStringFromBigInt(
|
||||
quote!.nativeFee,
|
||||
wallet.currency,
|
||||
);
|
||||
return amountParsingProxy.asDisplayString(
|
||||
Money(quote!.nativeFee, wallet.currency));
|
||||
}
|
||||
|
||||
@computed
|
||||
@@ -218,10 +218,10 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
if (amountError != null) return false;
|
||||
|
||||
final validAmount = amountParsingProxy.tryParseCryptoString(
|
||||
amount.replaceAll(',', '.'),
|
||||
amount.sanitized(),
|
||||
selectedToken!,
|
||||
);
|
||||
return validAmount != null && validAmount > BigInt.zero;
|
||||
return validAmount != null && validAmount > Money.zero(selectedToken!);
|
||||
}
|
||||
|
||||
@computed
|
||||
@@ -231,7 +231,7 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
try {
|
||||
final bal = wallet.balance[selectedToken!];
|
||||
|
||||
return bal?.fullAvailableBalance ?? BigInt.zero;
|
||||
return bal?.available.amount ?? BigInt.zero;
|
||||
} catch (e) {
|
||||
return BigInt.zero;
|
||||
}
|
||||
@@ -247,7 +247,7 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
);
|
||||
|
||||
if (amountBigInt == null || amountBigInt == BigInt.zero) return null;
|
||||
if (amountBigInt > selectedTokenBalance) {
|
||||
if (amountBigInt.amount > selectedTokenBalance) {
|
||||
return 'Insufficient balance for ${selectedToken!.title} token.';
|
||||
}
|
||||
|
||||
@@ -281,9 +281,9 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
return;
|
||||
}
|
||||
setAmount(
|
||||
amountParsingProxy.getDisplayCryptoStringFromBigInt(
|
||||
amountParsingProxy.asDisplayString(Money(
|
||||
selectedTokenBalance,
|
||||
token,
|
||||
token)
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -382,23 +382,23 @@ abstract class BridgeViewModelBase extends WalletChangeListenerViewModel with St
|
||||
}
|
||||
|
||||
({String? error, BigInt? parsedAmount}) _parseAndValidateAmount(Erc20Token token) {
|
||||
final amountBigInt = amountParsingProxy.tryParseCryptoString(
|
||||
final parsedAmount = amountParsingProxy.tryParseCryptoString(
|
||||
amount.replaceAll(',', '.'),
|
||||
token,
|
||||
);
|
||||
|
||||
if (amountBigInt == null || amountBigInt == BigInt.zero) {
|
||||
if (parsedAmount == null || parsedAmount == Money(BigInt.zero, token)) {
|
||||
return (error: 'Invalid amount', parsedAmount: null);
|
||||
}
|
||||
|
||||
if (amountBigInt > selectedTokenBalance) {
|
||||
if (parsedAmount.amount > selectedTokenBalance) {
|
||||
return (
|
||||
error: 'Insufficient balance for ${token.title} token.',
|
||||
parsedAmount: null,
|
||||
);
|
||||
}
|
||||
|
||||
return (error: null, parsedAmount: amountBigInt);
|
||||
return (error: null, parsedAmount: parsedAmount.amount);
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:cake_wallet/core/utilities.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
@@ -10,8 +11,10 @@ import 'package:cake_wallet/evm/evm.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
@@ -28,47 +31,74 @@ part 'balance_view_model.g.dart';
|
||||
|
||||
class BalanceRecord {
|
||||
const BalanceRecord({
|
||||
required this.raw,
|
||||
required this.availableBalance,
|
||||
required this.additionalBalance,
|
||||
required this.secondAvailableBalance,
|
||||
required this.secondAdditionalBalance,
|
||||
required this.frozenBalance,
|
||||
required this.fiatAvailableBalance,
|
||||
required this.fiatAdditionalBalance,
|
||||
required this.fiatFrozenBalance,
|
||||
required this.fiatSecondAvailableBalance,
|
||||
required this.fiatSecondAdditionalBalance,
|
||||
required this.fiatAvailableBalanceRaw,
|
||||
required this.fiatAdditionalBalanceRaw,
|
||||
required this.fiatFrozenBalanceRaw,
|
||||
required this.fiatSecondAvailableBalanceRaw,
|
||||
required this.fiatSecondAdditionalBalanceRaw,
|
||||
required this.asset,
|
||||
required this.secondAsset,
|
||||
required this.fiatCurrency,
|
||||
required this.formattedAssetTitle,
|
||||
this.languageCode,
|
||||
});
|
||||
|
||||
final String fiatAdditionalBalance;
|
||||
final String fiatAvailableBalance;
|
||||
final String fiatFrozenBalance;
|
||||
final Balance raw;
|
||||
|
||||
final String fiatAvailableBalanceRaw;
|
||||
final String fiatAdditionalBalanceRaw;
|
||||
final String fiatFrozenBalanceRaw;
|
||||
final String fiatSecondAvailableBalanceRaw;
|
||||
final String fiatSecondAdditionalBalanceRaw;
|
||||
|
||||
final String additionalBalance;
|
||||
final String availableBalance;
|
||||
final String frozenBalance;
|
||||
final String secondAvailableBalance;
|
||||
final String secondAdditionalBalance;
|
||||
final String fiatSecondAdditionalBalance;
|
||||
final String fiatSecondAvailableBalance;
|
||||
final CryptoCurrency asset;
|
||||
final CryptoCurrency secondAsset;
|
||||
final FiatCurrency? fiatCurrency;
|
||||
final String formattedAssetTitle;
|
||||
final String? languageCode;
|
||||
|
||||
String get combinedAvailableBalance =>
|
||||
((double.tryParse(availableBalance) ?? 0) + (double.tryParse(secondAvailableBalance) ?? 0))
|
||||
.toString().withMaxDecimals(8);
|
||||
(raw.available + (raw.secondAvailable ?? Money.zero(raw.available.currency)))
|
||||
.toString()
|
||||
.withMaxDecimals(8);
|
||||
|
||||
String get combinedFiatAvailableBalance =>
|
||||
((double.tryParse(fiatAvailableBalanceRaw) ?? 0) +
|
||||
(double.tryParse(fiatSecondAvailableBalanceRaw) ?? 0))
|
||||
.toStringAsFixed(2);
|
||||
String get combinedFiatAvailableBalance => fiatCurrency != null
|
||||
? "$fiatCurrency " +
|
||||
_withLocalSeperator(((double.tryParse(fiatAvailableBalanceRaw) ?? 0) +
|
||||
(double.tryParse(fiatSecondAvailableBalanceRaw) ?? 0))
|
||||
.toStringAsFixed(2))
|
||||
: "";
|
||||
|
||||
String get fiatAvailableBalanceRaw => fiatAvailableBalance.split(" ").last;
|
||||
String get fiatSecondAvailableBalanceRaw => fiatSecondAvailableBalance.split(" ").last;
|
||||
String get fiatCurrencyTicker => fiatAvailableBalance.split(" ").first;
|
||||
String get fiatAvailableBalance =>
|
||||
fiatCurrency != null ? "$fiatCurrency ${_withLocalSeperator(fiatAvailableBalanceRaw)}" : "";
|
||||
|
||||
String get fiatAdditionalBalance =>
|
||||
fiatCurrency != null ? "$fiatCurrency ${_withLocalSeperator(fiatAdditionalBalanceRaw)}" : "";
|
||||
|
||||
String get fiatFrozenBalance =>
|
||||
fiatCurrency != null ? "$fiatCurrency ${_withLocalSeperator(fiatFrozenBalanceRaw)}" : "";
|
||||
|
||||
String get fiatSecondAvailableBalance => fiatCurrency != null
|
||||
? "$fiatCurrency ${_withLocalSeperator(fiatSecondAvailableBalanceRaw)}"
|
||||
: "";
|
||||
|
||||
String get fiatSecondAdditionalBalance => fiatCurrency != null
|
||||
? "$fiatCurrency ${_withLocalSeperator(fiatSecondAdditionalBalanceRaw)}"
|
||||
: "";
|
||||
|
||||
String _withLocalSeperator(String rawAmount) =>
|
||||
languageCode == null ? rawAmount : rawAmount.withLocalSeperator(languageCode);
|
||||
}
|
||||
|
||||
class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
|
||||
@@ -221,12 +251,13 @@ abstract class BalanceViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
String additionalBalance(CryptoCurrency cryptoCurrency) {
|
||||
Money additionalBalance(CryptoCurrency cryptoCurrency) {
|
||||
final balance = _currencyBalance(cryptoCurrency);
|
||||
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance || balance.additional == BigInt.zero) return '0.0';
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance || balance.unavailable.isZero)
|
||||
return Money.zero(cryptoCurrency);
|
||||
|
||||
return cryptoCurrency.formatAmount(balance.additional);
|
||||
return balance.unavailable;
|
||||
}
|
||||
|
||||
@computed
|
||||
@@ -237,25 +268,26 @@ abstract class BalanceViewModelBase with Store {
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance) {
|
||||
final fiatCurrency = settingsStore.fiatCurrency;
|
||||
return MapEntry(
|
||||
key,
|
||||
BalanceRecord(
|
||||
availableBalance: '●●●●●●',
|
||||
additionalBalance: additionalBalance(key),
|
||||
frozenBalance: '',
|
||||
secondAvailableBalance: '●●●●●●',
|
||||
secondAdditionalBalance: '●●●●●●',
|
||||
fiatAdditionalBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
|
||||
fiatAvailableBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
|
||||
fiatFrozenBalance: isFiatDisabled ? '' : '',
|
||||
fiatSecondAvailableBalance:
|
||||
isFiatDisabled ? '' : '${fiatCurrency.toString()}',
|
||||
fiatSecondAdditionalBalance:
|
||||
isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
|
||||
asset: key,
|
||||
secondAsset: secondAsset,
|
||||
formattedAssetTitle: _formatterAsset(key)));
|
||||
key,
|
||||
BalanceRecord(
|
||||
raw: value,
|
||||
availableBalance: '●●●●●●',
|
||||
additionalBalance: '',
|
||||
frozenBalance: '',
|
||||
secondAvailableBalance: '●●●●●●',
|
||||
secondAdditionalBalance: '●●●●●●',
|
||||
fiatAdditionalBalanceRaw: '●●●●●',
|
||||
fiatAvailableBalanceRaw: '●●●●●',
|
||||
fiatFrozenBalanceRaw: '',
|
||||
fiatSecondAvailableBalanceRaw: '●●●●●',
|
||||
fiatSecondAdditionalBalanceRaw: '●●●●●',
|
||||
asset: key,
|
||||
secondAsset: secondAsset,
|
||||
fiatCurrency: isFiatDisabled ? null : fiatCurrency,
|
||||
formattedAssetTitle: _formatterAsset(key),
|
||||
),
|
||||
);
|
||||
}
|
||||
final fiatCurrency = settingsStore.fiatCurrency;
|
||||
final price = key.isPotentialScam
|
||||
? 0.0
|
||||
: fiatConversionStore.prices[key == CryptoCurrency.btcln ? CryptoCurrency.btc : key] ?? 0;
|
||||
@@ -264,48 +296,41 @@ abstract class BalanceViewModelBase with Store {
|
||||
// throw Exception('Price is null for: $key');
|
||||
// }
|
||||
|
||||
final available = evm?.getERC20AvailableBalance(value) ??
|
||||
(value.fullAvailableBalance - (value.secondAvailable ?? BigInt.zero));
|
||||
final additional = evm?.getERC20AvailableBalance(value) ??
|
||||
(value.additional - (value.secondAdditional ?? BigInt.zero));
|
||||
final availableFiatBalance =
|
||||
isFiatDisabled ? '' : _getFiatBalance(price: price, cryptoAmount: value.available);
|
||||
|
||||
final availableFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: '$fiatCurrency ${_getFiatBalance(price: price, cryptoAmount: key.formatAmount(available))}';
|
||||
final additionalFiatBalance =
|
||||
isFiatDisabled ? '' : _getFiatBalance(price: price, cryptoAmount: value.unavailable);
|
||||
|
||||
final additionalFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: '$fiatCurrency ${_getFiatBalance(price: price, cryptoAmount: key.formatAmount(additional))}';
|
||||
final frozenFiatBalance =
|
||||
isFiatDisabled ? '' : _getFiatBalance(price: price, cryptoAmount: value.frozen);
|
||||
|
||||
final frozenFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: '$fiatCurrency ${_getFiatBalance(price: price, cryptoAmount: value.frozen != null ? key.formatAmount(value.frozen!) : null)}';
|
||||
|
||||
final secondAvailableFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: '$fiatCurrency ${_getFiatBalance(price: price, cryptoAmount: value.secondAvailable != null ? key.formatAmount(value.secondAvailable!) : null)}';
|
||||
final secondAvailableFiatBalance =
|
||||
isFiatDisabled ? '' : _getFiatBalance(price: price, cryptoAmount: value.secondAvailable);
|
||||
|
||||
final secondAdditionalFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: '$fiatCurrency ${_getFiatBalance(price: price, cryptoAmount: value.secondAdditional != null ? key.formatAmount(value.secondAdditional!) : null)}';
|
||||
: _getFiatBalance(price: price, cryptoAmount: value.secondUnavailable);
|
||||
|
||||
return MapEntry(
|
||||
key,
|
||||
BalanceRecord(
|
||||
availableBalance: _getFormattedCryptoAmount(key, available),
|
||||
fiatAvailableBalance: availableFiatBalance,
|
||||
additionalBalance: _getFormattedCryptoAmount(key, additional),
|
||||
fiatAdditionalBalance: additionalFiatBalance,
|
||||
frozenBalance:
|
||||
(value.frozen ?? BigInt.zero) > BigInt.zero ? _getFormattedCryptoAmount(key, value.frozen??BigInt.zero) : '',
|
||||
fiatFrozenBalance: frozenFiatBalance,
|
||||
secondAvailableBalance: _getFormattedCryptoAmount(secondAsset, value.secondAvailable??BigInt.zero),
|
||||
fiatSecondAvailableBalance: secondAvailableFiatBalance,
|
||||
secondAdditionalBalance: _getFormattedCryptoAmount(secondAsset, value.secondAdditional??BigInt.zero),
|
||||
fiatSecondAdditionalBalance: secondAdditionalFiatBalance,
|
||||
raw: value,
|
||||
availableBalance: _getFormattedCryptoAmount(value.available),
|
||||
fiatAvailableBalanceRaw: availableFiatBalance,
|
||||
additionalBalance: _getFormattedCryptoAmount(value.unavailable),
|
||||
fiatAdditionalBalanceRaw: additionalFiatBalance,
|
||||
frozenBalance: _getFormattedCryptoAmount(value.frozen),
|
||||
fiatFrozenBalanceRaw: frozenFiatBalance,
|
||||
secondAvailableBalance: _getFormattedCryptoAmount(value.secondAvailable),
|
||||
fiatSecondAvailableBalanceRaw: secondAvailableFiatBalance,
|
||||
secondAdditionalBalance: _getFormattedCryptoAmount(value.secondUnavailable),
|
||||
fiatSecondAdditionalBalanceRaw: secondAdditionalFiatBalance,
|
||||
asset: key,
|
||||
secondAsset: secondAsset,
|
||||
fiatCurrency: isFiatDisabled ? null : settingsStore.fiatCurrency,
|
||||
formattedAssetTitle: _formatterAsset(key),
|
||||
languageCode: settingsStore.languageCode,
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -316,7 +341,7 @@ abstract class BalanceViewModelBase with Store {
|
||||
|
||||
bool hasAdditionalBalance(CryptoCurrency currency) {
|
||||
final isWalletTypeActivated = _hasAdditionalBalanceForWalletType(wallet.type);
|
||||
final isNotZeroAmount = additionalBalance(currency) != "0.0";
|
||||
final isNotZeroAmount = !additionalBalance(currency).isZero;
|
||||
|
||||
return isWalletTypeActivated && isNotZeroAmount;
|
||||
}
|
||||
@@ -324,9 +349,9 @@ abstract class BalanceViewModelBase with Store {
|
||||
@computed
|
||||
bool get hasSecondAdditionalBalance {
|
||||
if (wallet.type == WalletType.litecoin && mwebEnabled) {
|
||||
return (wallet.balance[CryptoCurrency.ltc]?.secondAdditional ?? 0) != 0;
|
||||
return (wallet.balance[CryptoCurrency.ltc]?.secondUnavailable ?? 0) != 0;
|
||||
} else if (wallet.type == WalletType.bitcoin) {
|
||||
return (wallet.balance[CryptoCurrency.btc]?.secondAdditional ?? 0) != 0;
|
||||
return (wallet.balance[CryptoCurrency.btc]?.secondUnavailable ?? 0) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -351,12 +376,12 @@ abstract class BalanceViewModelBase with Store {
|
||||
WalletType.zcash
|
||||
].contains(type);
|
||||
|
||||
String _getFormattedCryptoAmount(CryptoCurrency cryptoCurrency, BigInt? amount) {
|
||||
String _getFormattedCryptoAmount(Money? amount) {
|
||||
if (amount == null) return "";
|
||||
|
||||
return appStore.amountParsingProxy
|
||||
.getDisplayCryptoStringFromBigInt(amount, cryptoCurrency)
|
||||
.withMaxDecimals(8).withLocalSeperator(settingsStore.languageCode);
|
||||
.asDisplayString(amount)
|
||||
.withLocalSeperator(settingsStore.languageCode);
|
||||
}
|
||||
|
||||
@computed
|
||||
@@ -402,9 +427,9 @@ abstract class BalanceViewModelBase with Store {
|
||||
switch (sortBalanceBy) {
|
||||
case SortBalanceBy.FiatBalance:
|
||||
final aFiatBalance = _getFiatBalance(
|
||||
price: fiatConversionStore.prices[a.asset] ?? 0, cryptoAmount: a.availableBalance);
|
||||
price: fiatConversionStore.prices[a.asset] ?? 0, cryptoAmount: a.raw.available);
|
||||
final bFiatBalance = _getFiatBalance(
|
||||
price: fiatConversionStore.prices[b.asset] ?? 0, cryptoAmount: b.availableBalance);
|
||||
price: fiatConversionStore.prices[b.asset] ?? 0, cryptoAmount: b.raw.available);
|
||||
|
||||
return (double.tryParse(bFiatBalance) ?? 0)
|
||||
.compareTo((double.tryParse(aFiatBalance)) ?? 0);
|
||||
@@ -425,7 +450,8 @@ abstract class BalanceViewModelBase with Store {
|
||||
}
|
||||
|
||||
if (wallet.walletInfo.favoriteTokenAddress != null) {
|
||||
return formattedBalances.firstWhereOrNull((item) => (getTokenAddressBasedOnWallet(item.asset) ==
|
||||
return formattedBalances.firstWhereOrNull((item) =>
|
||||
(getTokenAddressBasedOnWallet(item.asset) ==
|
||||
wallet.walletInfo.favoriteTokenAddress)) ??
|
||||
formattedBalances.elementAtOrNull(0);
|
||||
}
|
||||
@@ -455,8 +481,8 @@ abstract class BalanceViewModelBase with Store {
|
||||
|
||||
@computed
|
||||
bool get showCombinedBalance {
|
||||
if(wallet.type == WalletType.bitcoin) return false;
|
||||
if(balances.values.length == 1) return false;
|
||||
if (wallet.type == WalletType.bitcoin) return false;
|
||||
if (balances.values.length == 1) return false;
|
||||
|
||||
return wallet.walletInfo.showCombinedBalance;
|
||||
}
|
||||
@@ -470,15 +496,14 @@ abstract class BalanceViewModelBase with Store {
|
||||
double ret = 0.0;
|
||||
for (final curr in wallet.balance.keys) {
|
||||
final record = wallet.balance[curr]!;
|
||||
final available = evm?.getERC20AvailableBalance(record) ??
|
||||
(record.fullAvailableBalance - (record.secondAvailable ?? BigInt.zero));
|
||||
final available = record.available - (record.secondAvailable ?? Money.zero(curr));
|
||||
final price = fiatConversionStore.prices[curr] ?? 0;
|
||||
ret += double.tryParse(calculateFiatAmount(
|
||||
price: price, cryptoAmount: curr.formatAmount(available).replaceAll(",", ""))
|
||||
printV(record.available);
|
||||
ret += double.tryParse(calculateFiatAmount(price: price, cryptoAmount: available.toString())
|
||||
.replaceAll(",", "")) ??
|
||||
0;
|
||||
}
|
||||
return ret.toStringAsFixed(2);
|
||||
return ret.toStringAsFixed(2).withLocalSeperator(settingsStore.languageCode);
|
||||
}
|
||||
|
||||
Balance _currencyBalance(CryptoCurrency cryptoCurrency) {
|
||||
@@ -522,13 +547,12 @@ abstract class BalanceViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
String _getFiatBalance({required double price, String? cryptoAmount}) {
|
||||
if (cryptoAmount == null || cryptoAmount.isEmpty || double.tryParse(cryptoAmount) == null) {
|
||||
return '0.00'.withLocalSeperator(settingsStore.languageCode);
|
||||
String _getFiatBalance({required double price, Money? cryptoAmount}) {
|
||||
if (cryptoAmount == null) {
|
||||
return '0.00';
|
||||
}
|
||||
|
||||
return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount)
|
||||
.withLocalSeperator(settingsStore.languageCode);
|
||||
return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount.toString(), raw: true);
|
||||
}
|
||||
|
||||
String _formatterAsset(CryptoCurrency asset) {
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import 'package:cake_wallet/decred/decred.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cw_core/keyable.dart';
|
||||
@@ -52,17 +46,12 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||
String get formattedCryptoAmount {
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance) return '---';
|
||||
if (balanceViewModel.wallet.type == WalletType.bitcoin) {
|
||||
final isLightning = (transaction.additionalInfo["isLightning"] as bool?) ?? false;
|
||||
final crypto = isLightning ? CryptoCurrency.btcln : CryptoCurrency.btc;
|
||||
final amount = _appStore.amountParsingProxy
|
||||
.getDisplayCryptoString(transaction.amount, crypto)
|
||||
.withMaxDecimals(8)
|
||||
return _appStore.amountParsingProxy
|
||||
.asDisplayStringWithSymbol(transaction.amount)
|
||||
.withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
|
||||
return '$amount ${_appStore.amountParsingProxy.getCryptoSymbol(crypto)}';
|
||||
}
|
||||
|
||||
return transaction.amountFormatted();
|
||||
return transaction.amount.toStringWithSymbol();
|
||||
}
|
||||
|
||||
String get formattedTitle {
|
||||
@@ -193,26 +182,18 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||
|
||||
switch (balanceViewModel.wallet.type) {
|
||||
case WalletType.monero:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: monero!.formatterMoneroAmountToDouble(amount: transaction.amount),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.wownero:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: wownero!.formatterWowneroAmountToDouble(amount: transaction.amount),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.dogecoin:
|
||||
case WalletType.nano:
|
||||
case WalletType.decred:
|
||||
case WalletType.zcash:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: bitcoin!.formatterBitcoinAmountToDouble(amount: transaction.amount),
|
||||
cryptoAmount: double.parse(transaction.amount.toString()),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.base:
|
||||
@@ -221,14 +202,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||
final asset = assetOfTransaction;
|
||||
final price = balanceViewModel.fiatConversionStore.prices[asset];
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: evm!.formatterEVMAmountToDouble(transaction: transaction),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.nano:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: double.parse(nanoUtil!.getRawAsUsableString(
|
||||
nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)),
|
||||
cryptoAmount: double.parse(transaction.amount.toString()),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
@@ -236,16 +210,15 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||
final asset = solana!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||
final price = balanceViewModel.fiatConversionStore.prices[asset];
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: solana!.getTransactionAmountRaw(transaction),
|
||||
cryptoAmount: double.parse(transaction.amount.toString()),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.tron:
|
||||
final asset = tron!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||
final price = balanceViewModel.fiatConversionStore.prices[asset];
|
||||
final cryptoAmount = tron!.getTransactionAmountRaw(transaction);
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: cryptoAmount,
|
||||
cryptoAmount: double.parse(transaction.amount.toString()),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
@@ -257,24 +230,10 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||
}
|
||||
final price = balanceViewModel.fiatConversionStore.prices[asset];
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: zano!.formatterIntAmountToDouble(
|
||||
amount: transaction.amount, currency: asset, forFee: false),
|
||||
cryptoAmount: double.parse(transaction.amount.toString()),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.decred:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: decred!.formatterDecredAmountToDouble(amount: transaction.amount),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
break;
|
||||
case WalletType.zcash:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount:
|
||||
zcash!.formatterZcashAmountToDouble(amount: BigInt.from(transaction.amount)),
|
||||
price: price,
|
||||
).withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
|
||||
case WalletType.none:
|
||||
case WalletType.banano:
|
||||
case WalletType.haven:
|
||||
|
||||
@@ -2,10 +2,12 @@ import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:math' show min;
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/core/amount_parsing_proxy.dart';
|
||||
import 'package:cake_wallet/core/create_trade_result.dart';
|
||||
import 'package:cake_wallet/core/fiat_conversion_service.dart';
|
||||
@@ -41,6 +43,8 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/currency_picker/fiat_currency_picker_sheet.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
|
||||
import 'package:cw_core/amount/amount_sanitizer.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import "package:cw_core/wallet_info.dart";
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||
@@ -103,8 +107,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
) : isSendAllEnabled = false,
|
||||
isFixedRateMode = false,
|
||||
isReceiveAmountEntered = false,
|
||||
_depositAmount = '',
|
||||
_receiveAmount = '',
|
||||
_depositAmount = null,
|
||||
_receiveAmount = null,
|
||||
receiveAddress = '',
|
||||
depositAddress = '',
|
||||
isDepositAddressEnabled = false,
|
||||
@@ -163,8 +167,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
});
|
||||
|
||||
isDepositAddressEnabled = !useSameWalletAddress(depositCurrency);
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
receiveAddress = '';
|
||||
depositAddress =
|
||||
useSameWalletAddress(depositCurrency) ? wallet.walletAddresses.addressForExchange : '';
|
||||
@@ -237,12 +241,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
final balance = wallet.balance[depositCurrency];
|
||||
if (balance != null) {
|
||||
depositAvailableAmount = _appStore.amountParsingProxy
|
||||
.getDisplayCryptoStringFromBigInt(balance.fullAvailableBalance, depositCurrency);
|
||||
depositAvailableAmount = _appStore.amountParsingProxy.asDisplayString(balance.available);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}).timeout(Duration(seconds: 20));
|
||||
} else if (isEVMCompatibleChain(wallet.type)) {
|
||||
final currency = depositCurrency;
|
||||
final balanceCurrency = wallet.balance.keys.firstWhereOrNull(
|
||||
@@ -253,15 +256,15 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
final balanceForCurrency =
|
||||
balanceCurrency != null ? wallet.balance[balanceCurrency] : null;
|
||||
if (depositCurrency == currency && balanceForCurrency != null) {
|
||||
depositAvailableAmount = _appStore.amountParsingProxy
|
||||
.getDisplayCryptoStringFromBigInt(
|
||||
balanceForCurrency.fullAvailableBalance, balanceCurrency!);
|
||||
depositAvailableAmount =
|
||||
_appStore.amountParsingProxy.asDisplayStringWithSymbol(balanceForCurrency.available);
|
||||
}
|
||||
} else {
|
||||
final currency = depositCurrency;
|
||||
final amount = _appStore.amountParsingProxy.getDisplayCryptoString(
|
||||
(await unspentCoinsListViewModel.getSendingBalance(UnspentCoinType.any)), depositCurrency);
|
||||
if(depositCurrency == currency) {
|
||||
final sendingBalance = Money.fromInt(
|
||||
await unspentCoinsListViewModel.getSendingBalance(UnspentCoinType.any), currency);
|
||||
final amount = _appStore.amountParsingProxy.asDisplayStringWithSymbol(sendingBalance);
|
||||
if (depositCurrency == currency) {
|
||||
depositAvailableAmount = amount;
|
||||
}
|
||||
}
|
||||
@@ -289,7 +292,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
].contains(wallet.type);
|
||||
|
||||
bool get hideAddressAfterExchange =>
|
||||
[WalletType.monero, WalletType.wownero, WalletType.zcash].contains(wallet.type);
|
||||
[WalletType.monero, WalletType.wownero, WalletType.zcash].contains(wallet.type) ||
|
||||
isElectrumWallet;
|
||||
|
||||
bool _useTorOnly;
|
||||
final ExchangeTemplateStore _exchangeTemplateStore;
|
||||
@@ -352,25 +356,29 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
ExchangeTradeState tradeState;
|
||||
|
||||
@observable
|
||||
String _depositAmount;
|
||||
Money? _depositAmount;
|
||||
|
||||
@computed
|
||||
bool get hasDepositAmount => _depositAmount != null;
|
||||
|
||||
@computed
|
||||
String get depositAmount =>
|
||||
_depositAmount == "..."? _depositAmount:amountParsingProxy.getDisplayCryptoAmount(_depositAmount, depositCurrency);
|
||||
_depositAmount == null ? "" : amountParsingProxy.asDisplayString(_depositAmount!);
|
||||
|
||||
@computed
|
||||
String get depositAmountCanonical => _depositAmount;
|
||||
String get depositAmountCanonical => _depositAmount == null ? "0.0" : _depositAmount.toString();
|
||||
|
||||
@observable
|
||||
String _receiveAmount;
|
||||
Money? _receiveAmount;
|
||||
|
||||
@computed
|
||||
String get receiveAmount =>
|
||||
_receiveAmount == "..." ? _receiveAmount:amountParsingProxy.getDisplayCryptoAmount(_receiveAmount, receiveCurrency);
|
||||
_receiveAmount == null ? "" : amountParsingProxy.asDisplayString(_receiveAmount!);
|
||||
|
||||
@action
|
||||
// only set canonical formated amounts here;
|
||||
void setCanonicalReceiveAmount(String value) => _receiveAmount = value;
|
||||
void setCanonicalReceiveAmount(String value) =>
|
||||
_receiveAmount = Money.tryParse(value, receiveCurrency);
|
||||
|
||||
@observable
|
||||
String depositAddress;
|
||||
@@ -486,7 +494,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
@computed
|
||||
String? get balanceDisplay {
|
||||
CryptoCurrency? balanceCurrency;
|
||||
if (isEVMCompatibleChain(wallet.type)) {
|
||||
if (isEVMCompatibleChain(wallet.type) || wallet.type == WalletType.solana || wallet.type == WalletType.tron) {
|
||||
balanceCurrency = wallet.balance.keys.firstWhereOrNull(
|
||||
(c) =>
|
||||
c.title == depositCurrency.title &&
|
||||
@@ -495,10 +503,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
} else {
|
||||
balanceCurrency = depositCurrency;
|
||||
}
|
||||
final bal = balanceCurrency != null ? wallet.balance[balanceCurrency]?.fullAvailableBalance : null;
|
||||
final bal = balanceCurrency != null ? wallet.balance[balanceCurrency]?.available : null;
|
||||
if (bal == null) return null;
|
||||
return amountParsingProxy.getDisplayCryptoStringFromBigInt(
|
||||
bal, balanceCurrency ?? depositCurrency);
|
||||
return amountParsingProxy.asDisplayString(bal);
|
||||
}
|
||||
|
||||
//* Still open to further optimize these checks
|
||||
@@ -572,10 +579,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
double bestRate = 0.0;
|
||||
|
||||
@computed
|
||||
bool get useSatoshiDeposit => _appStore.amountParsingProxy.useSatoshi(depositCurrency);
|
||||
bool get useDepositBaseUnit => _appStore.amountParsingProxy.useSatoshi(depositCurrency);
|
||||
|
||||
@computed
|
||||
bool get useSatoshisReceive => _appStore.amountParsingProxy.useSatoshi(receiveCurrency);
|
||||
bool get useReceiveBaseUnit => _appStore.amountParsingProxy.useSatoshi(receiveCurrency);
|
||||
|
||||
@computed
|
||||
AmountParsingProxy get amountParsingProxy => _appStore.amountParsingProxy;
|
||||
@@ -624,12 +631,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
String get receiveAmountFiatFormatted {
|
||||
var amount = '0.00';
|
||||
try {
|
||||
if (_receiveAmount.isNotEmpty) {
|
||||
if (_receiveAmount != null) {
|
||||
if (fiatConversionStore.prices[receiveCurrency] == null) return '';
|
||||
|
||||
amount = calculateFiatAmount(
|
||||
price: fiatConversionStore.prices[receiveCurrency]!,
|
||||
cryptoAmount: _receiveAmount,
|
||||
cryptoAmount: _receiveAmount.toString(),
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
@@ -642,12 +649,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
String get depositAmountFiatFormatted {
|
||||
var amount = '0.00';
|
||||
try {
|
||||
if (_depositAmount.isNotEmpty) {
|
||||
if (_depositAmount != null) {
|
||||
if (fiatConversionStore.prices[depositCurrency] == null) return '';
|
||||
|
||||
amount = calculateFiatAmount(
|
||||
price: fiatConversionStore.prices[depositCurrency]!,
|
||||
cryptoAmount: _depositAmount,
|
||||
cryptoAmount: _depositAmount.toString(),
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
@@ -660,12 +667,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
String get receiveAmountFiat {
|
||||
var amount = '';
|
||||
try {
|
||||
if (_receiveAmount.isNotEmpty) {
|
||||
if (_receiveAmount != null) {
|
||||
if (fiatConversionStore.prices[receiveCurrency] == null) return '';
|
||||
|
||||
amount = calculateFiatAmount(
|
||||
price: fiatConversionStore.prices[receiveCurrency]!,
|
||||
cryptoAmount: _receiveAmount,
|
||||
cryptoAmount: _receiveAmount.toString(),
|
||||
raw: true);
|
||||
}
|
||||
} catch (_) {
|
||||
@@ -678,13 +685,14 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
String get depositAmountFiat {
|
||||
var amount = '';
|
||||
try {
|
||||
if (_depositAmount.isNotEmpty) {
|
||||
if (_depositAmount != null) {
|
||||
if (fiatConversionStore.prices[depositCurrency] == null) return '';
|
||||
|
||||
amount = calculateFiatAmount(
|
||||
price: fiatConversionStore.prices[depositCurrency]!,
|
||||
cryptoAmount: _depositAmount,
|
||||
raw: true);
|
||||
price: fiatConversionStore.prices[depositCurrency]!,
|
||||
cryptoAmount: _depositAmount.toString(),
|
||||
raw: true,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
log('Error calculating deposit amount fiat formatted: $_');
|
||||
@@ -771,32 +779,37 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> changeReceiveAmount({required String amount}) async {
|
||||
amount = amountParsingProxy.getCanonicalCryptoAmount(amount, receiveCurrency);
|
||||
|
||||
_receiveAmount = amount;
|
||||
|
||||
Future<void> changeReceiveAmount({required String amount, bool isCanonical = false}) async {
|
||||
if (amount.isEmpty) {
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final _enteredAmount = double.tryParse(_receiveAmount.replaceAll(',', '.')) ?? 0;
|
||||
_receiveAmount = isCanonical
|
||||
? Money.tryParse(amount.sanitized(), receiveCurrency)
|
||||
: _appStore.amountParsingProxy.tryParseCryptoString(amount.sanitized(), receiveCurrency);
|
||||
|
||||
if (_receiveAmount == null) {
|
||||
_depositAmount = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final _enteredAmount = double.tryParse(_receiveAmount.toString()) ?? 0;
|
||||
|
||||
if (bestRate == 0) {
|
||||
_depositAmount = "...";
|
||||
_depositAmount = null;
|
||||
|
||||
await calculateBestRate();
|
||||
}
|
||||
|
||||
final amount_ = _enteredAmount / (forcedProvider == null ? bestRate : forcedProviderRate);
|
||||
_depositAmount = amount_.toString().withMaxDecimals(depositCurrency.decimals);
|
||||
_depositAmount = Money.tryParse(amount_.toStringAsFixed(depositCurrency.decimals), depositCurrency);
|
||||
}
|
||||
|
||||
@action
|
||||
void setReceiveAmountFromFiat({required String fiatAmount}) {
|
||||
final _enteredAmount = double.tryParse(fiatAmount.replaceAll(',', '.')) ?? 0.0;
|
||||
final _enteredAmount = double.tryParse(fiatAmount.sanitized()) ?? 0.0;
|
||||
final price = fiatConversionStore.prices[receiveCurrency];
|
||||
if (price == null || price == 0.0) return;
|
||||
|
||||
@@ -809,7 +822,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
void setDepositAmountFromFiat({required String fiatAmount}) {
|
||||
final _enteredAmount = double.tryParse(fiatAmount.replaceAll(',', '.')) ?? 0.0;
|
||||
final _enteredAmount = double.tryParse(fiatAmount.sanitized()) ?? 0.0;
|
||||
final price = fiatConversionStore.prices[depositCurrency];
|
||||
if (price == null || price == 0.0) return;
|
||||
|
||||
@@ -822,34 +835,40 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
Future<void> changeDepositAmount({required String amount, bool isCanonical = false}) async {
|
||||
_depositAmount = isCanonical ? amount.replaceAll(',', '.') : _appStore.amountParsingProxy
|
||||
.getCanonicalCryptoAmount(amount.replaceAll(',', '.'), depositCurrency);
|
||||
|
||||
if (amount.isEmpty) {
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_depositAmount = isCanonical
|
||||
? Money.tryParse(amount.sanitized(), depositCurrency)
|
||||
: _appStore.amountParsingProxy.tryParseCryptoString(amount.sanitized(), depositCurrency);
|
||||
|
||||
if (_depositAmount == null) {
|
||||
_receiveAmount = null;
|
||||
return;
|
||||
}
|
||||
/// For fixed-rate transactions, we don't want to recalculate receive amount
|
||||
/// as it should remain exactly what the user set
|
||||
if (isFixedRateMode) return;
|
||||
|
||||
final _enteredAmount = double.tryParse(_depositAmount) ?? 0;
|
||||
final _enteredAmount = double.tryParse(_depositAmount.toString()) ?? 0;
|
||||
|
||||
/// in case the best rate was not calculated yet
|
||||
if (bestRate == 0) {
|
||||
_receiveAmount = "...";
|
||||
_receiveAmount = null;
|
||||
|
||||
await calculateBestRate();
|
||||
}
|
||||
|
||||
final amount_ = _enteredAmount * (forcedProvider == null ? bestRate : forcedProviderRate);
|
||||
_receiveAmount = amount_.toString().withMaxDecimals(receiveCurrency.decimals);
|
||||
_receiveAmount =
|
||||
Money.tryParse(amount_.toStringAsFixed(min(20, receiveCurrency.decimals)), receiveCurrency);
|
||||
}
|
||||
|
||||
bool checkIfInputMeetsMinOrMaxCondition(String input) {
|
||||
final _enteredAmount = double.tryParse(input.replaceAll(',', '.')) ?? 0;
|
||||
final _enteredAmount = double.tryParse(input.sanitized()) ?? 0;
|
||||
double minLimit = limits.min ?? 0;
|
||||
double? maxLimit = limits.max;
|
||||
|
||||
@@ -866,8 +885,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
return;
|
||||
}
|
||||
|
||||
final amount = double.tryParse(isFixedRateMode ? _receiveAmount : _depositAmount) ??
|
||||
initialAmountByAssets(isFixedRateMode ? receiveCurrency : depositCurrency);
|
||||
final amount =
|
||||
double.tryParse(isFixedRateMode ? _receiveAmount.toString() : _depositAmount.toString()) ??
|
||||
initialAmountByAssets(isFixedRateMode ? receiveCurrency : depositCurrency);
|
||||
|
||||
forcedProviderRate = await forcedProvider!.fetchRate(
|
||||
from: depositCurrency,
|
||||
@@ -891,8 +911,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
bestRateProvider = null;
|
||||
return;
|
||||
}
|
||||
final amount = double.tryParse(isFixedRateMode ? _receiveAmount : _depositAmount) ??
|
||||
initialAmountByAssets(isFixedRateMode ? receiveCurrency : depositCurrency);
|
||||
final amount =
|
||||
double.tryParse(isFixedRateMode ? _receiveAmount.toString() : _depositAmount.toString()) ??
|
||||
initialAmountByAssets(isFixedRateMode ? receiveCurrency : depositCurrency);
|
||||
|
||||
final validProvidersForAmount = _tradeAvailableProviders.where((provider) {
|
||||
if (_excludeProviderForSwapAll(provider)) return false;
|
||||
@@ -1025,13 +1046,13 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
Future<void> createTrade() async {
|
||||
final depositAmountValue =
|
||||
double.tryParse(_depositAmount.replaceAll(',', '.')) ?? 0.0;
|
||||
final depositAmountValue = _depositAmount ?? Money.zero(depositCurrency);
|
||||
final receiveAmountValue = _receiveAmount ?? Money.zero(receiveCurrency);
|
||||
|
||||
final receiveAmountValue =
|
||||
double.tryParse(_receiveAmount.replaceAll(',', '.')) ?? 0.0;
|
||||
|
||||
if (depositAmountValue <= 0 || receiveAmountValue <= 0) {
|
||||
if (depositAmountValue.isZero ||
|
||||
depositAmountValue.isNegative ||
|
||||
receiveAmountValue.isZero ||
|
||||
receiveAmountValue.isNegative) {
|
||||
ExchangeProviderLogger.logError(
|
||||
provider: forcedProvider?.description ?? bestRateProvider?.description,
|
||||
function: 'createTrade',
|
||||
@@ -1047,25 +1068,26 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
},
|
||||
);
|
||||
|
||||
final invalidAmountError = depositAmountValue <= 0
|
||||
final invalidAmountError = depositAmountValue.isZero || depositAmountValue.isNegative
|
||||
? '$depositAmountValue is not a valid amount for depositAmount'
|
||||
: '$receiveAmountValue is not a valid amount for receiveAmount';
|
||||
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: S.current.trade_not_created,
|
||||
error: invalidAmountError,
|
||||
error: invalidAmountError
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSendAllEnabled) {
|
||||
await calculateDepositAllAmount();
|
||||
final amount = double.tryParse(_depositAmount);
|
||||
final amount = double.tryParse(_depositAmount.toString());
|
||||
|
||||
if (limits.min != null && amount != null && amount < limits.min!) {
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: S.current.trade_not_created,
|
||||
error: S.current.amount_is_below_minimum_limit(limits.min!.toString()));
|
||||
error: S.current.amount_is_below_minimum_limit(limits.min!.toString()),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1090,8 +1112,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
if (forcedProvider != null && _excludeProviderForReceiveExtraId(forcedProvider!)) {
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: S.current.trade_not_created,
|
||||
error: S.current.none_of_selected_providers_can_exchange);
|
||||
title: S.current.trade_not_created,
|
||||
error: S.current.none_of_selected_providers_can_exchange,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1183,7 +1206,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
if (isFixedRateMode && provider.supportsFixedRate == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (_excludeProviderForReceiveExtraId(provider)) {
|
||||
continue;
|
||||
}
|
||||
@@ -1200,13 +1223,13 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
bestRate = providerRate;
|
||||
bestRateProvider = provider;
|
||||
|
||||
await changeDepositAmount(amount: _depositAmount, isCanonical: true);
|
||||
await changeDepositAmount(amount: _depositAmount.toString(), isCanonical: true);
|
||||
|
||||
final request = TradeRequest(
|
||||
fromCurrency: depositCurrency,
|
||||
toCurrency: receiveCurrency,
|
||||
fromAmount: _depositAmount.replaceAll(',', '.'),
|
||||
toAmount: _receiveAmount.replaceAll(',', '.'),
|
||||
fromAmount: _depositAmount.toString(),
|
||||
toAmount: _receiveAmount.toString(),
|
||||
refundAddress: depositAddress,
|
||||
toAddress: receiveAddress,
|
||||
toAddressExtraId: receiveAddressExtraId.trim(),
|
||||
@@ -1218,8 +1241,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
await wallet.walletAddresses.saveAddressesInBox();
|
||||
}
|
||||
|
||||
var amount = isFixedRateMode ? _receiveAmount : _depositAmount;
|
||||
amount = amount.replaceAll(',', '.');
|
||||
var amount = isFixedRateMode ? _receiveAmount.toString() : _depositAmount.toString();
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
if (double.tryParse(amount) == null) {
|
||||
@@ -1242,6 +1264,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
trade.walletId = wallet.id;
|
||||
trade.chainId = wallet.chainId;
|
||||
trade.fromWalletAddress = wallet.walletAddresses.address;
|
||||
if(trade.from == null) {
|
||||
trade.from = depositCurrency;
|
||||
}
|
||||
if(trade.to == null) {
|
||||
trade.to = receiveCurrency;
|
||||
}
|
||||
|
||||
final canCreateTrade = await isCanCreateTrade(trade);
|
||||
if (!canCreateTrade.result) {
|
||||
@@ -1260,7 +1288,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
|
||||
tradesStore.setTrade(trade);
|
||||
if (trade.provider != ExchangeProviderDescription.thorChain) await trade.save();
|
||||
if (trade.provider != ExchangeProviderDescription.thorChain) await trade.save();
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
|
||||
/// return after the first successful trade
|
||||
@@ -1304,8 +1332,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
void reset() {
|
||||
_initialPairBasedOnWallet();
|
||||
isReceiveAmountEntered = false;
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
depositAddress =
|
||||
depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
|
||||
receiveAddress =
|
||||
@@ -1341,8 +1369,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
final amount = depositCurrency == CryptoCurrency.btcln
|
||||
// FIXME amount estimation is broken/impossible for ln, konsti suggested this
|
||||
? (amountParsingProxy
|
||||
.parseCryptoString(depositAvailableAmount, depositCurrency).toInt() - 10)
|
||||
? (amountParsingProxy.parseCryptoString(depositAvailableAmount, depositCurrency) -
|
||||
Money.fromInt(10, depositCurrency))
|
||||
: await bitcoin!.estimateFakeSendAllTxAmount(
|
||||
wallet,
|
||||
priority,
|
||||
@@ -1353,7 +1381,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
: UnspentCoinType.any,
|
||||
);
|
||||
|
||||
changeDepositAmount(amount: wallet.currency.formatAmount(BigInt.from(amount)), isCanonical: true);
|
||||
changeDepositAmount(amount: amount.toString(), isCanonical: true);
|
||||
} else if (wallet.type == WalletType.monero) {
|
||||
final amount = await unspentCoinsListViewModel.getSendingBalance(UnspentCoinType.any);
|
||||
|
||||
@@ -1371,7 +1399,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
return;
|
||||
}
|
||||
|
||||
final balanceAmount = _appStore.amountParsingProxy.getDisplayCryptoStringFromBigInt(balanceForCurrency.fullAvailableBalance, balanceCurrency!);
|
||||
final balanceAmount = _appStore.amountParsingProxy.asDisplayString(balanceForCurrency.available);
|
||||
final balanceDouble = double.tryParse(balanceAmount.replaceAll(',', '.')) ?? 0.0;
|
||||
if (balanceDouble <= 0) {
|
||||
changeDepositAmount(amount: wallet.currency.formatAmount(BigInt.zero), isCanonical: true);
|
||||
@@ -1399,7 +1427,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
return;
|
||||
}
|
||||
|
||||
final balanceWei = balanceForCurrency.fullAvailableBalance;
|
||||
final balanceWei = balanceForCurrency.available.amount;
|
||||
final feeWei = BigInt.parse(feeString);
|
||||
final amountAfterFeeWei = balanceWei > feeWei ? balanceWei - feeWei : BigInt.zero;
|
||||
changeDepositAmount(
|
||||
@@ -1449,14 +1477,14 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
void _onPairChange({bool clearBoth = false}) {
|
||||
if (clearBoth) {
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
if (!hasAllAmount) isSendAllEnabled = false;
|
||||
} else {
|
||||
if (isFixedRateMode) {
|
||||
_depositAmount = '';
|
||||
_depositAmount = null;
|
||||
} else {
|
||||
_receiveAmount = '';
|
||||
_receiveAmount = null;
|
||||
}
|
||||
}
|
||||
bestRate = 0.0;
|
||||
@@ -1559,6 +1587,21 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
}
|
||||
|
||||
String? _addressTypeValidation(String refundAddress, String receiveAddress) {
|
||||
final isRefundAddressSP = RegExp(AddressValidator.silentPaymentAddressPatternMainnet).hasMatch(refundAddress);
|
||||
if (isRefundAddressSP) return 'Silent Payment ${S.current.address_not_allowed_as_refund}';
|
||||
|
||||
final isReceiveAddressSP = RegExp(AddressValidator.silentPaymentAddressPatternMainnet).hasMatch(receiveAddress);
|
||||
if (isReceiveAddressSP) return 'Silent Payment ${S.current.address_not_allowed_as_receive}';
|
||||
|
||||
final isRefundAddressMWEB = RegExp(AddressValidator.mWebAddressPattern).hasMatch(refundAddress);
|
||||
if (isRefundAddressMWEB) return 'MWEB ${S.current.address_not_allowed_as_refund}';
|
||||
|
||||
final isReceiveAddressMWEB = RegExp(AddressValidator.mWebAddressPattern).hasMatch(receiveAddress);
|
||||
if (isReceiveAddressMWEB) return 'MWEB ${S.current.address_not_allowed_as_receive}';
|
||||
return null;
|
||||
}
|
||||
|
||||
void _defineIsReceiveAmountEditable() {
|
||||
/*if ((provider is ChangeNowExchangeProvider)
|
||||
&&(depositCurrency == CryptoCurrency.xmr)
|
||||
@@ -1591,8 +1634,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
@action
|
||||
void saveSelectedProviders() {
|
||||
_depositAmount = '';
|
||||
_receiveAmount = '';
|
||||
_depositAmount = null;
|
||||
_receiveAmount = null;
|
||||
isFixedRateMode = false;
|
||||
_defineIsReceiveAmountEditable();
|
||||
bestRateProvider = null;
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/parse_fixed.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
@@ -22,7 +23,9 @@ class DEuroViewModel = DEuroViewModelBase with _$DEuroViewModel;
|
||||
abstract class DEuroViewModelBase with Store {
|
||||
final AppStore _appStore;
|
||||
|
||||
static BigInt get MIN_ACCRUED_INTEREST => BigInt.parse("1000000000000");
|
||||
static Money get MIN_ACCRUED_INTEREST => Money(BigInt.parse("1000000000000"), CryptoCurrency.deuro);
|
||||
|
||||
static Money get ZERO => Money.zero(CryptoCurrency.deuro);
|
||||
|
||||
DEuroViewModelBase(
|
||||
this._appStore, this.balanceViewModel, this._settingsStore, this._fiatConversationStore,
|
||||
@@ -51,13 +54,13 @@ abstract class DEuroViewModelBase with Store {
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFiatAmountFormatted {
|
||||
final amount = transaction == null ? '0.00' : _getDEuroFiatAmount(transaction!.amountFormatted);
|
||||
return isFiatDisabled ? '' : '$amount ${fiat.title}';
|
||||
final amount = transaction == null ? "0.00" : _getDEuroFiatAmount(transaction!.amount);
|
||||
return isFiatDisabled ? "" : "$amount ${fiat.symbol}";
|
||||
}
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFeeFiatAmountFormatted {
|
||||
var amount = '0.00';
|
||||
var amount = "0.00";
|
||||
try {
|
||||
if (transaction != null) {
|
||||
final feeCurrency = CryptoCurrency.eth;
|
||||
@@ -67,42 +70,43 @@ abstract class DEuroViewModelBase with Store {
|
||||
);
|
||||
}
|
||||
} catch (_) {}
|
||||
return isFiatDisabled ? '' : '$amount ${fiat.title}';
|
||||
return isFiatDisabled ? "" : "$amount ${fiat.symbol}";
|
||||
}
|
||||
|
||||
@computed
|
||||
String get accountBalanceFormated {
|
||||
Money get accountBalance {
|
||||
final dEuroKey = balanceViewModel.balances.keys
|
||||
.firstWhereOrNull((e) => e.title == CryptoCurrency.deuro.title);
|
||||
if (dEuroKey == null) return '0.00';
|
||||
return balanceViewModel.balances[dEuroKey]?.availableBalance ?? '0.00';
|
||||
if (dEuroKey == null) return ZERO;
|
||||
return wallet.balance[dEuroKey]?.available ?? ZERO;
|
||||
}
|
||||
|
||||
@observable
|
||||
BigInt savingsBalance = BigInt.zero;
|
||||
Money savingsBalance = ZERO;
|
||||
|
||||
@computed
|
||||
String get savingsBalanceFormated =>
|
||||
evm!.formatterEVMAmountToDouble(amount: savingsBalance).toStringAsFixed(6);
|
||||
String get fiatSavingsBalanceFormated => _getDEuroFiatAmount(savingsBalance);
|
||||
|
||||
@observable
|
||||
Money? savingsBalanceV1 = null;
|
||||
|
||||
@computed
|
||||
String get fiatSavingsBalanceFormated => _getDEuroFiatAmount(savingsBalanceFormated);
|
||||
String get fiatSavingsBalanceV1Formated => _getDEuroFiatAmount(savingsBalanceV1);
|
||||
|
||||
@observable
|
||||
ExecutionState state = InitialExecutionState();
|
||||
|
||||
@observable
|
||||
String interestRateFormated = '0';
|
||||
String interestRateFormated = "0";
|
||||
|
||||
@observable
|
||||
BigInt accruedInterest = BigInt.zero;
|
||||
Money accruedInterest = ZERO;
|
||||
|
||||
@computed
|
||||
String get accruedInterestFormated =>
|
||||
evm!.formatterEVMAmountToDouble(amount: accruedInterest).toStringAsFixed(6);
|
||||
String get accruedInterestFormated => accruedInterest.toStringWithPrecision(fractionalDigits: 6);
|
||||
|
||||
@computed
|
||||
String get fiatAccruedInterestFormated => _getDEuroFiatAmount(accruedInterestFormated);
|
||||
String get fiatAccruedInterestFormated => _getDEuroFiatAmount(accruedInterest);
|
||||
|
||||
@observable
|
||||
BigInt approvedTokens = BigInt.zero;
|
||||
@@ -128,8 +132,12 @@ abstract class DEuroViewModelBase with Store {
|
||||
@action
|
||||
Future<void> reloadSavingsUserData() async {
|
||||
approvedTokens = await evm!.getDEuroSavingsApproved(_appStore.wallet!) ?? BigInt.zero;
|
||||
savingsBalance = await evm!.getDEuroSavingsBalance(_appStore.wallet!) ?? BigInt.zero;
|
||||
accruedInterest = await evm!.getDEuroAccruedInterest(_appStore.wallet!) ?? BigInt.zero;
|
||||
savingsBalance = await evm!.getDEuroSavingsBalance(_appStore.wallet!) ?? ZERO;
|
||||
accruedInterest = await evm!.getDEuroAccruedInterest(_appStore.wallet!) ?? ZERO;
|
||||
|
||||
final v1Balance = await evm!.getDEuroSavingsV1Balance(_appStore.wallet!) ?? ZERO;
|
||||
savingsBalanceV1 = v1Balance.isZero ? null : v1Balance;
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
@@ -151,9 +159,8 @@ abstract class DEuroViewModelBase with Store {
|
||||
state = TransactionCommitting();
|
||||
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
||||
final approval = await evm!.enableDEuroSaving(_appStore.wallet!, priority);
|
||||
if (approval == null) {
|
||||
throw Exception('DEuro saving not available');
|
||||
}
|
||||
if (approval == null) throw Exception("DEuro saving not available");
|
||||
|
||||
approvalTransaction = approval;
|
||||
state = InitialExecutionState();
|
||||
} catch (e) {
|
||||
@@ -167,13 +174,13 @@ abstract class DEuroViewModelBase with Store {
|
||||
state = TransactionCommitting();
|
||||
|
||||
if (amountRaw.isEmpty || amountRaw.trim().isEmpty) {
|
||||
throw Exception('Invalid amount: amount cannot be empty');
|
||||
throw Exception("Invalid amount: amount cannot be empty");
|
||||
}
|
||||
|
||||
final amount = tryParseFixed(amountRaw, 18);
|
||||
|
||||
if (amount == BigInt.zero || amount == null) {
|
||||
throw Exception('Invalid amount: amount cannot be zero');
|
||||
throw Exception("Invalid amount: amount cannot be zero");
|
||||
}
|
||||
|
||||
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
||||
@@ -181,9 +188,24 @@ abstract class DEuroViewModelBase with Store {
|
||||
final tx = await (isAdding
|
||||
? evm!.addDEuroSaving(_appStore.wallet!, amount, priority)
|
||||
: evm!.removeDEuroSaving(_appStore.wallet!, amount, priority));
|
||||
if (tx == null) {
|
||||
throw Exception('DEuro saving not available');
|
||||
}
|
||||
if (tx == null) throw Exception("DEuro saving not available");
|
||||
|
||||
transaction = tx;
|
||||
state = InitialExecutionState();
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> prepareSavingsV1Withdraw() async {
|
||||
try {
|
||||
state = TransactionCommitting();
|
||||
actionType = DEuroActionType.withdraw;
|
||||
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
||||
final tx = await evm!.withdrawDEuroSavingV1(_appStore.wallet!, priority);
|
||||
if (tx == null) throw Exception("DEuro saving not available");
|
||||
|
||||
transaction = tx;
|
||||
state = InitialExecutionState();
|
||||
} catch (e) {
|
||||
@@ -193,13 +215,13 @@ abstract class DEuroViewModelBase with Store {
|
||||
|
||||
Future<void> prepareCollectInterest() async {
|
||||
if (accruedInterest < MIN_ACCRUED_INTEREST) {
|
||||
state = FailureState('Accrued interest is below minimum threshold');
|
||||
state = FailureState("Accrued interest is below minimum threshold");
|
||||
return;
|
||||
}
|
||||
|
||||
final formatted = accruedInterestFormated;
|
||||
if (formatted.isEmpty || formatted == '0.000000') {
|
||||
state = FailureState('Invalid accrued interest amount');
|
||||
if (formatted.isEmpty || formatted == "0.000000") {
|
||||
state = FailureState("Invalid accrued interest amount");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -212,9 +234,8 @@ abstract class DEuroViewModelBase with Store {
|
||||
actionType = DEuroActionType.reinvest;
|
||||
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
||||
final tx = await evm!.reinvestDEuroInterest(_appStore.wallet!, priority);
|
||||
if (tx == null) {
|
||||
throw Exception('DEuro saving not available');
|
||||
}
|
||||
if (tx == null) throw Exception("DEuro saving not available");
|
||||
|
||||
transaction = tx;
|
||||
state = InitialExecutionState();
|
||||
} catch (e) {
|
||||
@@ -261,7 +282,9 @@ abstract class DEuroViewModelBase with Store {
|
||||
state = InitialExecutionState();
|
||||
}
|
||||
|
||||
String _getDEuroFiatAmount(String amount) {
|
||||
String _getDEuroFiatAmount(Money? amount) {
|
||||
if (amount == null) return "0.00";
|
||||
|
||||
try {
|
||||
var dEuro = CryptoCurrency.deuro;
|
||||
final keys = _fiatConversationStore.prices.keys.toList();
|
||||
@@ -270,19 +293,14 @@ abstract class DEuroViewModelBase with Store {
|
||||
}
|
||||
return calculateFiatAmount(
|
||||
price: _fiatConversationStore.prices[dEuro]!,
|
||||
cryptoAmount: amount,
|
||||
cryptoAmount: amount.toStringWithPrecision(fractionalDigits: 6),
|
||||
);
|
||||
} catch (_) {
|
||||
return '0.00';
|
||||
return "0.00";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NoEtherState extends ExecutionState {}
|
||||
|
||||
enum DEuroActionType {
|
||||
deposit,
|
||||
withdraw,
|
||||
reinvest,
|
||||
none;
|
||||
}
|
||||
enum DEuroActionType { deposit, withdraw, reinvest, none }
|
||||
|
||||
@@ -110,10 +110,10 @@ abstract class PayjoinDetailsViewModelBase with Store {
|
||||
value: '${transactionInfo!.height}',
|
||||
key: ValueKey('standard_list_item_transaction_details_height_key'),
|
||||
),
|
||||
if (transactionInfo!.feeFormatted()?.isNotEmpty ?? false)
|
||||
if (transactionInfo!.fee != null)
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_fee,
|
||||
value: transactionInfo!.feeFormatted()!,
|
||||
value: transactionInfo!.fee!.toStringWithSymbol(),
|
||||
key: ValueKey('standard_list_item_transaction_details_fee_key'),
|
||||
),
|
||||
]);
|
||||
|
||||
@@ -93,7 +93,7 @@ abstract class PaymentViewModelBase with Store {
|
||||
if (currentWallet != null &&
|
||||
currentWallet.type == detectedWalletType &&
|
||||
!isEVMCompatibleChain(detectedWalletType!)) {
|
||||
return PaymentFlowResult.currentWalletCompatible();
|
||||
return PaymentFlowResult.currentWalletCompatible(detectionResult);
|
||||
}
|
||||
|
||||
if (detectedWalletType == WalletType.solana) {
|
||||
@@ -229,8 +229,12 @@ class PaymentFlowResult {
|
||||
);
|
||||
|
||||
/// Current wallet is compatible
|
||||
factory PaymentFlowResult.currentWalletCompatible() =>
|
||||
PaymentFlowResult._(type: PaymentFlowType.currentWalletCompatible);
|
||||
factory PaymentFlowResult.currentWalletCompatible(
|
||||
AddressDetectionResult addressDetectionResult) =>
|
||||
PaymentFlowResult._(
|
||||
type: PaymentFlowType.currentWalletCompatible,
|
||||
addressDetectionResult: addressDetectionResult,
|
||||
);
|
||||
|
||||
/// Single compatible wallet available
|
||||
factory PaymentFlowResult.singleWallet(
|
||||
|
||||
@@ -32,7 +32,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
||||
void reset() => filePath = '';
|
||||
|
||||
@action
|
||||
Future<void> import(String password) async {
|
||||
Future<void> import(String password,{bool checkBackupApp = true}) async {
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
|
||||
@@ -44,7 +44,9 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
||||
final file = File(filePath);
|
||||
|
||||
try {
|
||||
await backupService.importBackupFile(file, password);
|
||||
await backupService.importBackupFile(file, password, checkBackupApp: checkBackupApp);
|
||||
} on IncompatibleBackupAppException {
|
||||
rethrow;
|
||||
} catch (e, s) {
|
||||
if (e.toString().contains("unknown_backup_version")) {
|
||||
state = FailureState('This is not a valid backup file, please make sure you have selected the correct one');
|
||||
@@ -74,6 +76,9 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
||||
});
|
||||
|
||||
state = ExecutedSuccessfullyState();
|
||||
} on IncompatibleBackupAppException {
|
||||
state = InitialExecutionState();
|
||||
rethrow;
|
||||
} catch (e, s) {
|
||||
var msg = e.toString().toLowerCase();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:math' show min;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/decred/decred.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||
@@ -9,7 +8,6 @@ import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
|
||||
@@ -17,14 +15,12 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/amount/amount_sanitizer.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import 'package:cw_core/format_fixed.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -50,7 +46,7 @@ abstract class OutputBase with Store {
|
||||
note = '',
|
||||
memo = "",
|
||||
extractedAddress = '',
|
||||
estimatedFee = '0.0',
|
||||
estimatedFee = Money.zero(cryptoCurrencyHandler()),
|
||||
parsedAddress = ParsedAddress(addresses: []) {
|
||||
autorun((_) {
|
||||
final status = _wallet.syncStatus;
|
||||
@@ -64,6 +60,9 @@ abstract class OutputBase with Store {
|
||||
|
||||
bool get useSatoshi => _appStore.amountParsingProxy.useSatoshi(cryptoCurrencyHandler());
|
||||
|
||||
@observable
|
||||
bool isFiatEntry = false;
|
||||
|
||||
@observable
|
||||
String fiatAmount;
|
||||
|
||||
@@ -74,8 +73,7 @@ abstract class OutputBase with Store {
|
||||
String? displayName;
|
||||
|
||||
@computed
|
||||
String get displayCryptoAmount =>
|
||||
_appStore.amountParsingProxy.getDisplayCryptoAmount(cryptoAmount, cryptoCurrencyHandler());
|
||||
String get displayCryptoAmount => _appStore.amountParsingProxy.asDisplayString(cryptoAmountMoney);
|
||||
|
||||
@observable
|
||||
String cryptoFullBalance;
|
||||
@@ -106,9 +104,8 @@ abstract class OutputBase with Store {
|
||||
String roundedCryptoAmount(int digits) => displayCryptoAmount.withMaxDecimals(digits);
|
||||
|
||||
String roundedFiatAmount(int digits) {
|
||||
if (fiatAmount.split(".").last.length <= digits) {
|
||||
return fiatAmount;
|
||||
}
|
||||
if (fiatAmount.split(".").last.length <= digits) return fiatAmount;
|
||||
|
||||
return double.tryParse(fiatAmount.replaceAll(",", ""))?.toStringAsPrecision(digits) ?? '0.0';
|
||||
}
|
||||
|
||||
@@ -116,65 +113,18 @@ abstract class OutputBase with Store {
|
||||
String? stealthAddress;
|
||||
|
||||
@computed
|
||||
int get formattedCryptoAmount {
|
||||
int amount = 0;
|
||||
Money get cryptoAmountMoney {
|
||||
if (cryptoAmount.isEmpty) return Money.zero(cryptoCurrencyHandler());
|
||||
|
||||
try {
|
||||
if (cryptoAmount.isNotEmpty) {
|
||||
final _cryptoAmount = cryptoAmount.replaceAll(',', '.');
|
||||
int _amount = 0;
|
||||
switch (walletType) {
|
||||
case WalletType.monero:
|
||||
_amount = monero!.formatterMoneroParseAmount(amount: _cryptoAmount);
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.dogecoin:
|
||||
_amount = cryptoCurrencyHandler().parseAmount(_cryptoAmount).toInt();
|
||||
break;
|
||||
case WalletType.decred:
|
||||
_amount = decred!.formatterStringDoubleToDecredAmount(_cryptoAmount);
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.base:
|
||||
case WalletType.arbitrum:
|
||||
case WalletType.bsc:
|
||||
_amount = evm!.formatterEVMParseAmount(_cryptoAmount);
|
||||
break;
|
||||
case WalletType.wownero:
|
||||
_amount = wownero!.formatterWowneroParseAmount(amount: _cryptoAmount);
|
||||
break;
|
||||
case WalletType.zano:
|
||||
_amount = zano!
|
||||
.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.zcash:
|
||||
_amount = zcash!.formatterZcashParseAmount(_cryptoAmount);
|
||||
break;
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_amount > 0) {
|
||||
amount = _amount;
|
||||
}
|
||||
}
|
||||
return cryptoCurrencyHandler().parseAmount(cryptoAmount.sanitized());
|
||||
} catch (e) {
|
||||
amount = 0;
|
||||
return Money.zero(cryptoCurrencyHandler());
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
@observable
|
||||
String estimatedFee;
|
||||
Money estimatedFee;
|
||||
|
||||
@action
|
||||
Future<void> calculateEstimatedFee() async {
|
||||
@@ -188,7 +138,7 @@ abstract class OutputBase with Store {
|
||||
if (_settingsStore.getPriority(_wallet.type, chainId: _wallet.chainId) != null) {
|
||||
fee = _wallet.calculateEstimatedFee(
|
||||
_settingsStore.getPriority(_wallet.type, chainId: _wallet.chainId)!,
|
||||
formattedCryptoAmount,
|
||||
cryptoAmountMoney.amount.toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -199,41 +149,35 @@ abstract class OutputBase with Store {
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.dogecoin:
|
||||
case WalletType.decred:
|
||||
estimatedFee = walletTypeToCryptoCurrency(_wallet.type).formatAmount(BigInt.from(fee));
|
||||
case WalletType.zano:
|
||||
estimatedFee = Money.fromInt(fee, walletTypeToCryptoCurrency(_wallet.type));
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
if (cryptoCurrencyHandler() == CryptoCurrency.btcln) {
|
||||
estimatedFee =
|
||||
_appStore.amountParsingProxy.getDisplayCryptoString(10, cryptoCurrencyHandler());
|
||||
estimatedFee = Money.fromInt(10, cryptoCurrencyHandler());
|
||||
break;
|
||||
}
|
||||
if (_settingsStore.getPriority(_wallet.type) ==
|
||||
bitcoin!.getBitcoinTransactionPriorityCustom()) {
|
||||
fee = bitcoin!.getEstimatedFeeWithFeeRate(
|
||||
_wallet, _settingsStore.customBitcoinFeeRate, formattedCryptoAmount);
|
||||
_wallet, _settingsStore.customBitcoinFeeRate, cryptoAmountMoney.amount.toInt());
|
||||
}
|
||||
|
||||
estimatedFee = _appStore.amountParsingProxy.getDisplayCryptoString(fee, cryptoCurrencyHandler());
|
||||
estimatedFee = Money.fromInt(fee, cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.solana:
|
||||
estimatedFee = solana!.getEstimateFees(_wallet).toString();
|
||||
break;
|
||||
case WalletType.zano:
|
||||
estimatedFee = zano!
|
||||
.formatterIntAmountToDouble(
|
||||
amount: fee, currency: cryptoCurrencyHandler(), forFee: true)
|
||||
.toString();
|
||||
estimatedFee = solana!.getEstimateFees(_wallet) ?? Money.zero(CryptoCurrency.sol);
|
||||
break;
|
||||
case WalletType.tron:
|
||||
if (cryptoCurrencyHandler() == CryptoCurrency.trx) {
|
||||
estimatedFee = tron!.getTronNativeEstimatedFee(_wallet).toString();
|
||||
estimatedFee = tron!.getTronNativeEstimatedFee(_wallet) ?? Money.zero(CryptoCurrency.trx);
|
||||
} else {
|
||||
estimatedFee = tron!.getTronTRC20EstimatedFee(_wallet).toString();
|
||||
estimatedFee = tron!.getTronTRC20EstimatedFee(_wallet) ?? Money.zero(CryptoCurrency.trx);
|
||||
}
|
||||
break;
|
||||
|
||||
case WalletType.zcash:
|
||||
estimatedFee = zcash!.formatterZcashAmountToDouble(amount: BigInt.from(fee)).toString();
|
||||
estimatedFee = Money.fromInt(fee, cryptoCurrencyHandler());
|
||||
break;
|
||||
|
||||
/// EVMs
|
||||
@@ -242,16 +186,19 @@ abstract class OutputBase with Store {
|
||||
case WalletType.base:
|
||||
case WalletType.arbitrum:
|
||||
case WalletType.bsc:
|
||||
final isNative = cryptoCurrencyHandler() == CryptoCurrency.eth ||
|
||||
cryptoCurrencyHandler() == CryptoCurrency.maticpoly ||
|
||||
cryptoCurrencyHandler() == CryptoCurrency.baseEth ||
|
||||
cryptoCurrencyHandler() == CryptoCurrency.arbEth ||
|
||||
cryptoCurrencyHandler() == CryptoCurrency.bnb;
|
||||
String? fee = isNative
|
||||
final isNative = [
|
||||
CryptoCurrency.eth,
|
||||
CryptoCurrency.maticpoly,
|
||||
CryptoCurrency.baseEth,
|
||||
CryptoCurrency.arbEth,
|
||||
CryptoCurrency.bnb
|
||||
].contains(cryptoCurrencyHandler());
|
||||
|
||||
final fee = isNative
|
||||
? evm!.getEVMNativeEstimatedFee(_wallet)
|
||||
: evm!.getEVMERC20EstimatedFee(_wallet);
|
||||
|
||||
estimatedFee = formatFixed(BigInt.parse(fee ?? '0.0'), 18, fractionalDigits: 12);
|
||||
estimatedFee = Money(BigInt.parse(fee ?? '0.0'), walletTypeToCryptoCurrency(_wallet.type));
|
||||
break;
|
||||
|
||||
/// end EVMs
|
||||
@@ -275,12 +222,12 @@ abstract class OutputBase with Store {
|
||||
|
||||
try {
|
||||
final currency = (isEVMCompatibleChain(_wallet.type) ||
|
||||
[WalletType.solana, WalletType.tron].contains(_wallet.type))
|
||||
[WalletType.solana, WalletType.tron].contains(_wallet.type)) ||
|
||||
cryptoCurrencyHandler() == CryptoCurrency.btcln
|
||||
? _wallet.currency
|
||||
: cryptoCurrencyHandler();
|
||||
|
||||
final cryptoAmount =
|
||||
double.parse(_appStore.amountParsingProxy.getCanonicalCryptoAmount(estimatedFee, currency));
|
||||
final cryptoAmount = double.parse(estimatedFee.toString());
|
||||
|
||||
return calculateFiatAmountRaw(
|
||||
price: _fiatConversationStore.prices[currency]!, cryptoAmount: cryptoAmount);
|
||||
@@ -294,7 +241,7 @@ abstract class OutputBase with Store {
|
||||
|
||||
WalletType get walletType => _wallet.type;
|
||||
|
||||
final CryptoCurrency Function() cryptoCurrencyHandler;
|
||||
final CryptoCurrency Function([CryptoCurrency?]) cryptoCurrencyHandler;
|
||||
final FiatConversionStore _fiatConversationStore;
|
||||
final AppStore _appStore;
|
||||
|
||||
@@ -401,6 +348,10 @@ abstract class OutputBase with Store {
|
||||
if(parsedAddress.name.isNotEmpty) {
|
||||
displayName = parsedAddress.name;
|
||||
}
|
||||
|
||||
if (parsedAddress.parseFrom == ParseFrom.lnurlpay) {
|
||||
cryptoCurrencyHandler(CryptoCurrency.btcln);
|
||||
}
|
||||
extractedAddress = await extractAddressFromParsed(context, parsedAddress);
|
||||
note = parsedAddress.description;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_mod
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
@@ -121,7 +122,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
fiatFromSettings = _appStore.settingsStore.fiatCurrency,
|
||||
fiatCurrencies = FiatCurrency.all,
|
||||
super(appStore: _appStore) {
|
||||
outputs.add(Output(wallet, _appStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
||||
outputs.add(Output(wallet, _appStore, _fiatConversationStore, _outputCryptoCurrencyHandler));
|
||||
|
||||
unspentCoinsListViewModel
|
||||
.initialSetup()
|
||||
@@ -162,12 +163,19 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
|
||||
bool get isEVMWallet => isEVMCompatibleChain(walletType);
|
||||
|
||||
@action
|
||||
CryptoCurrency _outputCryptoCurrencyHandler([CryptoCurrency? override]) {
|
||||
if (override != null && override != selectedCryptoCurrency) selectedCryptoCurrency = override;
|
||||
|
||||
return selectedCryptoCurrency;
|
||||
}
|
||||
|
||||
@action
|
||||
void setShowAddressBookPopup(bool value) => _settingsStore.showAddressBookPopupEnabled = value;
|
||||
|
||||
@action
|
||||
void addOutput() =>
|
||||
outputs.add(Output(wallet, _appStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
||||
outputs.add(Output(wallet, _appStore, _fiatConversationStore, _outputCryptoCurrencyHandler));
|
||||
|
||||
@action
|
||||
void removeOutput(Output output) {
|
||||
@@ -310,10 +318,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
// Handle case where balance might not be available yet (e.g., during chain switch)
|
||||
final balanceForCurrency = wallet.balance[selectedCryptoCurrency];
|
||||
if (balanceForCurrency == null) {
|
||||
return _appStore.amountParsingProxy.getDisplayCryptoString(0, selectedCryptoCurrency);
|
||||
return _appStore.amountParsingProxy.asDisplayString(Money.zero(selectedCryptoCurrency));
|
||||
}
|
||||
return _appStore.amountParsingProxy.getDisplayCryptoStringFromBigInt(
|
||||
wallet.balance[selectedCryptoCurrency]!.fullAvailableBalance, selectedCryptoCurrency);
|
||||
return _appStore.amountParsingProxy
|
||||
.asDisplayString(wallet.balance[selectedCryptoCurrency]!.available);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -340,7 +348,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
// only for electrum, monero, wownero, decred wallets atm:
|
||||
switch (wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
if (coinTypeToSpendFrom == UnspentCoinType.lightning) return balance;
|
||||
if (selectedCryptoCurrency == CryptoCurrency.btcln) return balance;
|
||||
return _appStore.amountParsingProxy.getDisplayCryptoString(
|
||||
await unspentCoinsListViewModel.getSendingBalance(coinTypeToSpendFrom),
|
||||
walletTypeToCryptoCurrency(walletType));
|
||||
@@ -420,6 +428,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
String get selectedCryptoCurrencySymbol =>
|
||||
amountParsingProxy.getCryptoSymbol(selectedCryptoCurrency);
|
||||
|
||||
@computed
|
||||
bool get useBaseUnits => amountParsingProxy.useSatoshi(selectedCryptoCurrency);
|
||||
|
||||
List<CryptoCurrency> currencies;
|
||||
|
||||
WalletType get walletType => wallet.type;
|
||||
@@ -681,7 +692,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
wallet,
|
||||
routerTo,
|
||||
routerData,
|
||||
BigInt.zero,
|
||||
Money.zero(wallet.currency),
|
||||
priority,
|
||||
useBlinkProtection: canSupportBlinkProtection(selectedChainId)
|
||||
? _settingsStore.useBlinkProtection
|
||||
@@ -804,7 +815,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
wallet,
|
||||
routerTo,
|
||||
routerData,
|
||||
routerValueWei,
|
||||
Money(routerValueWei, wallet.currency),
|
||||
priority,
|
||||
sourceTokenAddress: tokenContract,
|
||||
sourceTokenAmount: requiredAmount,
|
||||
@@ -842,7 +853,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
// Fallback to estimate if not available
|
||||
final fee = actualFee > 0 ? actualFee : 0.0005;
|
||||
|
||||
final amount = double.tryParse(trade.amount) ?? 0.0;
|
||||
final fromCurrency = trade.from ?? CryptoCurrency.sol;
|
||||
final amount = Money.tryParse(trade.amount, fromCurrency) ?? Money.zero(fromCurrency);
|
||||
|
||||
pendingTransaction = await solana!.signAndPrepareJupiterSwapTransaction(
|
||||
wallet,
|
||||
@@ -850,7 +862,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
requestId!,
|
||||
trade.payoutAddress ?? '',
|
||||
amount,
|
||||
fee,
|
||||
Money.tryParse(fee.toString(), CryptoCurrency.sol) ?? Money.zero(CryptoCurrency.sol),
|
||||
);
|
||||
|
||||
state = ExecutedSuccessfullyState();
|
||||
@@ -1104,41 +1116,41 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
// instead, they rely on the tx to eventually get fetched at sync time, which can take a while
|
||||
if(isEVMWallet) {
|
||||
wallet.transactionHistory.addOne(evm!.getTransactionInfo(
|
||||
id: pendingTransaction!.evmTxHashFromRawHex!,
|
||||
height: 0,
|
||||
// FIXME(malik) this is even more critical given all the issues we had with decimal point parsing. with money it'll be easy
|
||||
ethAmount: selectedCryptoCurrency.parseAmount(outputs.first.cryptoAmount),
|
||||
ethFee: CryptoCurrency.eth.parseAmount(pendingTransaction!.feeFormattedValue),
|
||||
tokenSymbol: selectedCryptoCurrency.title,
|
||||
direction: TransactionDirection.outgoing,
|
||||
isPending: true,
|
||||
date: DateTime.now(),
|
||||
confirmations: 0,
|
||||
chainId: wallet.chainId ?? 0));
|
||||
id: pendingTransaction!.evmTxHashFromRawHex!,
|
||||
height: 0,
|
||||
amount: outputs.first.cryptoAmountMoney,
|
||||
fee: pendingTransaction!.fee,
|
||||
tokenSymbol: selectedCryptoCurrency.title,
|
||||
direction: TransactionDirection.outgoing,
|
||||
isPending: true,
|
||||
date: DateTime.now(),
|
||||
confirmations: 0,
|
||||
chainId: wallet.chainId ?? 0,
|
||||
));
|
||||
}
|
||||
|
||||
if(walletType == WalletType.solana) {
|
||||
wallet.transactionHistory.addOne(solana!.getTransactionInfo(
|
||||
id: pendingTransaction!.id,
|
||||
blockTime: DateTime.now(),
|
||||
tokenSymbol: selectedCryptoCurrency.title,
|
||||
to: "",
|
||||
from: "",
|
||||
direction: TransactionDirection.outgoing,
|
||||
solAmount: solana!.getPendingTransactionAmount(pendingTransaction!),
|
||||
isPending: true,
|
||||
txFee: solana!.getPendingTransactionFee(pendingTransaction!)));
|
||||
id: pendingTransaction!.id,
|
||||
blockTime: DateTime.now(),
|
||||
to: "",
|
||||
from: "",
|
||||
direction: TransactionDirection.outgoing,
|
||||
amount: pendingTransaction!.amount,
|
||||
isPending: true,
|
||||
fee: pendingTransaction!.fee,
|
||||
));
|
||||
}
|
||||
|
||||
if (walletType == WalletType.tron) {
|
||||
wallet.transactionHistory.addOne(tron!.getTransactionInfo(
|
||||
id: pendingTransaction!.id,
|
||||
blockTime: DateTime.now(),
|
||||
tokenSymbol: selectedCryptoCurrency.title,
|
||||
direction: TransactionDirection.outgoing,
|
||||
tronAmount: selectedCryptoCurrency.parseAmount(outputs.first.cryptoAmount),
|
||||
isPending: true,
|
||||
txFee: CryptoCurrency.trx.parseAmount(outputs.first.estimatedFee).toInt()));
|
||||
id: pendingTransaction!.id,
|
||||
blockTime: DateTime.now(),
|
||||
direction: TransactionDirection.outgoing,
|
||||
amount: outputs.first.cryptoAmountMoney,
|
||||
isPending: true,
|
||||
fee: outputs.first.estimatedFee,
|
||||
));
|
||||
}
|
||||
|
||||
if (pendingTransaction!.id.isNotEmpty) {
|
||||
@@ -1419,9 +1431,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
|
||||
return await evm!.createTokenApproval(
|
||||
wallet,
|
||||
requiredAmount,
|
||||
Money(requiredAmount, erc20Token),
|
||||
spender,
|
||||
erc20Token,
|
||||
priority,
|
||||
useBlinkProtection:
|
||||
canSupportBlinkProtection(selectedChainId) ? _settingsStore.useBlinkProtection : false,
|
||||
|
||||
@@ -23,8 +23,8 @@ abstract class TemplateViewModelBase with Store {
|
||||
_appStore = appStore,
|
||||
_fiatConversationStore = fiatConversationStore,
|
||||
_currency = wallet.currency,
|
||||
output = Output(wallet, appStore, fiatConversationStore, () => wallet.currency) {
|
||||
output = Output(_wallet, _appStore, _fiatConversationStore, () => _currency);
|
||||
output = Output(wallet, appStore, fiatConversationStore, ([_]) => wallet.currency) {
|
||||
output = Output(_wallet, _appStore, _fiatConversationStore, _outputCryptoCurrencyHandler);
|
||||
}
|
||||
|
||||
@observable
|
||||
@@ -53,15 +53,20 @@ abstract class TemplateViewModelBase with Store {
|
||||
output.reset();
|
||||
}
|
||||
|
||||
Template toTemplate({required String cryptoCurrency, required String fiatCurrency}) {
|
||||
return Template(
|
||||
Template toTemplate({required String cryptoCurrency, required String fiatCurrency}) => Template(
|
||||
isCurrencySelectedRaw: isCryptoSelected,
|
||||
nameRaw: name,
|
||||
addressRaw: address,
|
||||
cryptoCurrencyRaw: cryptoCurrency,
|
||||
fiatCurrencyRaw: fiatCurrency,
|
||||
amountRaw: output.cryptoAmount,
|
||||
amountFiatRaw: output.fiatAmount);
|
||||
amountFiatRaw: output.fiatAmount,
|
||||
);
|
||||
|
||||
CryptoCurrency _outputCryptoCurrencyHandler([CryptoCurrency? override]) {
|
||||
if (override != null && _currency != override) changeSelectedCurrency(override);
|
||||
|
||||
return _currency;
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -56,11 +56,11 @@ abstract class SupportViewModelBase with Store {
|
||||
icon: 'assets/images/change_now.png',
|
||||
linkTitle: 'support@changenow.io',
|
||||
link: 'mailto:support@changenow.io'),
|
||||
LinkListItem(
|
||||
title: 'SideShift',
|
||||
icon: 'assets/images/sideshift.png',
|
||||
linkTitle: 'help.sideshift.ai',
|
||||
link: 'https://help.sideshift.ai/en/'),
|
||||
// LinkListItem(
|
||||
// title: 'SideShift',
|
||||
// icon: 'assets/images/sideshift.png',
|
||||
// linkTitle: 'help.sideshift.ai',
|
||||
// link: 'https://help.sideshift.ai/en/'),
|
||||
LinkListItem(
|
||||
title: 'SimpleSwap',
|
||||
icon: 'assets/images/simpleSwap.png',
|
||||
|
||||
@@ -79,22 +79,22 @@ class TxDetailRowDefinition {
|
||||
title: S.current.transaction_details_date,
|
||||
valueGetter: (vm) => DateFormatter.withCurrentLocal().format(vm.transactionInfo.date)),
|
||||
|
||||
|
||||
TxDetailRowDefinition(
|
||||
keyString: "standard_list_item_transaction_details_height_key",
|
||||
title: S.current.transaction_details_height,
|
||||
valueGetter: (vm) => vm.transactionInfo.height?.toString() ?? "",
|
||||
applicable: (vm) => !([WalletType.solana, WalletType.tron].contains(vm.wallet.type) &&
|
||||
!isLightning(vm.transactionInfo))),
|
||||
|
||||
keyString: "standard_list_item_transaction_details_height_key",
|
||||
title: S.current.transaction_details_height,
|
||||
valueGetter: (vm) => vm.transactionInfo.height?.toString() ?? "",
|
||||
applicable: (vm) =>
|
||||
![WalletType.solana, WalletType.tron].contains(vm.wallet.type) ||
|
||||
!isLightning(vm.transactionInfo),
|
||||
),
|
||||
|
||||
TxDetailRowDefinition(
|
||||
keyString: "standard_list_item_transaction_details_fee_key",
|
||||
title: S.current.transaction_details_fee,
|
||||
valueGetter: (vm) => vm.transactionInfo.feeFormatted()!,
|
||||
valueGetter: (vm) => vm.transactionInfo.fee!.toStringWithSymbol(),
|
||||
applicable: (vm) =>
|
||||
vm.wallet.type != WalletType.nano &&
|
||||
(vm.transactionInfo.feeFormatted() ?? "").isNotEmpty),
|
||||
(vm.transactionInfo.fee?.toStringWithSymbol() ?? "").isNotEmpty),
|
||||
|
||||
|
||||
TxDetailRowDefinition(
|
||||
@@ -496,14 +496,15 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||
RBFListItems.add(
|
||||
StandartListItem(
|
||||
title: S.current.old_fee,
|
||||
value: tx.feeFormatted() ?? '0.0',
|
||||
value: tx.fee?.toStringWithSymbol() ?? '0.0',
|
||||
key: ValueKey('standard_list_item_rbf_old_fee_key'),
|
||||
),
|
||||
);
|
||||
|
||||
if (transactionInfo.fee != null && rawTransaction.isNotEmpty) {
|
||||
final size = bitcoin!.getTransactionVSize(wallet, rawTransaction);
|
||||
final recommendedRate = (transactionInfo.fee! / size).round() + 1;
|
||||
final recommendedRate = (transactionInfo.fee! / BigInt.from(size)) +
|
||||
transactionInfo.fee!.copyWith(amount: BigInt.one);
|
||||
|
||||
RBFListItems.add(
|
||||
StandartListItem(title: 'New recommended fee rate', value: '$recommendedRate sat/byte'));
|
||||
@@ -609,14 +610,14 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||
if (wallet.type == WalletType.bitcoin) {
|
||||
final crypto = isLightning(transactionInfo) ? CryptoCurrency.btcln : CryptoCurrency.btc;
|
||||
final amount = _appStore.amountParsingProxy
|
||||
.getDisplayCryptoString(transactionInfo.amount, crypto)
|
||||
.asDisplayString(transactionInfo.amount)
|
||||
.withMaxDecimals(8)
|
||||
.withLocalSeperator(_appStore.settingsStore.languageCode);
|
||||
|
||||
return '$amount ${_appStore.amountParsingProxy.getCryptoSymbol(crypto)}';
|
||||
}
|
||||
|
||||
return transactionInfo.amountFormatted();
|
||||
return transactionInfo.amount.toStringWithSymbol();
|
||||
}
|
||||
|
||||
void replaceByFee(String newFee) => sendViewModel.replaceByFee(transactionInfo, newFee);
|
||||
|
||||
@@ -614,11 +614,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||
void setAddress(WalletAddressListItem address) =>
|
||||
wallet.walletAddresses.address = address.address;
|
||||
|
||||
@observable
|
||||
bool isRotatingAddress = false;
|
||||
|
||||
@action
|
||||
Future<void> rotateAddress() async {
|
||||
await createNewAddress(wallet, "");
|
||||
if (isElectrumWallet) {
|
||||
if(isRotatingAddress) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
isRotatingAddress = true;
|
||||
await createNewAddress(wallet, "");
|
||||
wallet.walletAddresses.address = addressList.whereType<WalletAddressListItem>().last.address;
|
||||
} finally {
|
||||
isRotatingAddress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user