mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-05-06 21:02:17 +00:00
WIP use Amount
This commit is contained in:
parent
2936c1b807
commit
81c612ddd7
104 changed files with 2211 additions and 1890 deletions
lib
db
models
pages
coin_control
exchange_view
confirm_change_now_send.dart
exchange_step_views
send_from_view.dartsub_widgets
trade_details_view.dartpaynym
dialogs
subwidgets
send_view
settings_views/global_settings_view/syncing_preferences_views
token_view/sub_widgets
wallet_view
wallets_view/sub_widgets
pages_desktop_specific
coin_control
desktop_exchange
my_stack_view
services
coins
bitcoin
bitcoincash
coin_service.dartdogecoin
epiccash
ethereum
firo
litecoin
manager.dartmonero
namecoin
particl
wownero
ethereum
mixins
utilities
widgets
test
pages/send_view
screen_tests
address_book_view/subviews
add_address_book_view_screen_test.mocks.dartaddress_book_entry_details_view_screen_test.mocks.dartedit_address_book_entry_view_screen_test.mocks.dart
lockscreen_view_screen_test.mocks.dartmain_view_tests
main_view_screen_testA_test.mocks.dartmain_view_screen_testB_test.mocks.dartmain_view_screen_testC_test.mocks.dart
onboarding
backup_key_view_screen_test.mocks.dartbackup_key_warning_view_screen_test.mocks.dartcreate_pin_view_screen_test.mocks.dartrestore_wallet_view_screen_test.mocks.dartverify_backup_key_view_screen_test.mocks.dart
settings_view
settings_subviews
currency_view_screen_test.mocks.dart
settings_view_screen_test.mocks.dartnetwork_settings_subviews
wallet_backup_view_screen_test.mocks.dartwallet_settings_subviews
wallet_settings_view_screen_test.mocks.darttransaction_subviews
wallet_view
services/coins
widget_tests
|
@ -3,6 +3,7 @@ import 'package:flutter_native_splash/cli_commands.dart';
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/exceptions/main_db/main_db_exception.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
|
|
@ -67,10 +67,10 @@ extension MainDBQueries on MainDB {
|
|||
final maybeDecimal = Decimal.tryParse(searchTerm);
|
||||
if (maybeDecimal != null) {
|
||||
qq = qq.or().valueEqualTo(
|
||||
Format.decimalAmountToSatoshis(
|
||||
Amount.fromDecimal(
|
||||
maybeDecimal,
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -139,10 +139,10 @@ extension MainDBQueries on MainDB {
|
|||
final maybeDecimal = Decimal.tryParse(searchTerm);
|
||||
if (maybeDecimal != null) {
|
||||
qq = qq.or().valueEqualTo(
|
||||
Format.decimalAmountToSatoshis(
|
||||
Amount.fromDecimal(
|
||||
maybeDecimal,
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
|
||||
enum Unit {
|
||||
base,
|
||||
u,
|
||||
m,
|
||||
normal;
|
||||
}
|
||||
|
||||
class Balance {
|
||||
final Coin coin;
|
||||
final int total;
|
||||
final int spendable;
|
||||
final int blockedTotal;
|
||||
final int pendingSpendable;
|
||||
final Amount total;
|
||||
final Amount spendable;
|
||||
final Amount blockedTotal;
|
||||
final Amount pendingSpendable;
|
||||
|
||||
Balance({
|
||||
required this.coin,
|
||||
|
@ -19,36 +25,64 @@ class Balance {
|
|||
required this.pendingSpendable,
|
||||
});
|
||||
|
||||
Decimal getTotal({bool includeBlocked = true}) => Format.satoshisToAmount(
|
||||
includeBlocked ? total : total - blockedTotal,
|
||||
coin: coin,
|
||||
);
|
||||
// Decimal getTotal({bool includeBlocked = true}) => Format.satoshisToAmount(
|
||||
// includeBlocked ? total : total - blockedTotal,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// Decimal getSpendable() => Format.satoshisToAmount(
|
||||
// spendable,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// Decimal getPending() => Format.satoshisToAmount(
|
||||
// pendingSpendable,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// Decimal getBlocked() => Format.satoshisToAmount(
|
||||
// blockedTotal,
|
||||
// coin: coin,
|
||||
// );
|
||||
|
||||
Decimal getSpendable() => Format.satoshisToAmount(
|
||||
spendable,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
Decimal getPending() => Format.satoshisToAmount(
|
||||
pendingSpendable,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
Decimal getBlocked() => Format.satoshisToAmount(
|
||||
blockedTotal,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
String toJsonIgnoreCoin() => jsonEncode(toMap()..remove("coin"));
|
||||
String toJsonIgnoreCoin() => jsonEncode({
|
||||
"total": total.toJsonString(),
|
||||
"spendable": spendable.toJsonString(),
|
||||
"blockedTotal": blockedTotal.toJsonString(),
|
||||
"pendingSpendable": pendingSpendable.toJsonString(),
|
||||
});
|
||||
|
||||
// need to fall back to parsing from in due to cached balances being previously
|
||||
// stored as int values instead of Amounts
|
||||
factory Balance.fromJson(String json, Coin coin) {
|
||||
final decoded = jsonDecode(json);
|
||||
return Balance(
|
||||
coin: coin,
|
||||
total: decoded["total"] as int,
|
||||
spendable: decoded["spendable"] as int,
|
||||
blockedTotal: decoded["blockedTotal"] as int,
|
||||
pendingSpendable: decoded["pendingSpendable"] as int,
|
||||
total: decoded["total"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["total"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["total"] as int),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
spendable: decoded["spendable"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["spendable"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["spendable"] as int),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
blockedTotal: decoded["blockedTotal"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["blockedTotal"] as int),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: decoded["pendingSpendable"] is String
|
||||
? Amount.fromSerializedJsonString(
|
||||
decoded["pendingSpendable"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["pendingSpendable"] as int),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/models/balance.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
|
||||
class TokenBalance extends Balance {
|
||||
TokenBalance({
|
||||
required this.contractAddress,
|
||||
required this.decimalPlaces,
|
||||
required super.total,
|
||||
required super.spendable,
|
||||
required super.blockedTotal,
|
||||
|
@ -17,37 +15,35 @@ class TokenBalance extends Balance {
|
|||
});
|
||||
|
||||
final String contractAddress;
|
||||
final int decimalPlaces;
|
||||
|
||||
@override
|
||||
Decimal getTotal({bool includeBlocked = false}) =>
|
||||
Format.satoshisToEthTokenAmount(
|
||||
includeBlocked ? total : total - blockedTotal,
|
||||
decimalPlaces,
|
||||
);
|
||||
|
||||
@override
|
||||
Decimal getSpendable() => Format.satoshisToEthTokenAmount(
|
||||
spendable,
|
||||
decimalPlaces,
|
||||
);
|
||||
|
||||
@override
|
||||
Decimal getPending() => Format.satoshisToEthTokenAmount(
|
||||
pendingSpendable,
|
||||
decimalPlaces,
|
||||
);
|
||||
|
||||
@override
|
||||
Decimal getBlocked() => Format.satoshisToEthTokenAmount(
|
||||
blockedTotal,
|
||||
decimalPlaces,
|
||||
);
|
||||
// @override
|
||||
// Decimal getTotal({bool includeBlocked = false}) =>
|
||||
// Format.satoshisToEthTokenAmount(
|
||||
// includeBlocked ? total : total - blockedTotal,
|
||||
// decimalPlaces,
|
||||
// );
|
||||
//
|
||||
// @override
|
||||
// Decimal getSpendable() => Format.satoshisToEthTokenAmount(
|
||||
// spendable,
|
||||
// decimalPlaces,
|
||||
// );
|
||||
//
|
||||
// @override
|
||||
// Decimal getPending() => Format.satoshisToEthTokenAmount(
|
||||
// pendingSpendable,
|
||||
// decimalPlaces,
|
||||
// );
|
||||
//
|
||||
// @override
|
||||
// Decimal getBlocked() => Format.satoshisToEthTokenAmount(
|
||||
// blockedTotal,
|
||||
// decimalPlaces,
|
||||
// );
|
||||
|
||||
@override
|
||||
String toJsonIgnoreCoin() => jsonEncode({
|
||||
"contractAddress": contractAddress,
|
||||
"decimalPlaces": decimalPlaces,
|
||||
"total": total,
|
||||
"spendable": spendable,
|
||||
"blockedTotal": blockedTotal,
|
||||
|
@ -56,15 +52,36 @@ class TokenBalance extends Balance {
|
|||
|
||||
factory TokenBalance.fromJson(
|
||||
String json,
|
||||
int fractionDigits,
|
||||
) {
|
||||
final decoded = jsonDecode(json);
|
||||
return TokenBalance(
|
||||
contractAddress: decoded["contractAddress"] as String,
|
||||
decimalPlaces: decoded["decimalPlaces"] as int,
|
||||
total: decoded["total"] as int,
|
||||
spendable: decoded["spendable"] as int,
|
||||
blockedTotal: decoded["blockedTotal"] as int,
|
||||
pendingSpendable: decoded["pendingSpendable"] as int,
|
||||
total: decoded["total"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["total"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["total"] as int),
|
||||
fractionDigits: fractionDigits,
|
||||
),
|
||||
spendable: decoded["spendable"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["spendable"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["spendable"] as int),
|
||||
fractionDigits: fractionDigits,
|
||||
),
|
||||
blockedTotal: decoded["blockedTotal"] is String
|
||||
? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["blockedTotal"] as int),
|
||||
fractionDigits: fractionDigits,
|
||||
),
|
||||
pendingSpendable: decoded["pendingSpendable"] is String
|
||||
? Amount.fromSerializedJsonString(
|
||||
decoded["pendingSpendable"] as String)
|
||||
: Amount(
|
||||
rawValue: BigInt.from(decoded["pendingSpendable"] as int),
|
||||
fractionDigits: fractionDigits,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import 'package:stackwallet/utilities/amount.dart';
|
||||
|
||||
class TransactionFilter {
|
||||
final bool sent;
|
||||
final bool received;
|
||||
final bool trade;
|
||||
final DateTime? from;
|
||||
final DateTime? to;
|
||||
final int? amount;
|
||||
final Amount? amount;
|
||||
final String keyword;
|
||||
|
||||
TransactionFilter({
|
||||
|
@ -23,7 +25,7 @@ class TransactionFilter {
|
|||
bool? trade,
|
||||
DateTime? from,
|
||||
DateTime? to,
|
||||
int? amount,
|
||||
Amount? amount,
|
||||
String? keyword,
|
||||
}) {
|
||||
return TransactionFilter(
|
||||
|
|
|
@ -8,12 +8,13 @@ import 'package:stackwallet/db/isar/main_db.dart';
|
|||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/pages/coin_control/utxo_card.dart';
|
||||
import 'package:stackwallet/pages/coin_control/utxo_details_view.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/services/mixins/coin_control_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart';
|
||||
|
@ -682,12 +683,14 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> {
|
|||
value += element,
|
||||
);
|
||||
return Text(
|
||||
"${Format.satoshisToAmount(
|
||||
selectedSum,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
"${selectedSum.toAmount(fractionDigits: coin.decimals).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: widget.requestedTotal == null
|
||||
? STextStyles.w600_14(context)
|
||||
: STextStyles.w600_14(context).copyWith(
|
||||
|
@ -728,12 +731,14 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> {
|
|||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
widget.requestedTotal!,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
"${widget.requestedTotal!.toAmount(fractionDigits: coin.decimals).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -2,10 +2,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
|
@ -123,10 +124,13 @@ class _UtxoCardState extends ConsumerState<UtxoCard> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
"${utxo.value.toAmount(fractionDigits: coin.decimals).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)}} ${coin.ticker}",
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
|
|
@ -6,9 +6,10 @@ import 'package:isar/isar.dart';
|
|||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -239,12 +240,13 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
width: 16,
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo!.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
"${utxo!.value.toAmount(fractionDigits: coin.decimals).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.pageTitleH2(context),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -11,9 +11,9 @@ import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub
|
|||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -359,14 +359,10 @@ class _ConfirmChangeNowSendViewState
|
|||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(
|
||||
(transactionInfo["fee"] as int),
|
||||
ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
"${(transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: ref.watch(
|
||||
managerProvider
|
||||
.select((value) => value.coin.decimals),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
|
@ -400,26 +396,37 @@ class _ConfirmChangeNowSendViewState
|
|||
.textConfirmTotalAmount,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(
|
||||
(transactionInfo["fee"] as int) +
|
||||
(transactionInfo["recipientAmt"] as int),
|
||||
ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
ref.watch(
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final coin = ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
final fee =
|
||||
(transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
final amount =
|
||||
transactionInfo["recipientAmt"] as Amount;
|
||||
final total = amount + fee;
|
||||
final locale = ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
);
|
||||
return Text(
|
||||
"${total.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)}"
|
||||
" ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -570,16 +577,20 @@ class _ConfirmChangeNowSendViewState
|
|||
final price = ref.watch(
|
||||
priceAnd24hChangeNotifierProvider
|
||||
.select((value) => value.getPrice(coin)));
|
||||
final amount = Format.satoshisToAmount(
|
||||
transactionInfo["recipientAmt"] as int,
|
||||
coin: coin,
|
||||
);
|
||||
final value = price.item1 * amount;
|
||||
final amount =
|
||||
transactionInfo["recipientAmt"] as Amount;
|
||||
final value = (price.item1 * amount.decimal)
|
||||
.toAmount(fractionDigits: 2);
|
||||
final currency = ref.watch(prefsChangeNotifierProvider
|
||||
.select((value) => value.currency));
|
||||
final locale = ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
);
|
||||
|
||||
return Text(
|
||||
" | ${value.toStringAsFixed(Constants.decimalPlacesForCoin(coin))} $currency",
|
||||
" | ${value.localizedStringAsFixed(locale: locale)} $currency",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
|
@ -592,12 +603,13 @@ class _ConfirmChangeNowSendViewState
|
|||
],
|
||||
),
|
||||
child: Text(
|
||||
"${Format.satoshiAmountToPrettyString(transactionInfo["recipientAmt"] as int, ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
))} ${ref.watch(
|
||||
"${(transactionInfo["recipientAmt"] as Amount).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
|
@ -625,12 +637,17 @@ class _ConfirmChangeNowSendViewState
|
|||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(transactionInfo["fee"] as int, ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
))} ${ref.watch(
|
||||
"${(transactionInfo["fee"] as int).toAmount(fractionDigits: ref.watch(
|
||||
managerProvider.select(
|
||||
(value) => value.coin.decimals,
|
||||
),
|
||||
)).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
|
@ -711,21 +728,35 @@ class _ConfirmChangeNowSendViewState
|
|||
.textConfirmTotalAmount,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString((transactionInfo["fee"] as int) + (transactionInfo["recipientAmt"] as int), ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
))} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final coin = ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
);
|
||||
final fee = (transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
final amount =
|
||||
transactionInfo["recipientAmt"] as Amount;
|
||||
final total = amount + fee;
|
||||
final locale = ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
);
|
||||
return Text(
|
||||
"${total.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)}"
|
||||
" ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -15,11 +15,11 @@ import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dia
|
|||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
|
@ -526,10 +526,11 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
walletsChangeNotifierProvider)
|
||||
.getManager(tuple.item1);
|
||||
|
||||
final amount =
|
||||
Format.decimalAmountToSatoshis(
|
||||
model.sendAmount,
|
||||
manager.coin);
|
||||
final Amount amount =
|
||||
model.sendAmount.toAmount(
|
||||
fractionDigits:
|
||||
manager.coin.decimals,
|
||||
);
|
||||
final address =
|
||||
model.trade!.payInAddress;
|
||||
|
||||
|
@ -565,7 +566,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
final txDataFuture =
|
||||
manager.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate":
|
||||
FeeRateType.average,
|
||||
|
@ -670,12 +671,17 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
.useMaterialPageRoute,
|
||||
builder:
|
||||
(BuildContext context) {
|
||||
final coin =
|
||||
coinFromTickerCaseInsensitive(
|
||||
model.trade!
|
||||
.payInCurrency);
|
||||
return SendFromView(
|
||||
coin:
|
||||
coinFromTickerCaseInsensitive(
|
||||
model.trade!
|
||||
.payInCurrency),
|
||||
amount: model.sendAmount,
|
||||
coin: coin,
|
||||
amount: model.sendAmount
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals,
|
||||
),
|
||||
address: model
|
||||
.trade!.payInAddress,
|
||||
trade: model.trade!,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -13,15 +12,14 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
|
@ -45,7 +43,7 @@ class SendFromView extends ConsumerStatefulWidget {
|
|||
static const String routeName = "/sendFrom";
|
||||
|
||||
final Coin coin;
|
||||
final Decimal amount;
|
||||
final Amount amount;
|
||||
final String address;
|
||||
final Trade trade;
|
||||
final bool shouldPopRoot;
|
||||
|
@ -57,14 +55,10 @@ class SendFromView extends ConsumerStatefulWidget {
|
|||
|
||||
class _SendFromViewState extends ConsumerState<SendFromView> {
|
||||
late final Coin coin;
|
||||
late final Decimal amount;
|
||||
late final Amount amount;
|
||||
late final String address;
|
||||
late final Trade trade;
|
||||
|
||||
String formatAmount(Decimal amount, Coin coin) {
|
||||
return amount.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
coin = widget.coin;
|
||||
|
@ -151,7 +145,13 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
|
|||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"You need to send ${formatAmount(amount, coin)} ${coin.ticker}",
|
||||
"You need to send ${amount.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
: STextStyles.itemSubtitle(context),
|
||||
|
@ -202,7 +202,7 @@ class SendFromCard extends ConsumerStatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final Decimal amount;
|
||||
final Amount amount;
|
||||
final String address;
|
||||
final Trade trade;
|
||||
final bool fromDesktopStep4;
|
||||
|
@ -213,13 +213,11 @@ class SendFromCard extends ConsumerStatefulWidget {
|
|||
|
||||
class _SendFromCardState extends ConsumerState<SendFromCard> {
|
||||
late final String walletId;
|
||||
late final Decimal amount;
|
||||
late final Amount amount;
|
||||
late final String address;
|
||||
late final Trade trade;
|
||||
|
||||
Future<void> _send(Manager manager, {bool? shouldSendPublicFiroFunds}) async {
|
||||
final _amount = Format.decimalAmountToSatoshis(amount, manager.coin);
|
||||
|
||||
try {
|
||||
bool wasCancelled = false;
|
||||
|
||||
|
@ -265,7 +263,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
if (shouldSendPublicFiroFunds == null) {
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
|
@ -277,7 +275,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
if (shouldSendPublicFiroFunds) {
|
||||
txDataFuture = firoWallet.prepareSendPublic(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
|
@ -286,7 +284,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
} else {
|
||||
txDataFuture = firoWallet.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
|
@ -452,37 +450,11 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
"Use private balance",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
FutureBuilder(
|
||||
// TODO redo this widget now that its not actually a future
|
||||
future: Future(() =>
|
||||
(manager.wallet as FiroWallet)
|
||||
.availablePrivateBalance()),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
Text(
|
||||
"${(manager.wallet as FiroWallet).availablePrivateBalance().localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -540,37 +512,11 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
"Use public balance",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
FutureBuilder(
|
||||
// TODO redo this widget now that its not actually a future
|
||||
future: Future(() =>
|
||||
(manager.wallet as FiroWallet)
|
||||
.availablePublicBalance()),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
Text(
|
||||
"${(manager.wallet as FiroWallet).availablePublicBalance().localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -652,35 +598,11 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
height: 2,
|
||||
),
|
||||
if (!isFiro)
|
||||
FutureBuilder(
|
||||
// TODO redo this widget now that its not actually a future
|
||||
future: Future(() => manager.balance.getTotal()),
|
||||
builder:
|
||||
(builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
Text(
|
||||
"${manager.balance.spendable.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -9,10 +9,9 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -198,18 +197,6 @@ class _ExchangeProviderOptionsState
|
|||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Decimal rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
}
|
||||
Coin coin;
|
||||
try {
|
||||
coin = coinFromTickerCaseInsensitive(
|
||||
|
@ -217,18 +204,32 @@ class _ExchangeProviderOptionsState
|
|||
} catch (_) {
|
||||
coin = Coin.bitcoin;
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals);
|
||||
}
|
||||
|
||||
return Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed(
|
||||
value: rate,
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
|
@ -435,18 +436,6 @@ class _ExchangeProviderOptionsState
|
|||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Decimal rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
}
|
||||
Coin coin;
|
||||
try {
|
||||
coin = coinFromTickerCaseInsensitive(
|
||||
|
@ -454,18 +443,32 @@ class _ExchangeProviderOptionsState
|
|||
} catch (_) {
|
||||
coin = Coin.bitcoin;
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
return Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed(
|
||||
value: rate,
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dar
|
|||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -256,11 +257,11 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
label: "Send from Stack",
|
||||
buttonHeight: ButtonHeight.l,
|
||||
onPressed: () {
|
||||
final amount = sendAmount;
|
||||
final address = trade.payInAddress;
|
||||
|
||||
final coin =
|
||||
coinFromTickerCaseInsensitive(trade.payInCurrency);
|
||||
final amount =
|
||||
sendAmount.toAmount(fractionDigits: coin.decimals);
|
||||
final address = trade.payInAddress;
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
SendFromView.routeName,
|
||||
|
@ -339,13 +340,32 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
"-${Format.localizedStringAsFixed(value: sendAmount, locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), decimalPlaces: trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8)} ${trade.payInCurrency.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
Builder(builder: (context) {
|
||||
String text;
|
||||
try {
|
||||
final coin = coinFromTickerCaseInsensitive(
|
||||
trade.payInCurrency);
|
||||
final amount = sendAmount.toAmount(
|
||||
fractionDigits: coin.decimals);
|
||||
text = amount.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
text = sendAmount.toStringAsFixed(
|
||||
trade.payInCurrency.toLowerCase() == "xmr"
|
||||
? 12
|
||||
: 8);
|
||||
}
|
||||
|
||||
return SelectableText(
|
||||
"-$text ${trade.payInCurrency.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
if (!isDesktop)
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -17,25 +16,22 @@ class ConfirmPaynymConnectDialog extends StatelessWidget {
|
|||
const ConfirmPaynymConnectDialog({
|
||||
Key? key,
|
||||
required this.nymName,
|
||||
required this.locale,
|
||||
required this.onConfirmPressed,
|
||||
required this.amount,
|
||||
required this.coin,
|
||||
}) : super(key: key);
|
||||
|
||||
final String nymName;
|
||||
final String locale;
|
||||
final VoidCallback onConfirmPressed;
|
||||
final int amount;
|
||||
final Amount amount;
|
||||
final Coin coin;
|
||||
|
||||
String get title => "Connect to $nymName";
|
||||
|
||||
String get message => "A one-time connection fee of "
|
||||
"${Format.satoshisToAmount(
|
||||
amount,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
)} ${coin.ticker} "
|
||||
"${amount.localizedStringAsFixed(locale: locale)} ${coin.ticker} "
|
||||
"will be charged to connect to this PayNym.\n\nThis fee "
|
||||
"covers the cost of creating a one-time transaction to create a "
|
||||
"record on the blockchain. This keeps PayNyms decentralized.";
|
||||
|
|
|
@ -13,9 +13,11 @@ import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
|||
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
|
||||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/send_view.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -134,6 +136,7 @@ class _PaynymDetailsPopupState extends ConsumerState<PaynymDetailsPopup> {
|
|||
context: context,
|
||||
builder: (context) => ConfirmPaynymConnectDialog(
|
||||
nymName: widget.accountLite.nymName,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
onConfirmPressed: () {
|
||||
//
|
||||
print("CONFIRM NOTIF TX: $preparedTx");
|
||||
|
@ -156,7 +159,10 @@ class _PaynymDetailsPopupState extends ConsumerState<PaynymDetailsPopup> {
|
|||
),
|
||||
);
|
||||
},
|
||||
amount: (preparedTx["amount"] as int) + (preparedTx["fee"] as int),
|
||||
amount: (preparedTx["amount"] as Amount) +
|
||||
(preparedTx["fee"] as int).toAmount(
|
||||
fractionDigits: manager.coin.decimals,
|
||||
),
|
||||
coin: manager.coin,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -12,8 +12,10 @@ import 'package:stackwallet/pages/paynym/dialogs/confirm_paynym_connect_dialog.d
|
|||
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
|
||||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -102,6 +104,7 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> {
|
|||
context: context,
|
||||
builder: (context) => ConfirmPaynymConnectDialog(
|
||||
nymName: widget.accountLite.nymName,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
onConfirmPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
unawaited(
|
||||
|
@ -139,7 +142,10 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> {
|
|||
),
|
||||
);
|
||||
},
|
||||
amount: (preparedTx["amount"] as int) + (preparedTx["fee"] as int),
|
||||
amount: (preparedTx["amount"] as Amount) +
|
||||
(preparedTx["fee"] as int).toAmount(
|
||||
fractionDigits: manager.coin.decimals,
|
||||
),
|
||||
coin: manager.coin,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -18,10 +18,10 @@ import 'package:stackwallet/route_generator.dart';
|
|||
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -403,12 +403,12 @@ class _ConfirmTransactionViewState
|
|||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(transactionInfo["recipientAmt"] as int, ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
))} $unit",
|
||||
"${(transactionInfo["recipientAmt"] as Amount).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
)} $unit",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
|
@ -427,12 +427,18 @@ class _ConfirmTransactionViewState
|
|||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(transactionInfo["fee"] as int, ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
))} ${ref.watch(
|
||||
"${(transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: ref.watch(
|
||||
managerProvider.select(
|
||||
(value) => value.coin.decimals,
|
||||
),
|
||||
),
|
||||
).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
|
@ -534,7 +540,7 @@ class _ConfirmTransactionViewState
|
|||
Builder(
|
||||
builder: (context) {
|
||||
final amount =
|
||||
transactionInfo["recipientAmt"] as int;
|
||||
transactionInfo["recipientAmt"] as Amount;
|
||||
final coin = ref.watch(
|
||||
managerProvider.select(
|
||||
(value) => value.coin,
|
||||
|
@ -551,29 +557,25 @@ class _ConfirmTransactionViewState
|
|||
.getPrice(coin)
|
||||
.item1;
|
||||
if (price > Decimal.zero) {
|
||||
fiatAmount = Format.localizedStringAsFixed(
|
||||
value: Format.satoshisToAmount(amount,
|
||||
coin: coin) *
|
||||
price,
|
||||
locale: ref
|
||||
.read(
|
||||
localeServiceChangeNotifierProvider)
|
||||
.locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
fiatAmount = (amount.decimal * price)
|
||||
.toAmount(fractionDigits: 2)
|
||||
.localizedStringAsFixed(
|
||||
locale: ref
|
||||
.read(
|
||||
localeServiceChangeNotifierProvider)
|
||||
.locale,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(
|
||||
amount,
|
||||
ref.watch(
|
||||
"${amount.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
coin,
|
||||
)} $unit",
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
|
@ -676,19 +678,19 @@ class _ConfirmTransactionViewState
|
|||
value.getManager(walletId)))
|
||||
.coin;
|
||||
|
||||
final fee = Format.satoshisToAmount(
|
||||
transactionInfo["fee"] as int,
|
||||
coin: coin,
|
||||
final fee =
|
||||
(transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: fee,
|
||||
"${fee.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(
|
||||
|
@ -855,17 +857,17 @@ class _ConfirmTransactionViewState
|
|||
.select((value) => value.getManager(walletId)))
|
||||
.coin;
|
||||
|
||||
final fee = Format.satoshisToAmount(
|
||||
transactionInfo["fee"] as int,
|
||||
coin: coin,
|
||||
final fee = (transactionInfo["fee"] as int).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: fee,
|
||||
locale: ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
"${fee.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
|
@ -911,34 +913,37 @@ class _ConfirmTransactionViewState
|
|||
.textConfirmTotalAmount,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshiAmountToPrettyString(
|
||||
(transactionInfo["fee"] as int) +
|
||||
(transactionInfo["recipientAmt"] as int),
|
||||
ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
Builder(builder: (context) {
|
||||
final coin = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).coin));
|
||||
final fee = (transactionInfo["fee"] as int)
|
||||
.toAmount(fractionDigits: coin.decimals);
|
||||
final locale = ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
);
|
||||
final amount = transactionInfo["recipientAmt"] as Amount;
|
||||
return Text(
|
||||
"${(amount + fee).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${ref.watch(
|
||||
managerProvider.select((value) => value.coin),
|
||||
).ticker}",
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textConfirmTotalAmount,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -25,13 +25,13 @@ import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
|||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/address_utils.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -94,8 +94,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
final _cryptoFocus = FocusNode();
|
||||
final _baseFocus = FocusNode();
|
||||
|
||||
Decimal? _amountToSend;
|
||||
Decimal? _cachedAmountToSend;
|
||||
Amount? _amountToSend;
|
||||
Amount? _cachedAmountToSend;
|
||||
String? _address;
|
||||
|
||||
String? _privateBalanceString;
|
||||
|
@ -106,7 +106,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
bool _cryptoAmountChangeLock = false;
|
||||
late VoidCallback onCryptoAmountChanged;
|
||||
|
||||
Decimal? _cachedBalance;
|
||||
Amount? _cachedBalance;
|
||||
|
||||
Set<UTXO> selectedUTXOs = {};
|
||||
|
||||
|
@ -118,7 +118,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
cryptoAmount != ",") {
|
||||
_amountToSend = cryptoAmount.contains(",")
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
|
||||
: Decimal.parse(cryptoAmount);
|
||||
.toAmount(fractionDigits: coin.decimals)
|
||||
: Decimal.parse(cryptoAmount)
|
||||
.toAmount(fractionDigits: coin.decimals);
|
||||
if (_cachedAmountToSend != null &&
|
||||
_cachedAmountToSend == _amountToSend) {
|
||||
return;
|
||||
|
@ -131,13 +133,13 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
||||
|
||||
if (price > Decimal.zero) {
|
||||
final String fiatAmountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend! * price,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
|
||||
baseAmountController.text = fiatAmountString;
|
||||
baseAmountController.text = (_amountToSend!.decimal * price)
|
||||
.toAmount(
|
||||
fractionDigits: 2,
|
||||
)
|
||||
.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_amountToSend = null;
|
||||
|
@ -152,11 +154,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
_amountToSend == null
|
||||
? 0
|
||||
: Format.decimalAmountToSatoshis(
|
||||
_amountToSend!,
|
||||
coin,
|
||||
),
|
||||
? 0.toAmount(fractionDigits: coin.decimals)
|
||||
: _amountToSend!,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -176,24 +175,19 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
_amountToSend == null
|
||||
? 0
|
||||
: Format.decimalAmountToSatoshis(
|
||||
_amountToSend!,
|
||||
coin,
|
||||
),
|
||||
? 0.toAmount(fractionDigits: coin.decimals)
|
||||
: _amountToSend!,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int _currentFee = 0;
|
||||
late Amount _currentFee;
|
||||
|
||||
void _setCurrentFee(String fee, bool shouldSetState) {
|
||||
final value = Format.decimalAmountToSatoshis(
|
||||
Decimal.parse(fee),
|
||||
coin,
|
||||
);
|
||||
final value = Decimal.parse(fee).toAmount(fractionDigits: coin.decimals);
|
||||
|
||||
if (shouldSetState) {
|
||||
setState(() => _currentFee = value);
|
||||
} else {
|
||||
|
@ -211,28 +205,28 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
return null;
|
||||
}
|
||||
|
||||
void _updatePreviewButtonState(String? address, Decimal? amount) {
|
||||
void _updatePreviewButtonState(String? address, Amount? amount) {
|
||||
if (isPaynymSend) {
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(amount != null && amount > Decimal.zero);
|
||||
(amount != null && amount > Amount.zero);
|
||||
} else {
|
||||
final isValidAddress = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.validateAddress(address ?? "");
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(isValidAddress && amount != null && amount > Decimal.zero);
|
||||
(isValidAddress && amount != null && amount > Amount.zero);
|
||||
}
|
||||
}
|
||||
|
||||
late Future<String> _calculateFeesFuture;
|
||||
|
||||
Map<int, String> cachedFees = {};
|
||||
Map<int, String> cachedFiroPrivateFees = {};
|
||||
Map<int, String> cachedFiroPublicFees = {};
|
||||
Map<Amount, String> cachedFees = {};
|
||||
Map<Amount, String> cachedFiroPrivateFees = {};
|
||||
Map<Amount, String> cachedFiroPublicFees = {};
|
||||
|
||||
Future<String> calculateFees(int amount) async {
|
||||
if (amount <= 0) {
|
||||
Future<String> calculateFees(Amount amount) async {
|
||||
if (amount <= Amount.zero) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
|
@ -269,7 +263,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
break;
|
||||
}
|
||||
|
||||
int fee;
|
||||
final String locale = ref.read(localeServiceChangeNotifierProvider).locale;
|
||||
Amount fee;
|
||||
if (coin == Coin.monero) {
|
||||
MoneroTransactionPriority specialMoneroId;
|
||||
switch (ref.read(feeRateTypeStateProvider.state).state) {
|
||||
|
@ -285,8 +280,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
}
|
||||
|
||||
fee = await manager.estimateFeeFor(amount, specialMoneroId.raw!);
|
||||
cachedFees[amount] = Format.satoshisToAmount(fee, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cachedFees[amount] = fee.localizedStringAsFixed(locale: locale);
|
||||
|
||||
return cachedFees[amount]!;
|
||||
} else if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
|
@ -294,23 +288,22 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
"Private") {
|
||||
fee = await manager.estimateFeeFor(amount, feeRate);
|
||||
|
||||
cachedFiroPrivateFees[amount] = Format.satoshisToAmount(fee, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cachedFiroPrivateFees[amount] =
|
||||
fee.localizedStringAsFixed(locale: locale);
|
||||
|
||||
return cachedFiroPrivateFees[amount]!;
|
||||
} else {
|
||||
fee = await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
|
||||
cachedFiroPublicFees[amount] = Format.satoshisToAmount(fee, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cachedFiroPublicFees[amount] =
|
||||
fee.localizedStringAsFixed(locale: locale);
|
||||
|
||||
return cachedFiroPublicFees[amount]!;
|
||||
}
|
||||
} else {
|
||||
fee = await manager.estimateFeeFor(amount, feeRate);
|
||||
cachedFees[amount] = Format.satoshisToAmount(fee, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cachedFees[amount] = fee.localizedStringAsFixed(locale: locale);
|
||||
|
||||
return cachedFees[amount]!;
|
||||
}
|
||||
|
@ -321,7 +314,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
final wallet = ref.read(provider).wallet as FiroWallet?;
|
||||
|
||||
if (wallet != null) {
|
||||
Decimal? balance;
|
||||
Amount? balance;
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
balance = wallet.availablePrivateBalance();
|
||||
|
@ -329,8 +322,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
balance = wallet.availablePublicBalance();
|
||||
}
|
||||
|
||||
return Format.localizedStringAsFixed(
|
||||
value: balance, locale: locale, decimalPlaces: 8);
|
||||
return balance.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -345,20 +339,19 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||
|
||||
final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin);
|
||||
int availableBalance;
|
||||
final Amount amount = _amountToSend!;
|
||||
final Amount availableBalance;
|
||||
if ((coin == Coin.firo || coin == Coin.firoTestNet)) {
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
availableBalance = Format.decimalAmountToSatoshis(
|
||||
(manager.wallet as FiroWallet).availablePrivateBalance(), coin);
|
||||
availableBalance =
|
||||
(manager.wallet as FiroWallet).availablePrivateBalance();
|
||||
} else {
|
||||
availableBalance = Format.decimalAmountToSatoshis(
|
||||
(manager.wallet as FiroWallet).availablePublicBalance(), coin);
|
||||
availableBalance =
|
||||
(manager.wallet as FiroWallet).availablePublicBalance();
|
||||
}
|
||||
} else {
|
||||
availableBalance =
|
||||
Format.decimalAmountToSatoshis(manager.balance.getSpendable(), coin);
|
||||
availableBalance = manager.balance.spendable;
|
||||
}
|
||||
|
||||
final coinControlEnabled =
|
||||
|
@ -462,7 +455,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
final feeRate = ref.read(feeRateTypeStateProvider);
|
||||
txDataFuture = wallet.preparePaymentCodeSend(
|
||||
paymentCode: paymentCode,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": feeRate,
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -477,13 +470,13 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
"Private") {
|
||||
txDataFuture = (manager.wallet as FiroWallet).prepareSendPublic(
|
||||
address: _address!,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {"feeRate": ref.read(feeRateTypeStateProvider)},
|
||||
);
|
||||
} else {
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: _address!,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -565,12 +558,14 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
coin = widget.coin;
|
||||
ref.refresh(feeSheetSessionCacheProvider);
|
||||
_currentFee = 0.toAmount(fractionDigits: coin.decimals);
|
||||
|
||||
_calculateFeesFuture = calculateFees(0);
|
||||
_calculateFeesFuture =
|
||||
calculateFees(0.toAmount(fractionDigits: coin.decimals));
|
||||
_data = widget.autoFillData;
|
||||
walletId = widget.walletId;
|
||||
coin = widget.coin;
|
||||
clipboard = widget.clipboard;
|
||||
scanner = widget.barcodeScanner;
|
||||
|
||||
|
@ -676,12 +671,14 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
ref.listen(publicPrivateBalanceStateProvider, (previous, next) {
|
||||
if (_amountToSend == null) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(0);
|
||||
_calculateFeesFuture =
|
||||
calculateFees(0.toAmount(fractionDigits: coin.decimals));
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||
_amountToSend!,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -802,7 +799,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
coin != Coin.firoTestNet)
|
||||
? Future(() => ref.watch(
|
||||
provider.select((value) =>
|
||||
value.balance.getSpendable())))
|
||||
value.balance.spendable)))
|
||||
: ref.watch(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private"
|
||||
? Future(() => (ref
|
||||
|
@ -814,7 +811,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
.wallet as FiroWallet)
|
||||
.availablePublicBalance()),
|
||||
builder:
|
||||
(_, AsyncSnapshot<Decimal> snapshot) {
|
||||
(_, AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
|
@ -825,10 +822,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
return GestureDetector(
|
||||
onTap: () {
|
||||
cryptoAmountController.text =
|
||||
_cachedBalance!.toStringAsFixed(
|
||||
Constants
|
||||
.decimalPlacesForCoin(
|
||||
coin));
|
||||
_cachedBalance!
|
||||
.localizedStringAsFixed(
|
||||
locale: locale);
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
@ -837,10 +833,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: _cachedBalance!,
|
||||
"${_cachedBalance!.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${coin.ticker}",
|
||||
style:
|
||||
STextStyles.titleBold12(
|
||||
|
@ -851,17 +845,11 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
textAlign: TextAlign.right,
|
||||
),
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: _cachedBalance! *
|
||||
ref.watch(priceAnd24hChangeNotifierProvider
|
||||
.select((value) =>
|
||||
value
|
||||
.getPrice(
|
||||
coin)
|
||||
.item1)),
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
"${(_cachedBalance!.decimal * ref.watch(priceAnd24hChangeNotifierProvider.select((value) => value.getPrice(coin).item1))).toAmount(
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
style: STextStyles.subtitle(
|
||||
context)
|
||||
.copyWith(
|
||||
|
@ -1134,23 +1122,19 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
// autofill amount field
|
||||
if (results["amount"] !=
|
||||
null) {
|
||||
final amount =
|
||||
final Amount amount =
|
||||
Decimal.parse(results[
|
||||
"amount"]!);
|
||||
"amount"]!)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals,
|
||||
);
|
||||
cryptoAmountController
|
||||
.text =
|
||||
Format
|
||||
amount
|
||||
.localizedStringAsFixed(
|
||||
value: amount,
|
||||
locale: ref
|
||||
.read(
|
||||
localeServiceChangeNotifierProvider)
|
||||
.locale,
|
||||
decimalPlaces: Constants
|
||||
.decimalPlacesForCoin(
|
||||
coin),
|
||||
locale: locale,
|
||||
);
|
||||
amount.toString();
|
||||
_amountToSend = amount;
|
||||
}
|
||||
|
||||
|
@ -1413,24 +1397,21 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
"Private") {
|
||||
cryptoAmountController.text = firoWallet
|
||||
.availablePrivateBalance()
|
||||
.toStringAsFixed(
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin));
|
||||
.localizedStringAsFixed(
|
||||
locale: locale);
|
||||
} else {
|
||||
cryptoAmountController.text = firoWallet
|
||||
.availablePublicBalance()
|
||||
.toStringAsFixed(
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin));
|
||||
.localizedStringAsFixed(
|
||||
locale: locale);
|
||||
}
|
||||
} else {
|
||||
cryptoAmountController.text = (ref
|
||||
.read(provider)
|
||||
.balance
|
||||
.getSpendable())
|
||||
.toStringAsFixed(
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin));
|
||||
cryptoAmountController.text = ref
|
||||
.read(provider)
|
||||
.balance
|
||||
.spendable
|
||||
.localizedStringAsFixed(
|
||||
locale: locale);
|
||||
}
|
||||
_cryptoAmountChanged();
|
||||
},
|
||||
|
@ -1531,26 +1512,30 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
if (baseAmountString.isNotEmpty &&
|
||||
baseAmountString != "." &&
|
||||
baseAmountString != ",") {
|
||||
final baseAmount =
|
||||
final Amount baseAmount =
|
||||
baseAmountString.contains(",")
|
||||
? Decimal.parse(baseAmountString
|
||||
.replaceFirst(",", "."))
|
||||
: Decimal.parse(baseAmountString);
|
||||
.replaceFirst(",", "."))
|
||||
.toAmount(fractionDigits: 2)
|
||||
: Decimal.parse(baseAmountString)
|
||||
.toAmount(fractionDigits: 2);
|
||||
|
||||
var _price = ref
|
||||
final Decimal _price = ref
|
||||
.read(priceAnd24hChangeNotifierProvider)
|
||||
.getPrice(coin)
|
||||
.item1;
|
||||
|
||||
if (_price == Decimal.zero) {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend = 0.toAmount(
|
||||
fractionDigits: coin.decimals);
|
||||
} else {
|
||||
_amountToSend = baseAmount <= Decimal.zero
|
||||
? Decimal.zero
|
||||
: (baseAmount / _price).toDecimal(
|
||||
scaleOnInfinitePrecision:
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin));
|
||||
_amountToSend = baseAmount <= Amount.zero
|
||||
? 0.toAmount(
|
||||
fractionDigits: coin.decimals)
|
||||
: (baseAmount.decimal / _price)
|
||||
.toDouble()
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals);
|
||||
}
|
||||
if (_cachedAmountToSend != null &&
|
||||
_cachedAmountToSend == _amountToSend) {
|
||||
|
@ -1562,21 +1547,19 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
level: LogLevel.Info);
|
||||
|
||||
final amountString =
|
||||
Format.localizedStringAsFixed(
|
||||
value: _amountToSend!,
|
||||
_amountToSend!.localizedStringAsFixed(
|
||||
locale: ref
|
||||
.read(
|
||||
localeServiceChangeNotifierProvider)
|
||||
.locale,
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = amountString;
|
||||
_cryptoAmountChangeLock = false;
|
||||
} else {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend =
|
||||
0.toAmount(fractionDigits: coin.decimals);
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = "";
|
||||
_cryptoAmountChangeLock = false;
|
||||
|
@ -1654,13 +1637,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
.balance
|
||||
.spendable;
|
||||
|
||||
int? amount;
|
||||
Amount? amount;
|
||||
if (_amountToSend != null) {
|
||||
amount =
|
||||
Format.decimalAmountToSatoshis(
|
||||
_amountToSend!,
|
||||
coin,
|
||||
);
|
||||
amount = _amountToSend!;
|
||||
|
||||
if (spendable == amount) {
|
||||
// this is now a send all
|
||||
|
@ -1803,10 +1782,13 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
builder: (_) =>
|
||||
TransactionFeeSelectionSheet(
|
||||
walletId: walletId,
|
||||
amount: Decimal.tryParse(
|
||||
cryptoAmountController
|
||||
.text) ??
|
||||
Decimal.zero,
|
||||
amount: (Decimal.tryParse(
|
||||
cryptoAmountController
|
||||
.text) ??
|
||||
Decimal.zero)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
updateChosen: (String fee) {
|
||||
_setCurrentFee(
|
||||
fee,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
|
@ -8,7 +7,6 @@ import 'package:stackwallet/utilities/constants.dart';
|
|||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
|
||||
class FiroBalanceSelectionSheet extends ConsumerStatefulWidget {
|
||||
const FiroBalanceSelectionSheet({
|
||||
|
@ -153,29 +151,18 @@ class _FiroBalanceSelectionSheetState
|
|||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
// TODO redo this widget now that its not actually a future
|
||||
future: Future(
|
||||
() => firoWallet.availablePrivateBalance()),
|
||||
builder:
|
||||
(context, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${snapshot.data!.toStringAsFixed(8)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough:
|
||||
stringsToLoopThrough,
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
Text(
|
||||
"${firoWallet.availablePrivateBalance().localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
),
|
||||
// ],
|
||||
|
@ -245,31 +232,18 @@ class _FiroBalanceSelectionSheetState
|
|||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
// TODO redo this widget now that its not actually a future
|
||||
future: Future(
|
||||
() => firoWallet.availablePublicBalance()),
|
||||
builder:
|
||||
(context, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${snapshot.data!.toStringAsFixed(8)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough:
|
||||
stringsToLoopThrough,
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
// ],
|
||||
// ),
|
||||
Text(
|
||||
"${firoWallet.availablePublicBalance().localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -8,10 +8,10 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -23,9 +23,9 @@ final feeSheetSessionCacheProvider =
|
|||
});
|
||||
|
||||
class FeeSheetSessionCache extends ChangeNotifier {
|
||||
final Map<int, Decimal> fast = {};
|
||||
final Map<int, Decimal> average = {};
|
||||
final Map<int, Decimal> slow = {};
|
||||
final Map<Amount, Amount> fast = {};
|
||||
final Map<Amount, Amount> average = {};
|
||||
final Map<Amount, Amount> slow = {};
|
||||
|
||||
void notify() => notifyListeners();
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class TransactionFeeSelectionSheet extends ConsumerStatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final Decimal amount;
|
||||
final Amount amount;
|
||||
final Function updateChosen;
|
||||
final bool isToken;
|
||||
|
||||
|
@ -52,7 +52,7 @@ class TransactionFeeSelectionSheet extends ConsumerStatefulWidget {
|
|||
class _TransactionFeeSelectionSheetState
|
||||
extends ConsumerState<TransactionFeeSelectionSheet> {
|
||||
late final String walletId;
|
||||
late final Decimal amount;
|
||||
late final Amount amount;
|
||||
|
||||
FeeObject? feeObject;
|
||||
|
||||
|
@ -63,8 +63,8 @@ class _TransactionFeeSelectionSheetState
|
|||
"Calculating...",
|
||||
];
|
||||
|
||||
Future<Decimal> feeFor({
|
||||
required int amount,
|
||||
Future<Amount> feeFor({
|
||||
required Amount amount,
|
||||
required FeeRateType feeRateType,
|
||||
required int feeRate,
|
||||
required Coin coin,
|
||||
|
@ -79,30 +79,21 @@ class _TransactionFeeSelectionSheetState
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.fast.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
} else {
|
||||
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||
final fee = await tokenWallet.estimateFeeFor(amount, feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(fee, coin: coin);
|
||||
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
|
||||
|
@ -115,30 +106,21 @@ class _TransactionFeeSelectionSheetState
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.regular.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
} else {
|
||||
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||
final fee = await tokenWallet.estimateFeeFor(amount, feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(fee, coin: coin);
|
||||
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).average[amount]!;
|
||||
|
@ -151,30 +133,21 @@ class _TransactionFeeSelectionSheetState
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.slow.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
} else {
|
||||
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||
final fee = await tokenWallet.estimateFeeFor(amount, feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(fee, coin: coin);
|
||||
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
|
||||
|
@ -347,23 +320,25 @@ class _TransactionFeeSelectionSheetState
|
|||
if (feeObject != null)
|
||||
FutureBuilder(
|
||||
future: feeFor(
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.fast,
|
||||
feeRate: feeObject!.fast,
|
||||
amount: Format
|
||||
.decimalAmountToSatoshis(
|
||||
amount, manager.coin)),
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.fast,
|
||||
feeRate: feeObject!.fast,
|
||||
amount: amount,
|
||||
),
|
||||
// future: manager.estimateFeeFor(
|
||||
// Format.decimalAmountToSatoshis(
|
||||
// amount),
|
||||
// feeObject!.fast),
|
||||
builder: (_,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"(~${snapshot.data!.toStringAsFixed(manager.coin.decimals)} ${manager.coin.ticker})",
|
||||
"(~${snapshot.data!.decimal.toStringAsFixed(
|
||||
manager.coin.decimals,
|
||||
)}"
|
||||
" ${manager.coin.ticker})",
|
||||
style: STextStyles.itemSubtitle(
|
||||
context),
|
||||
textAlign: TextAlign.left,
|
||||
|
@ -479,23 +454,23 @@ class _TransactionFeeSelectionSheetState
|
|||
if (feeObject != null)
|
||||
FutureBuilder(
|
||||
future: feeFor(
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.average,
|
||||
feeRate: feeObject!.medium,
|
||||
amount: Format
|
||||
.decimalAmountToSatoshis(
|
||||
amount, manager.coin)),
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.average,
|
||||
feeRate: feeObject!.medium,
|
||||
amount: amount,
|
||||
),
|
||||
// future: manager.estimateFeeFor(
|
||||
// Format.decimalAmountToSatoshis(
|
||||
// amount),
|
||||
// feeObject!.fast),
|
||||
builder: (_,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"(~${snapshot.data!.toStringAsFixed(manager.coin.decimals)} ${manager.coin.ticker})",
|
||||
"(~${snapshot.data!.decimal.toStringAsFixed(manager.coin.decimals)}"
|
||||
" ${manager.coin.ticker})",
|
||||
style: STextStyles.itemSubtitle(
|
||||
context),
|
||||
textAlign: TextAlign.left,
|
||||
|
@ -612,23 +587,22 @@ class _TransactionFeeSelectionSheetState
|
|||
if (feeObject != null)
|
||||
FutureBuilder(
|
||||
future: feeFor(
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.slow,
|
||||
feeRate: feeObject!.slow,
|
||||
amount: Format
|
||||
.decimalAmountToSatoshis(
|
||||
amount, manager.coin)),
|
||||
coin: manager.coin,
|
||||
feeRateType: FeeRateType.slow,
|
||||
feeRate: feeObject!.slow,
|
||||
amount: amount,
|
||||
),
|
||||
// future: manager.estimateFeeFor(
|
||||
// Format.decimalAmountToSatoshis(
|
||||
// amount),
|
||||
// feeObject!.fast),
|
||||
builder: (_,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"(~${snapshot.data!.toStringAsFixed(manager.coin.decimals)} ${manager.coin.ticker})",
|
||||
"(~${snapshot.data!.decimal.toStringAsFixed(manager.coin.decimals)} ${manager.coin.ticker})",
|
||||
style: STextStyles.itemSubtitle(
|
||||
context),
|
||||
textAlign: TextAlign.left,
|
||||
|
@ -686,7 +660,6 @@ class _TransactionFeeSelectionSheetState
|
|||
|
||||
String? getAmount(FeeRateType feeRateType, Coin coin) {
|
||||
try {
|
||||
final amount = Format.decimalAmountToSatoshis(this.amount, coin);
|
||||
switch (feeRateType) {
|
||||
case FeeRateType.fast:
|
||||
if (ref.read(feeSheetSessionCacheProvider).fast[amount] != null) {
|
||||
|
|
|
@ -25,7 +25,6 @@ import 'package:stackwallet/utilities/clipboard_interface.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -34,7 +33,6 @@ import 'package:stackwallet/utilities/util.dart';
|
|||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/eth_token_icon.dart';
|
||||
|
@ -102,7 +100,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
Timer? _cryptoAmountChangedFeeUpdateTimer;
|
||||
Timer? _baseAmountChangedFeeUpdateTimer;
|
||||
late Future<String> _calculateFeesFuture;
|
||||
Map<int, String> cachedFees = {};
|
||||
String cachedFees = "";
|
||||
|
||||
void _onTokenSendViewPasteAddressFieldButtonPressed() async {
|
||||
final ClipboardData? data = await clipboard.getData(Clipboard.kTextPlain);
|
||||
|
@ -165,17 +163,13 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
|
||||
// autofill amount field
|
||||
if (results["amount"] != null) {
|
||||
final amount = Decimal.parse(results["amount"]!);
|
||||
cryptoAmountController.text = Format.localizedStringAsFixed(
|
||||
value: amount,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
amount.toString();
|
||||
_amountToSend = Amount.fromDecimal(
|
||||
amount,
|
||||
final Amount amount = Decimal.parse(results["amount"]!).toAmount(
|
||||
fractionDigits: tokenContract.decimals,
|
||||
);
|
||||
cryptoAmountController.text = amount.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
_amountToSend = amount;
|
||||
}
|
||||
|
||||
_updatePreviewButtonState(_address, _amountToSend);
|
||||
|
@ -243,14 +237,10 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend",
|
||||
level: LogLevel.Info);
|
||||
|
||||
final amountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend!.decimal,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = amountString;
|
||||
cryptoAmountController.text = _amountToSend!.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
_cryptoAmountChangeLock = false;
|
||||
} else {
|
||||
_amountToSend = Amount.zero;
|
||||
|
@ -291,13 +281,13 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
.item1;
|
||||
|
||||
if (price > Decimal.zero) {
|
||||
final String fiatAmountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend!.decimal * price,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
|
||||
baseAmountController.text = fiatAmountString;
|
||||
baseAmountController.text = (_amountToSend!.decimal * price)
|
||||
.toAmount(
|
||||
fractionDigits: 2,
|
||||
)
|
||||
.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_amountToSend = null;
|
||||
|
@ -310,9 +300,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
_cryptoAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () {
|
||||
if (coin != Coin.epicCash && !_baseFocus.hasFocus) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
_amountToSend == null ? 0 : _amountToSend!.raw.toInt(),
|
||||
);
|
||||
_calculateFeesFuture = calculateFees();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -324,9 +312,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
_baseAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () {
|
||||
if (coin != Coin.epicCash && !_cryptoFocus.hasFocus) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
_amountToSend == null ? 0 : _amountToSend!.raw.toInt(),
|
||||
);
|
||||
_calculateFeesFuture = calculateFees();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -351,15 +337,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
(isValidAddress && amount != null && amount > Amount.zero);
|
||||
}
|
||||
|
||||
Future<String> calculateFees(int amount) async {
|
||||
if (amount <= 0) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
if (cachedFees[amount] != null) {
|
||||
return cachedFees[amount]!;
|
||||
}
|
||||
|
||||
Future<String> calculateFees() async {
|
||||
final wallet = ref.read(tokenServiceProvider)!;
|
||||
final feeObject = await wallet.fees;
|
||||
|
||||
|
@ -377,13 +355,12 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
break;
|
||||
}
|
||||
|
||||
int fee;
|
||||
final Amount fee = wallet.estimateFeeFor(feeRate);
|
||||
cachedFees = fee.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
|
||||
fee = await wallet.estimateFeeFor(amount, feeRate);
|
||||
cachedFees[amount] = Format.satoshisToAmount(fee, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
|
||||
return cachedFees[amount]!;
|
||||
return cachedFees;
|
||||
}
|
||||
|
||||
Future<void> _previewTransaction() async {
|
||||
|
@ -397,10 +374,6 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||
|
||||
final Amount amount = _amountToSend!;
|
||||
final Amount availableBalance = Amount.fromDecimal(
|
||||
tokenWallet.balance.getSpendable(),
|
||||
fractionDigits: tokenContract.decimals,
|
||||
);
|
||||
|
||||
// // confirm send all
|
||||
// if (amount == availableBalance) {
|
||||
|
@ -487,7 +460,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
|
||||
txDataFuture = tokenWallet.prepareSend(
|
||||
address: _address!,
|
||||
satoshiAmount: amount.raw.toInt(),
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
},
|
||||
|
@ -560,7 +533,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
void initState() {
|
||||
ref.refresh(feeSheetSessionCacheProvider);
|
||||
|
||||
_calculateFeesFuture = calculateFees(0);
|
||||
_calculateFeesFuture = calculateFees();
|
||||
_data = widget.autoFillData;
|
||||
walletId = widget.walletId;
|
||||
coin = widget.coin;
|
||||
|
@ -703,9 +676,13 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
cryptoAmountController.text = ref
|
||||
.read(tokenServiceProvider)!
|
||||
.balance
|
||||
.getSpendable()
|
||||
.toStringAsFixed(
|
||||
tokenContract.decimals);
|
||||
.spendable
|
||||
.localizedStringAsFixed(
|
||||
locale: ref
|
||||
.read(
|
||||
localeServiceChangeNotifierProvider)
|
||||
.locale,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
@ -714,7 +691,20 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"${ref.read(tokenServiceProvider)!.balance.getSpendable().toStringAsFixed(tokenContract.decimals)} ${tokenContract.symbol}",
|
||||
"${ref.watch(
|
||||
tokenServiceProvider.select(
|
||||
(value) => value!
|
||||
.balance.spendable
|
||||
.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)} ${tokenContract.symbol}",
|
||||
style:
|
||||
STextStyles.titleBold12(context)
|
||||
.copyWith(
|
||||
|
@ -723,22 +713,11 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
textAlign: TextAlign.right,
|
||||
),
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: ref
|
||||
.read(
|
||||
tokenServiceProvider)!
|
||||
.balance
|
||||
.getSpendable() *
|
||||
ref.watch(
|
||||
priceAnd24hChangeNotifierProvider
|
||||
.select((value) => value
|
||||
.getTokenPrice(
|
||||
tokenContract
|
||||
.address)
|
||||
.item1)),
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
"${(ref.watch(tokenServiceProvider.select((value) => value!.balance.spendable.decimal)) * ref.watch(priceAnd24hChangeNotifierProvider.select((value) => value.getTokenPrice(tokenContract.address).item1))).toAmount(
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
style: STextStyles.subtitle(context)
|
||||
.copyWith(
|
||||
fontSize: 8,
|
||||
|
@ -1138,9 +1117,14 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
|
|||
TransactionFeeSelectionSheet(
|
||||
walletId: walletId,
|
||||
isToken: true,
|
||||
amount: Decimal.tryParse(
|
||||
cryptoAmountController.text) ??
|
||||
Decimal.zero,
|
||||
amount: (Decimal.tryParse(
|
||||
cryptoAmountController
|
||||
.text) ??
|
||||
Decimal.zero)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
tokenContract.decimals,
|
||||
),
|
||||
updateChosen: (String fee) {
|
||||
setState(() {
|
||||
_calculateFeesFuture =
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -7,11 +6,9 @@ import 'package:stackwallet/utilities/assets.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
|
@ -144,40 +141,18 @@ class WalletSyncingOptionsView extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: Future(
|
||||
() => manager.balance.getTotal()),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) =>
|
||||
value.locale)),
|
||||
decimalPlaces: 8,
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(
|
||||
context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(
|
||||
context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
Text(
|
||||
"${manager.balance.total.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${manager.coin.ticker}",
|
||||
style:
|
||||
STextStyles.itemSubtitle(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
|
|
|
@ -113,7 +113,13 @@ class _MyTokenSelectItemState extends ConsumerState<MyTokenSelectItem> {
|
|||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
"${cachedBalance.getCachedBalance().getTotal()} "
|
||||
"${cachedBalance.getCachedBalance().total.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} "
|
||||
"${widget.token.symbol}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
|
|
|
@ -15,10 +15,10 @@ import 'package:stackwallet/providers/global/prefs_provider.dart';
|
|||
import 'package:stackwallet/providers/global/price_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
|
@ -80,7 +80,13 @@ class TokenSummary extends ConsumerWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"${balance.getTotal()}"
|
||||
"${balance.total.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)}"
|
||||
" ${token.symbol}",
|
||||
style: STextStyles.pageTitleH1(context),
|
||||
),
|
||||
|
@ -96,17 +102,23 @@ class TokenSummary extends ConsumerWidget {
|
|||
height: 6,
|
||||
),
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: ref
|
||||
.read(tokenServiceProvider)!
|
||||
.balance
|
||||
.getSpendable() *
|
||||
ref.watch(priceAnd24hChangeNotifierProvider.select(
|
||||
(value) => value.getTokenPrice(token.address).item1)),
|
||||
locale: ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
"${(balance.total.decimal * ref.watch(
|
||||
priceAnd24hChangeNotifierProvider.select(
|
||||
(value) => value.getTokenPrice(token.address).item1,
|
||||
),
|
||||
)).toAmount(
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${ref.watch(
|
||||
prefsChangeNotifierProvider.select(
|
||||
(value) => value.currency,
|
||||
),
|
||||
)}",
|
||||
style: STextStyles.subtitle500(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/balance.dart';
|
||||
|
@ -6,6 +5,7 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
|
||||
|
@ -112,7 +112,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
BalanceSelector(
|
||||
title: "Available balance",
|
||||
coin: coin,
|
||||
balance: balance.getSpendable(),
|
||||
balance: balance.spendable,
|
||||
onPressed: () {
|
||||
ref.read(walletBalanceToggleStateProvider.state).state =
|
||||
WalletBalanceToggleState.available;
|
||||
|
@ -138,7 +138,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
BalanceSelector(
|
||||
title: "Available private balance",
|
||||
coin: coin,
|
||||
balance: balanceSecondary.getSpendable(),
|
||||
balance: balanceSecondary.spendable,
|
||||
onPressed: () {
|
||||
ref.read(walletBalanceToggleStateProvider.state).state =
|
||||
WalletBalanceToggleState.available;
|
||||
|
@ -162,7 +162,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
BalanceSelector(
|
||||
title: "Full balance",
|
||||
coin: coin,
|
||||
balance: balance.getTotal(),
|
||||
balance: balance.total,
|
||||
onPressed: () {
|
||||
ref.read(walletBalanceToggleStateProvider.state).state =
|
||||
WalletBalanceToggleState.full;
|
||||
|
@ -188,7 +188,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
BalanceSelector(
|
||||
title: "Full private balance",
|
||||
coin: coin,
|
||||
balance: balanceSecondary.getTotal(),
|
||||
balance: balanceSecondary.total,
|
||||
onPressed: () {
|
||||
ref.read(walletBalanceToggleStateProvider.state).state =
|
||||
WalletBalanceToggleState.full;
|
||||
|
@ -217,7 +217,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class BalanceSelector<T> extends StatelessWidget {
|
||||
class BalanceSelector<T> extends ConsumerWidget {
|
||||
const BalanceSelector({
|
||||
Key? key,
|
||||
required this.title,
|
||||
|
@ -231,14 +231,14 @@ class BalanceSelector<T> extends StatelessWidget {
|
|||
|
||||
final String title;
|
||||
final Coin coin;
|
||||
final Decimal balance;
|
||||
final Amount balance;
|
||||
final VoidCallback onPressed;
|
||||
final void Function(T?) onChanged;
|
||||
final T value;
|
||||
final T? groupValue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
|
@ -278,7 +278,13 @@ class BalanceSelector<T> extends StatelessWidget {
|
|||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"${balance.toStringAsFixed(Constants.decimalPlacesForCoin(coin))} ${coin.ticker}",
|
||||
"${balance.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/balance_refreshed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
||||
import '../../../providers/wallet/public_private_balance_state_provider.dart';
|
||||
|
||||
class WalletSummaryInfo extends ConsumerStatefulWidget {
|
||||
const WalletSummaryInfo({
|
||||
Key? key,
|
||||
|
@ -94,7 +92,7 @@ class _WalletSummaryInfoState extends ConsumerState<WalletSummaryInfo> {
|
|||
ref.watch(walletBalanceToggleStateProvider.state).state ==
|
||||
WalletBalanceToggleState.available;
|
||||
|
||||
final Decimal balanceToShow;
|
||||
final Amount balanceToShow;
|
||||
String title;
|
||||
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
|
@ -106,12 +104,11 @@ class _WalletSummaryInfoState extends ConsumerState<WalletSummaryInfo> {
|
|||
|
||||
final bal = _showPrivate ? firoWallet.balancePrivate : firoWallet.balance;
|
||||
|
||||
balanceToShow = _showAvailable ? bal.getSpendable() : bal.getTotal();
|
||||
balanceToShow = _showAvailable ? bal.spendable : bal.total;
|
||||
title = _showAvailable ? "Available" : "Full";
|
||||
title += _showPrivate ? " private balance" : " public balance";
|
||||
} else {
|
||||
balanceToShow =
|
||||
_showAvailable ? balance.getSpendable() : balance.getTotal();
|
||||
balanceToShow = _showAvailable ? balance.spendable : balance.total;
|
||||
title = _showAvailable ? "Available balance" : "Full balance";
|
||||
}
|
||||
|
||||
|
@ -151,10 +148,8 @@ class _WalletSummaryInfoState extends ConsumerState<WalletSummaryInfo> {
|
|||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: SelectableText(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: balanceToShow,
|
||||
"${balanceToShow.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.pageTitleH1(context).copyWith(
|
||||
fontSize: 24,
|
||||
|
@ -166,11 +161,11 @@ class _WalletSummaryInfoState extends ConsumerState<WalletSummaryInfo> {
|
|||
),
|
||||
if (externalCalls)
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: priceTuple.item1 * balanceToShow,
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} $baseCurrency",
|
||||
"${(priceTuple.item1 * balanceToShow.decimal).toAmount(
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} $baseCurrency",
|
||||
style: STextStyles.subtitle500(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_sear
|
|||
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -111,8 +112,7 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (filter.amount != null &&
|
||||
BigInt.from(filter.amount!) != tx.realAmount.raw) {
|
||||
if (filter.amount != null && filter.amount! != tx.realAmount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -956,10 +956,8 @@ class _DesktopTransactionCardRowState
|
|||
builder: (_) {
|
||||
final amount = _transaction.realAmount;
|
||||
return Text(
|
||||
"$prefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal,
|
||||
"$prefix${amount.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
|
@ -980,11 +978,11 @@ class _DesktopTransactionCardRowState
|
|||
final amount = _transaction.realAmount;
|
||||
|
||||
return Text(
|
||||
"$prefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal * price,
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} $baseCurrency",
|
||||
"$prefix${(amount.decimal * price).toAmount(
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} $baseCurrency",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||
);
|
||||
},
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -68,7 +67,7 @@ class _TransactionDetailsViewState
|
|||
|
||||
late final Coin coin;
|
||||
late final Amount amount;
|
||||
late final Decimal fee;
|
||||
late final Amount fee;
|
||||
late final String amountPrefix;
|
||||
late final String unit;
|
||||
late final bool isTokenTx;
|
||||
|
@ -83,9 +82,8 @@ class _TransactionDetailsViewState
|
|||
walletId = widget.walletId;
|
||||
|
||||
coin = widget.coin;
|
||||
amount = _transaction
|
||||
.realAmount; //Format.satoshisToAmount(_transaction.amount, coin: coin);
|
||||
fee = Format.satoshisToAmount(_transaction.fee, coin: coin);
|
||||
amount = _transaction.realAmount;
|
||||
fee = _transaction.fee.toAmount(fractionDigits: coin.decimals);
|
||||
|
||||
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
_transaction.subType == TransactionSubType.mint) {
|
||||
|
@ -445,15 +443,12 @@ class _TransactionDetailsViewState
|
|||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SelectableText(
|
||||
"$amountPrefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal,
|
||||
"$amountPrefix${amount.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) =>
|
||||
value.locale),
|
||||
),
|
||||
decimalPlaces:
|
||||
amount.fractionDigits,
|
||||
)} $unit",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
|
@ -476,28 +471,26 @@ class _TransactionDetailsViewState
|
|||
.select((value) =>
|
||||
value.externalCalls)))
|
||||
SelectableText(
|
||||
"$amountPrefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal *
|
||||
ref.watch(
|
||||
priceAnd24hChangeNotifierProvider
|
||||
.select((value) => isTokenTx
|
||||
? value
|
||||
.getTokenPrice(
|
||||
_transaction
|
||||
.otherData!)
|
||||
.item1
|
||||
: value
|
||||
.getPrice(
|
||||
coin)
|
||||
.item1),
|
||||
"$amountPrefix${(amount.decimal * ref.watch(
|
||||
priceAnd24hChangeNotifierProvider.select(
|
||||
(value) => isTokenTx
|
||||
? value
|
||||
.getTokenPrice(
|
||||
_transaction
|
||||
.otherData!)
|
||||
.item1
|
||||
: value
|
||||
.getPrice(
|
||||
coin)
|
||||
.item1),
|
||||
)).toAmount(fractionDigits: 2).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) =>
|
||||
value.locale),
|
||||
),
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(
|
||||
)} ${ref.watch(
|
||||
prefsChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.currency,
|
||||
|
@ -896,24 +889,20 @@ class _TransactionDetailsViewState
|
|||
currentHeight,
|
||||
coin.requiredConfirmations,
|
||||
)
|
||||
? Format.localizedStringAsFixed(
|
||||
value: fee,
|
||||
? fee.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) =>
|
||||
value.locale)),
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(
|
||||
coin))
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
)
|
||||
: "Pending"
|
||||
: Format.localizedStringAsFixed(
|
||||
value: fee,
|
||||
: fee.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale)),
|
||||
decimalPlaces:
|
||||
Constants.decimalPlacesForCoin(coin));
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
);
|
||||
if (isTokenTx) {
|
||||
feeString += " ${coin.ticker}";
|
||||
}
|
||||
|
@ -1517,13 +1506,15 @@ class IconCopyButton extends StatelessWidget {
|
|||
),
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(text: data));
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:stackwallet/models/transaction_filter.dart';
|
|||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -75,13 +76,12 @@ class _TransactionSearchViewState
|
|||
_toDateString =
|
||||
_selectedToDate == null ? "" : Format.formatDate(_selectedToDate!);
|
||||
|
||||
// TODO: Fix XMR (modify Format.funcs to take optional Coin parameter)
|
||||
// final amt = Format.satoshisToAmount(widget.coin == Coin.monero ? )
|
||||
String amount = "";
|
||||
if (filterState.amount != null) {
|
||||
amount = Format.satoshiAmountToPrettyString(filterState.amount!,
|
||||
ref.read(localeServiceChangeNotifierProvider).locale, widget.coin);
|
||||
}
|
||||
final String amount = filterState.amount?.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: widget.coin.decimals,
|
||||
) ??
|
||||
"";
|
||||
|
||||
_amountTextEditingController.text = amount;
|
||||
}
|
||||
|
||||
|
@ -966,15 +966,13 @@ class _TransactionSearchViewState
|
|||
|
||||
Future<void> _onApplyPressed() async {
|
||||
final amountText = _amountTextEditingController.text;
|
||||
Decimal? amountDecimal;
|
||||
Amount? amount;
|
||||
if (amountText.isNotEmpty && !(amountText == "," || amountText == ".")) {
|
||||
amountDecimal = amountText.contains(",")
|
||||
amount = amountText.contains(",")
|
||||
? Decimal.parse(amountText.replaceFirst(",", "."))
|
||||
: Decimal.parse(amountText);
|
||||
}
|
||||
int? amount;
|
||||
if (amountDecimal != null) {
|
||||
amount = Format.decimalAmountToSatoshis(amountDecimal, widget.coin);
|
||||
.toAmount(fractionDigits: widget.coin.decimals)
|
||||
: Decimal.parse(amountText)
|
||||
.toAmount(fractionDigits: widget.coin.decimals);
|
||||
}
|
||||
|
||||
final TransactionFilter filter = TransactionFilter(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -38,6 +37,7 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_
|
|||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
|
@ -346,8 +346,8 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
);
|
||||
final firoWallet = ref.read(managerProvider).wallet as FiroWallet;
|
||||
|
||||
final publicBalance = firoWallet.availablePublicBalance();
|
||||
if (publicBalance <= Decimal.zero) {
|
||||
final Amount publicBalance = firoWallet.availablePublicBalance();
|
||||
if (publicBalance <= Amount.zero) {
|
||||
shouldPop = true;
|
||||
if (mounted) {
|
||||
Navigator.of(context).popUntil(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
@ -6,10 +5,10 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
|||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -38,8 +37,8 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
late final String walletId;
|
||||
late final ChangeNotifierProvider<Manager> managerProvider;
|
||||
|
||||
Decimal _cachedBalance = Decimal.zero;
|
||||
Decimal _cachedFiatValue = Decimal.zero;
|
||||
Amount _cachedBalance = Amount.zero;
|
||||
Amount _cachedFiatValue = Amount.zero;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -223,21 +222,23 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
),
|
||||
FutureBuilder(
|
||||
future: Future(() => ref.watch(managerProvider
|
||||
.select((value) => value.balance.getTotal()))),
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
.select((value) => value.balance.total))),
|
||||
builder: (builderContext, AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
if (snapshot.data != null) {
|
||||
_cachedBalance = snapshot.data!;
|
||||
if (externalCalls) {
|
||||
_cachedFiatValue = _cachedBalance *
|
||||
ref
|
||||
.watch(
|
||||
priceAnd24hChangeNotifierProvider.select(
|
||||
(value) => value.getPrice(coin),
|
||||
),
|
||||
)
|
||||
.item1;
|
||||
if (externalCalls && _cachedBalance > Amount.zero) {
|
||||
_cachedFiatValue = (_cachedBalance.decimal *
|
||||
ref
|
||||
.watch(
|
||||
priceAnd24hChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.getPrice(coin),
|
||||
),
|
||||
)
|
||||
.item1)
|
||||
.toAmount(fractionDigits: 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,13 +248,13 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
decimalPlaces: 8,
|
||||
value: _cachedBalance,
|
||||
"${_cachedBalance.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
decimalPlaces: ref.watch(managerProvider
|
||||
.select((value) => value.coin.decimals)),
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.titleBold12(context).copyWith(
|
||||
fontSize: 16,
|
||||
|
@ -269,13 +270,12 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
),
|
||||
if (externalCalls)
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
decimalPlaces: 2,
|
||||
value: _cachedFiatValue,
|
||||
"${_cachedFiatValue.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(
|
||||
prefsChangeNotifierProvider
|
||||
.select((value) => value.currency),
|
||||
|
|
|
@ -7,10 +7,10 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
|||
import 'package:stackwallet/pages/wallets_sheet/wallets_sheet.dart';
|
||||
import 'package:stackwallet/pages/wallets_view/eth_wallets_overview.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
@ -108,13 +108,12 @@ class WalletListItem extends ConsumerWidget {
|
|||
final calls =
|
||||
ref.watch(prefsChangeNotifierProvider).externalCalls;
|
||||
|
||||
final priceString = Format.localizedStringAsFixed(
|
||||
value: tuple.item1,
|
||||
locale: ref
|
||||
.watch(localeServiceChangeNotifierProvider.notifier)
|
||||
.locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
final priceString = tuple.item1
|
||||
.toAmount(fractionDigits: 2)
|
||||
.localizedStringAsFixed(
|
||||
locale: ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
);
|
||||
|
||||
final double percentChange = tuple.item2;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -7,10 +6,10 @@ import 'package:stackwallet/db/isar/main_db.dart';
|
|||
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart';
|
||||
|
@ -37,7 +36,7 @@ class DesktopCoinControlUseDialog extends ConsumerStatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final Decimal? amountToSend;
|
||||
final Amount? amountToSend;
|
||||
|
||||
@override
|
||||
ConsumerState<DesktopCoinControlUseDialog> createState() =>
|
||||
|
@ -114,12 +113,16 @@ class _DesktopCoinControlUseDialogState
|
|||
);
|
||||
}
|
||||
|
||||
final selectedSum = Format.satoshisToAmount(
|
||||
_selectedUTXOs
|
||||
.map((e) => e.value)
|
||||
.fold(0, (value, element) => value += element),
|
||||
coin: coin,
|
||||
);
|
||||
final Amount selectedSum = _selectedUTXOs.map((e) => e.value).fold(
|
||||
Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
(value, element) => value += Amount(
|
||||
rawValue: BigInt.from(element),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
|
||||
final enableApply = widget.amountToSend == null
|
||||
? selectedChanged(_selectedUTXOs)
|
||||
|
@ -470,7 +473,7 @@ class _DesktopCoinControlUseDialogState
|
|||
),
|
||||
),
|
||||
Text(
|
||||
"${widget.amountToSend!.toStringAsFixed(
|
||||
"${widget.amountToSend!.decimal.toStringAsFixed(
|
||||
coin.decimals,
|
||||
)}"
|
||||
" ${coin.ticker}",
|
||||
|
@ -505,7 +508,7 @@ class _DesktopCoinControlUseDialogState
|
|||
),
|
||||
),
|
||||
Text(
|
||||
"${selectedSum.toStringAsFixed(
|
||||
"${selectedSum.decimal.toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(
|
||||
|
|
|
@ -4,9 +4,10 @@ import 'package:isar/isar.dart';
|
|||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/pages/coin_control/utxo_details_view.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
|
@ -143,10 +144,16 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
),
|
||||
if (!widget.compact)
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
"${Amount(
|
||||
rawValue: BigInt.from(utxo.value),
|
||||
fractionDigits: coin.decimals,
|
||||
).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
textAlign: TextAlign.right,
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
|
@ -163,10 +170,16 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
"${Amount(
|
||||
rawValue: BigInt.from(utxo.value),
|
||||
fractionDigits: coin.decimals,
|
||||
).localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
)} ${coin.ticker}",
|
||||
textAlign: TextAlign.right,
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
|||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
|
||||
|
@ -182,10 +183,11 @@ class _StepScaffoldState extends ConsumerState<StepScaffold> {
|
|||
|
||||
void sendFromStack() {
|
||||
final trade = ref.read(desktopExchangeModelProvider)!.trade!;
|
||||
final amount = Decimal.parse(trade.payInAmount);
|
||||
final address = trade.payInAddress;
|
||||
|
||||
final coin = coinFromTickerCaseInsensitive(trade.payInCurrency);
|
||||
final amount = Decimal.parse(trade.payInAmount).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -6,10 +5,8 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||
|
@ -268,7 +265,7 @@ class _DesktopChooseFromStackState
|
|||
}
|
||||
}
|
||||
|
||||
class BalanceDisplay extends ConsumerStatefulWidget {
|
||||
class BalanceDisplay extends ConsumerWidget {
|
||||
const BalanceDisplay({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
|
@ -277,65 +274,19 @@ class BalanceDisplay extends ConsumerStatefulWidget {
|
|||
final String walletId;
|
||||
|
||||
@override
|
||||
ConsumerState<BalanceDisplay> createState() => _BalanceDisplayState();
|
||||
}
|
||||
|
||||
class _BalanceDisplayState extends ConsumerState<BalanceDisplay> {
|
||||
late final String walletId;
|
||||
|
||||
Decimal? _cachedBalance;
|
||||
|
||||
static const loopedText = [
|
||||
"Loading balance ",
|
||||
"Loading balance. ",
|
||||
"Loading balance.. ",
|
||||
"Loading balance..."
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
walletId = widget.walletId;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final manager = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId)));
|
||||
final locale = ref.watch(
|
||||
localeServiceChangeNotifierProvider.select((value) => value.locale));
|
||||
|
||||
// TODO redo this widget now that its not actually a future
|
||||
return FutureBuilder(
|
||||
future: Future(() => manager.balance.getSpendable()),
|
||||
builder: (context, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData &&
|
||||
snapshot.data != null) {
|
||||
_cachedBalance = snapshot.data;
|
||||
}
|
||||
|
||||
if (_cachedBalance == null) {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: loopedText,
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: _cachedBalance!,
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
}
|
||||
},
|
||||
return Text(
|
||||
"${manager.balance.spendable.localizedStringAsFixed(locale: locale)} "
|
||||
"${manager.coin.ticker}",
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ import 'package:stackwallet/providers/global/price_provider.dart';
|
|||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
|
@ -120,22 +120,15 @@ class _DesktopPaynymSendDialogState
|
|||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: !isFiro
|
||||
? manager.balance.getSpendable()
|
||||
: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private"
|
||||
? (manager.wallet as FiroWallet)
|
||||
.availablePrivateBalance()
|
||||
: (manager.wallet as FiroWallet)
|
||||
.availablePublicBalance(),
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${coin.ticker}",
|
||||
"${!isFiro ? manager.balance.spendable.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
) : ref.watch(
|
||||
publicPrivateBalanceStateProvider.state,
|
||||
).state == "Private" ? (manager.wallet as FiroWallet).availablePrivateBalance().localizedStringAsFixed(
|
||||
locale: locale,
|
||||
) : (manager.wallet as FiroWallet).availablePublicBalance().localizedStringAsFixed(
|
||||
locale: locale,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.titleBold12(context),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
|
@ -143,25 +136,7 @@ class _DesktopPaynymSendDialogState
|
|||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: (!isFiro
|
||||
? manager.balance.getSpendable()
|
||||
: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private"
|
||||
? (manager.wallet as FiroWallet)
|
||||
.availablePrivateBalance()
|
||||
: (manager.wallet as FiroWallet)
|
||||
.availablePublicBalance()) *
|
||||
ref.watch(
|
||||
priceAnd24hChangeNotifierProvider.select(
|
||||
(value) => value.getPrice(coin).item1)),
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
"${((!isFiro ? manager.balance.spendable.decimal : ref.watch(publicPrivateBalanceStateProvider.state).state == "Private" ? (manager.wallet as FiroWallet).availablePrivateBalance().decimal : (manager.wallet as FiroWallet).availablePublicBalance().decimal) * ref.watch(priceAnd24hChangeNotifierProvider.select((value) => value.getPrice(coin).item1))).toAmount(fractionDigits: 2).localizedStringAsFixed(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
|
||||
style: STextStyles.baseXS(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -3,9 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
|
@ -205,8 +205,10 @@ class TablePriceInfo extends ConsumerWidget {
|
|||
),
|
||||
);
|
||||
|
||||
final priceString = Format.localizedStringAsFixed(
|
||||
value: tuple.item1,
|
||||
final priceString = Amount.fromDecimal(
|
||||
tuple.item1,
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: ref
|
||||
.watch(
|
||||
localeServiceChangeNotifierProvider.notifier,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -10,11 +9,11 @@ import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|||
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
|
@ -44,8 +43,8 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
|||
"Calculating...",
|
||||
];
|
||||
|
||||
Future<Decimal> feeFor({
|
||||
required int amount,
|
||||
Future<Amount> feeFor({
|
||||
required Amount amount,
|
||||
required FeeRateType feeRateType,
|
||||
required int feeRate,
|
||||
required Coin coin,
|
||||
|
@ -59,24 +58,16 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.fast.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
|
||||
|
@ -89,24 +80,16 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.regular.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).average[amount]!;
|
||||
|
@ -119,24 +102,16 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
|||
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||
final fee = await manager.estimateFeeFor(
|
||||
amount, MoneroTransactionPriority.slow.raw!);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
fee,
|
||||
coin: coin,
|
||||
);
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||
"Private") {
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate),
|
||||
coin: coin);
|
||||
await (manager.wallet as FiroWallet)
|
||||
.estimateFeeForPublic(amount, feeRate);
|
||||
} else {
|
||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||
Format.satoshisToAmount(
|
||||
await manager.estimateFeeFor(amount, feeRate),
|
||||
coin: coin);
|
||||
await manager.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
}
|
||||
return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
|
||||
|
@ -242,7 +217,7 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
|||
}
|
||||
|
||||
final sendAmountProvider =
|
||||
StateProvider.autoDispose<Decimal>((_) => Decimal.zero);
|
||||
StateProvider.autoDispose<Amount>((_) => Amount.zero);
|
||||
|
||||
class FeeDropDownChild extends ConsumerWidget {
|
||||
const FeeDropDownChild({
|
||||
|
@ -257,8 +232,8 @@ class FeeDropDownChild extends ConsumerWidget {
|
|||
final FeeObject? feeObject;
|
||||
final FeeRateType feeRateType;
|
||||
final String walletId;
|
||||
final Future<Decimal> Function({
|
||||
required int amount,
|
||||
final Future<Amount> Function({
|
||||
required Amount amount,
|
||||
required FeeRateType feeRateType,
|
||||
required int feeRate,
|
||||
required Coin coin,
|
||||
|
@ -322,19 +297,20 @@ class FeeDropDownChild extends ConsumerWidget {
|
|||
: feeRateType == FeeRateType.slow
|
||||
? feeObject!.slow
|
||||
: feeObject!.medium,
|
||||
amount: Format.decimalAmountToSatoshis(
|
||||
ref.watch(sendAmountProvider.state).state,
|
||||
manager.coin,
|
||||
),
|
||||
amount: ref.watch(sendAmountProvider.state).state,
|
||||
),
|
||||
builder: (_, AsyncSnapshot<Decimal> snapshot) {
|
||||
builder: (_, AsyncSnapshot<Amount> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"${feeRateType.prettyName} (~${snapshot.data!} ${manager.coin.ticker})",
|
||||
"${feeRateType.prettyName} "
|
||||
"(~${snapshot.data!.decimal.toStringAsFixed(
|
||||
manager.coin.decimals,
|
||||
)} "
|
||||
"${manager.coin.ticker})",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
|
|
|
@ -25,12 +25,12 @@ import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
|||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/address_utils.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -88,8 +88,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
|
||||
String? _note;
|
||||
|
||||
Decimal? _amountToSend;
|
||||
Decimal? _cachedAmountToSend;
|
||||
Amount? _amountToSend;
|
||||
Amount? _cachedAmountToSend;
|
||||
String? _address;
|
||||
|
||||
String? _privateBalanceString;
|
||||
|
@ -106,20 +106,19 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||
|
||||
final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin);
|
||||
int availableBalance;
|
||||
final Amount amount = _amountToSend!;
|
||||
final Amount availableBalance;
|
||||
if ((coin == Coin.firo || coin == Coin.firoTestNet)) {
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
availableBalance = Format.decimalAmountToSatoshis(
|
||||
(manager.wallet as FiroWallet).availablePrivateBalance(), coin);
|
||||
availableBalance =
|
||||
(manager.wallet as FiroWallet).availablePrivateBalance();
|
||||
} else {
|
||||
availableBalance = Format.decimalAmountToSatoshis(
|
||||
(manager.wallet as FiroWallet).availablePublicBalance(), coin);
|
||||
availableBalance =
|
||||
(manager.wallet as FiroWallet).availablePublicBalance();
|
||||
}
|
||||
} else {
|
||||
availableBalance =
|
||||
Format.decimalAmountToSatoshis(manager.balance.getSpendable(), coin);
|
||||
availableBalance = manager.balance.spendable;
|
||||
}
|
||||
|
||||
final coinControlEnabled =
|
||||
|
@ -268,7 +267,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
final feeRate = ref.read(feeRateTypeStateProvider);
|
||||
txDataFuture = wallet.preparePaymentCodeSend(
|
||||
paymentCode: paymentCode,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": feeRate,
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -283,7 +282,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
"Private") {
|
||||
txDataFuture = (manager.wallet as FiroWallet).prepareSendPublic(
|
||||
address: _address!,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -296,7 +295,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
} else {
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: _address!,
|
||||
satoshiAmount: amount,
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -435,7 +434,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
cryptoAmount != ",") {
|
||||
_amountToSend = cryptoAmount.contains(",")
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
|
||||
: Decimal.parse(cryptoAmount);
|
||||
.toAmount(fractionDigits: coin.decimals)
|
||||
: Decimal.parse(cryptoAmount)
|
||||
.toAmount(fractionDigits: coin.decimals);
|
||||
if (_cachedAmountToSend != null &&
|
||||
_cachedAmountToSend == _amountToSend) {
|
||||
return;
|
||||
|
@ -448,11 +449,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
||||
|
||||
if (price > Decimal.zero) {
|
||||
final String fiatAmountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend! * price,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
final String fiatAmountString = (_amountToSend!.decimal * price)
|
||||
.toAmount(fractionDigits: 2)
|
||||
.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
|
||||
baseAmountController.text = fiatAmountString;
|
||||
}
|
||||
|
@ -476,17 +477,17 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
return null;
|
||||
}
|
||||
|
||||
void _updatePreviewButtonState(String? address, Decimal? amount) {
|
||||
void _updatePreviewButtonState(String? address, Amount? amount) {
|
||||
if (isPaynymSend) {
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(amount != null && amount > Decimal.zero);
|
||||
(amount != null && amount > Amount.zero);
|
||||
} else {
|
||||
final isValidAddress = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.validateAddress(address ?? "");
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(isValidAddress && amount != null && amount > Decimal.zero);
|
||||
(isValidAddress && amount != null && amount > Amount.zero);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,15 +499,16 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
final wallet = ref.read(provider).wallet as FiroWallet?;
|
||||
|
||||
if (wallet != null) {
|
||||
Decimal? balance;
|
||||
Amount? balance;
|
||||
if (private) {
|
||||
balance = wallet.availablePrivateBalance();
|
||||
} else {
|
||||
balance = wallet.availablePublicBalance();
|
||||
}
|
||||
|
||||
return Format.localizedStringAsFixed(
|
||||
value: balance, locale: locale, decimalPlaces: 8);
|
||||
return balance.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -577,9 +579,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
|
||||
// autofill amount field
|
||||
if (results["amount"] != null) {
|
||||
final amount = Decimal.parse(results["amount"]!);
|
||||
cryptoAmountController.text = Format.localizedStringAsFixed(
|
||||
value: amount,
|
||||
final amount = Decimal.parse(results["amount"]!).toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
cryptoAmountController.text = amount.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
|
@ -643,18 +646,20 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
baseAmountString != ",") {
|
||||
final baseAmount = baseAmountString.contains(",")
|
||||
? Decimal.parse(baseAmountString.replaceFirst(",", "."))
|
||||
: Decimal.parse(baseAmountString);
|
||||
.toAmount(fractionDigits: 2)
|
||||
: Decimal.parse(baseAmountString).toAmount(fractionDigits: 2);
|
||||
|
||||
var _price =
|
||||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
||||
|
||||
if (_price == Decimal.zero) {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend = Decimal.zero.toAmount(fractionDigits: coin.decimals);
|
||||
} else {
|
||||
_amountToSend = baseAmount <= Decimal.zero
|
||||
? Decimal.zero
|
||||
: (baseAmount / _price).toDecimal(
|
||||
scaleOnInfinitePrecision: Constants.decimalPlacesForCoin(coin));
|
||||
_amountToSend = baseAmount <= Amount.zero
|
||||
? Decimal.zero.toAmount(fractionDigits: coin.decimals)
|
||||
: (baseAmount.decimal / _price)
|
||||
.toDecimal(scaleOnInfinitePrecision: coin.decimals)
|
||||
.toAmount(fractionDigits: coin.decimals);
|
||||
}
|
||||
if (_cachedAmountToSend != null && _cachedAmountToSend == _amountToSend) {
|
||||
return;
|
||||
|
@ -663,17 +668,16 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend",
|
||||
level: LogLevel.Info);
|
||||
|
||||
final amountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend!,
|
||||
final amountString = _amountToSend!.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
decimalPlaces: coin.decimals,
|
||||
);
|
||||
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = amountString;
|
||||
_cryptoAmountChangeLock = false;
|
||||
} else {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend = Decimal.zero.toAmount(fractionDigits: coin.decimals);
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = "";
|
||||
_cryptoAmountChangeLock = false;
|
||||
|
@ -694,19 +698,24 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
.wallet as FiroWallet;
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
cryptoAmountController.text = (firoWallet.availablePrivateBalance())
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cryptoAmountController.text = firoWallet
|
||||
.availablePrivateBalance()
|
||||
.decimal
|
||||
.toStringAsFixed(coin.decimals);
|
||||
} else {
|
||||
cryptoAmountController.text = (firoWallet.availablePublicBalance())
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cryptoAmountController.text = firoWallet
|
||||
.availablePublicBalance()
|
||||
.decimal
|
||||
.toStringAsFixed(coin.decimals);
|
||||
}
|
||||
} else {
|
||||
cryptoAmountController.text = (ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.balance
|
||||
.getSpendable())
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cryptoAmountController.text = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.balance
|
||||
.spendable
|
||||
.decimal
|
||||
.toStringAsFixed(coin.decimals);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
|
|||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -72,7 +71,6 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
late TextEditingController sendToController;
|
||||
late TextEditingController cryptoAmountController;
|
||||
late TextEditingController baseAmountController;
|
||||
// late TextEditingController feeController;
|
||||
|
||||
late final SendViewAutoFillData? _data;
|
||||
|
||||
|
@ -82,8 +80,8 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
|
||||
String? _note;
|
||||
|
||||
Decimal? _amountToSend;
|
||||
Decimal? _cachedAmountToSend;
|
||||
Amount? _amountToSend;
|
||||
Amount? _cachedAmountToSend;
|
||||
String? _address;
|
||||
|
||||
bool _addressToggleFlag = false;
|
||||
|
@ -94,16 +92,11 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
Future<void> previewSend() async {
|
||||
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||
|
||||
final amount = Amount.fromDecimal(
|
||||
_amountToSend!,
|
||||
fractionDigits: tokenWallet.tokenContract.decimals,
|
||||
);
|
||||
|
||||
// todo use Amount class
|
||||
final availableBalance = tokenWallet.balance.spendable;
|
||||
final Amount amount = _amountToSend!;
|
||||
final Amount availableBalance = tokenWallet.balance.spendable;
|
||||
|
||||
// confirm send all
|
||||
if (amount.raw.toInt() == availableBalance) {
|
||||
if (amount == availableBalance) {
|
||||
final bool? shouldSendAll = await showDialog<bool>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
|
@ -233,7 +226,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
|
||||
txDataFuture = tokenWallet.prepareSend(
|
||||
address: _address!,
|
||||
satoshiAmount: amount.raw.toInt(),
|
||||
amount: amount,
|
||||
args: {
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
},
|
||||
|
@ -361,8 +354,14 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
cryptoAmount != "." &&
|
||||
cryptoAmount != ",") {
|
||||
_amountToSend = cryptoAmount.contains(",")
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
|
||||
: Decimal.parse(cryptoAmount);
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", ".")).toAmount(
|
||||
fractionDigits:
|
||||
ref.read(tokenServiceProvider)!.tokenContract.decimals,
|
||||
)
|
||||
: Decimal.parse(cryptoAmount).toAmount(
|
||||
fractionDigits:
|
||||
ref.read(tokenServiceProvider)!.tokenContract.decimals,
|
||||
);
|
||||
if (_cachedAmountToSend != null &&
|
||||
_cachedAmountToSend == _amountToSend) {
|
||||
return;
|
||||
|
@ -375,8 +374,10 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
||||
|
||||
if (price > Decimal.zero) {
|
||||
final String fiatAmountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend! * price,
|
||||
final String fiatAmountString = Amount.fromDecimal(
|
||||
_amountToSend!.decimal * price,
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: 2,
|
||||
);
|
||||
|
@ -403,13 +404,13 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
return null;
|
||||
}
|
||||
|
||||
void _updatePreviewButtonState(String? address, Decimal? amount) {
|
||||
void _updatePreviewButtonState(String? address, Amount? amount) {
|
||||
final isValidAddress = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.validateAddress(address ?? "");
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(isValidAddress && amount != null && amount > Decimal.zero);
|
||||
(isValidAddress && amount != null && amount > Amount.zero);
|
||||
}
|
||||
|
||||
Future<void> scanQr() async {
|
||||
|
@ -442,12 +443,14 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
|
||||
// autofill amount field
|
||||
if (results["amount"] != null) {
|
||||
final amount = Decimal.parse(results["amount"]!);
|
||||
cryptoAmountController.text = Format.localizedStringAsFixed(
|
||||
value: amount,
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
final amount = Decimal.parse(results["amount"]!).toAmount(
|
||||
fractionDigits:
|
||||
ref.read(tokenServiceProvider)!.tokenContract.decimals,
|
||||
);
|
||||
cryptoAmountController.text = amount.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
);
|
||||
|
||||
amount.toString();
|
||||
_amountToSend = amount;
|
||||
}
|
||||
|
@ -498,23 +501,28 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
}
|
||||
|
||||
void fiatTextFieldOnChanged(String baseAmountString) {
|
||||
final int tokenDecimals =
|
||||
ref.read(tokenServiceProvider)!.tokenContract.decimals;
|
||||
|
||||
if (baseAmountString.isNotEmpty &&
|
||||
baseAmountString != "." &&
|
||||
baseAmountString != ",") {
|
||||
final baseAmount = baseAmountString.contains(",")
|
||||
? Decimal.parse(baseAmountString.replaceFirst(",", "."))
|
||||
: Decimal.parse(baseAmountString);
|
||||
.toAmount(fractionDigits: 2)
|
||||
: Decimal.parse(baseAmountString).toAmount(fractionDigits: 2);
|
||||
|
||||
var _price =
|
||||
final Decimal _price =
|
||||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
||||
|
||||
if (_price == Decimal.zero) {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend = Decimal.zero.toAmount(fractionDigits: tokenDecimals);
|
||||
} else {
|
||||
_amountToSend = baseAmount <= Decimal.zero
|
||||
? Decimal.zero
|
||||
: (baseAmount / _price).toDecimal(
|
||||
scaleOnInfinitePrecision: Constants.decimalPlacesForCoin(coin));
|
||||
_amountToSend = baseAmount <= Amount.zero
|
||||
? Decimal.zero.toAmount(fractionDigits: tokenDecimals)
|
||||
: (baseAmount.decimal / _price)
|
||||
.toDecimal(scaleOnInfinitePrecision: tokenDecimals)
|
||||
.toAmount(fractionDigits: tokenDecimals);
|
||||
}
|
||||
if (_cachedAmountToSend != null && _cachedAmountToSend == _amountToSend) {
|
||||
return;
|
||||
|
@ -523,17 +531,16 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend",
|
||||
level: LogLevel.Info);
|
||||
|
||||
final amountString = Format.localizedStringAsFixed(
|
||||
value: _amountToSend!,
|
||||
final amountString = _amountToSend!.localizedStringAsFixed(
|
||||
locale: ref.read(localeServiceChangeNotifierProvider).locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
decimalPlaces: tokenDecimals,
|
||||
);
|
||||
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = amountString;
|
||||
_cryptoAmountChangeLock = false;
|
||||
} else {
|
||||
_amountToSend = Decimal.zero;
|
||||
_amountToSend = Decimal.zero.toAmount(fractionDigits: tokenDecimals);
|
||||
_cryptoAmountChangeLock = true;
|
||||
cryptoAmountController.text = "";
|
||||
_cryptoAmountChangeLock = false;
|
||||
|
@ -543,9 +550,14 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
|||
}
|
||||
|
||||
Future<void> sendAllTapped() async {
|
||||
cryptoAmountController.text =
|
||||
(ref.read(tokenServiceProvider)!.balance.getSpendable())
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
cryptoAmountController.text = ref
|
||||
.read(tokenServiceProvider)!
|
||||
.balance
|
||||
.spendable
|
||||
.decimal
|
||||
.toStringAsFixed(
|
||||
ref.read(tokenServiceProvider)!.tokenContract.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
@ -18,6 +17,7 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/providers/wallet/my_paynym_account_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -162,7 +162,7 @@ class _DesktopWalletFeaturesState extends ConsumerState<DesktopWalletFeatures> {
|
|||
final firoWallet = ref.read(managerProvider).wallet as FiroWallet;
|
||||
|
||||
final publicBalance = firoWallet.availablePublicBalance();
|
||||
if (publicBalance <= Decimal.zero) {
|
||||
if (publicBalance <= Amount.zero) {
|
||||
shouldPop = true;
|
||||
if (context.mounted) {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/balance.dart';
|
||||
|
@ -9,9 +8,9 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
||||
|
@ -86,7 +85,7 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
|||
: ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).balance));
|
||||
|
||||
Decimal balanceToShow;
|
||||
Amount balanceToShow;
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
Balance? balanceSecondary = ref
|
||||
.watch(
|
||||
|
@ -101,18 +100,16 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
|||
WalletBalanceToggleState.available;
|
||||
|
||||
if (_showAvailable) {
|
||||
balanceToShow = showPrivate
|
||||
? balanceSecondary!.getSpendable()
|
||||
: balance.getSpendable();
|
||||
} else {
|
||||
balanceToShow =
|
||||
showPrivate ? balanceSecondary!.getTotal() : balance.getTotal();
|
||||
showPrivate ? balanceSecondary!.spendable : balance.spendable;
|
||||
} else {
|
||||
balanceToShow = showPrivate ? balanceSecondary!.total : balance.total;
|
||||
}
|
||||
} else {
|
||||
if (_showAvailable) {
|
||||
balanceToShow = balance.getSpendable();
|
||||
balanceToShow = balance.spendable;
|
||||
} else {
|
||||
balanceToShow = balance.getTotal();
|
||||
balanceToShow = balance.total;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,8 +124,7 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
|||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: balanceToShow,
|
||||
"${balanceToShow.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: decimalPlaces,
|
||||
)} $unit",
|
||||
|
@ -137,8 +133,10 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
|||
),
|
||||
if (externalCalls)
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: priceTuple.item1 * balanceToShow,
|
||||
"${Amount.fromDecimal(
|
||||
priceTuple.item1 * balanceToShow.decimal,
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} $baseCurrency",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -144,6 +143,7 @@ import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/syncin
|
|||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/color_theme.dart';
|
||||
|
@ -1280,7 +1280,7 @@ class RouteGenerator {
|
|||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case SendFromView.routeName:
|
||||
if (args is Tuple4<Coin, Decimal, String, Trade>) {
|
||||
if (args is Tuple4<Coin, Amount, String, Trade>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => SendFromView(
|
||||
|
|
|
@ -51,8 +51,14 @@ import 'package:tuple/tuple.dart';
|
|||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 294;
|
||||
const int DUST_LIMIT_P2PKH = 546;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(294),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
final Amount DUST_LIMIT_P2PKH = Amount(
|
||||
rawValue: BigInt.from(546),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
|
||||
|
@ -155,7 +161,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
// checkChangeAddressForTransactions:
|
||||
// _checkP2PKHChangeAddressForTransactions,
|
||||
addDerivation: addDerivation,
|
||||
dustLimitP2PKH: DUST_LIMIT_P2PKH,
|
||||
dustLimitP2PKH: DUST_LIMIT_P2PKH.raw.toInt(),
|
||||
minConfirms: MINIMUM_CONFIRMATIONS,
|
||||
);
|
||||
}
|
||||
|
@ -1119,7 +1125,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -1149,14 +1155,14 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1468,9 +1474,18 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2404,8 +2419,11 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
feeRatePerKB: selectedTxFeeRate,
|
||||
);
|
||||
|
||||
final int roughEstimate =
|
||||
roughFeeEstimate(spendableOutputs.length, 1, selectedTxFeeRate);
|
||||
final int roughEstimate = roughFeeEstimate(
|
||||
spendableOutputs.length,
|
||||
1,
|
||||
selectedTxFeeRate,
|
||||
).raw.toInt();
|
||||
if (feeForOneOutput < roughEstimate) {
|
||||
feeForOneOutput = roughEstimate;
|
||||
}
|
||||
|
@ -2476,7 +2494,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2484,7 +2502,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -3063,22 +3081,28 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance += Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3087,31 +3111,35 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
}
|
||||
}
|
||||
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(
|
||||
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -3125,7 +3153,11 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -47,7 +47,10 @@ import 'package:tuple/tuple.dart';
|
|||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 0;
|
||||
const int DUST_LIMIT = 546;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(546),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
|
||||
|
@ -212,10 +215,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
|
||||
@override
|
||||
Future<int> get maxFee async {
|
||||
final fee = (await fees).fast;
|
||||
final satsFee = Format.satoshisToAmount(fee, coin: coin) *
|
||||
Decimal.fromInt(Constants.satsPerCoin(coin));
|
||||
return satsFee.floor().toBigInt().toInt();
|
||||
throw UnimplementedError("Not used in bch");
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1049,7 +1049,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -1078,14 +1078,14 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
}
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final result = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1423,9 +1423,18 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2156,12 +2165,27 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
Set<String> inputAddresses = {};
|
||||
Set<String> outputAddresses = {};
|
||||
|
||||
int totalInputValue = 0;
|
||||
int totalOutputValue = 0;
|
||||
Amount totalInputValue = Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount totalOutputValue = Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
int amountSentFromWallet = 0;
|
||||
int amountReceivedInWallet = 0;
|
||||
int changeAmount = 0;
|
||||
Amount amountSentFromWallet = Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount amountReceivedInWallet = Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount changeAmount = Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// parse inputs
|
||||
for (final input in txData["vin"] as List) {
|
||||
|
@ -2178,13 +2202,13 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
// check matching output
|
||||
if (prevOut == output["n"]) {
|
||||
// get value
|
||||
final value = Format.decimalAmountToSatoshis(
|
||||
final value = Amount.fromDecimal(
|
||||
Decimal.parse(output["value"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// add value to total
|
||||
totalInputValue += value;
|
||||
totalInputValue = totalInputValue + value;
|
||||
|
||||
// get input(prevOut) address
|
||||
final address =
|
||||
|
@ -2197,7 +2221,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
// if input was from my wallet, add value to amount sent
|
||||
if (receivingAddresses.contains(address) ||
|
||||
changeAddresses.contains(address)) {
|
||||
amountSentFromWallet += value;
|
||||
amountSentFromWallet = amountSentFromWallet + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2207,9 +2231,9 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
// parse outputs
|
||||
for (final output in txData["vout"] as List) {
|
||||
// get value
|
||||
final value = Format.decimalAmountToSatoshis(
|
||||
final value = Amount.fromDecimal(
|
||||
Decimal.parse(output["value"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// add value to total
|
||||
|
@ -2246,7 +2270,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
txData["address"] as isar_models.Address;
|
||||
|
||||
isar_models.TransactionType type;
|
||||
int amount;
|
||||
Amount amount;
|
||||
if (mySentFromAddresses.isNotEmpty && myReceivedOnAddresses.isNotEmpty) {
|
||||
// tx is sent to self
|
||||
type = isar_models.TransactionType.sentToSelf;
|
||||
|
@ -2301,10 +2325,10 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
scriptPubKeyAddress:
|
||||
json["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||
json['scriptPubKey']['type'] as String,
|
||||
value: Format.decimalAmountToSatoshis(
|
||||
value: Amount.fromDecimal(
|
||||
Decimal.parse(json["value"].toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
outputs.add(output);
|
||||
}
|
||||
|
@ -2316,12 +2340,9 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
(DateTime.now().millisecondsSinceEpoch ~/ 1000),
|
||||
type: type,
|
||||
subType: isar_models.TransactionSubType.none,
|
||||
amount: amount,
|
||||
amountString: Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: coin.decimals,
|
||||
).toJsonString(),
|
||||
fee: fee,
|
||||
amount: amount.raw.toInt(),
|
||||
amountString: amount.toJsonString(),
|
||||
fee: fee.raw.toInt(),
|
||||
height: txData["height"] as int?,
|
||||
isCancelled: false,
|
||||
isLelantus: false,
|
||||
|
@ -2548,7 +2569,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2556,7 +2577,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > 546 satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -3117,22 +3138,28 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance += Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3141,19 +3168,19 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
|
@ -3161,12 +3188,15 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
}
|
||||
|
||||
// TODO: correct formula for bch?
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -3180,7 +3210,11 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
|||
import 'package:stackwallet/services/coins/particl/particl_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
|
@ -244,7 +245,7 @@ abstract class CoinServiceAPI {
|
|||
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
});
|
||||
|
||||
|
@ -299,7 +300,7 @@ abstract class CoinServiceAPI {
|
|||
|
||||
bool get isConnected;
|
||||
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate);
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate);
|
||||
|
||||
Future<bool> generateNewAddress();
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:bip39/bip39.dart' as bip39;
|
|||
import 'package:bitcoindart/bitcoindart.dart';
|
||||
import 'package:bitcoindart/bitcoindart.dart' as btc_dart;
|
||||
import 'package:bs58check/bs58check.dart' as bs58check;
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
|
@ -49,7 +48,10 @@ import 'package:tuple/tuple.dart';
|
|||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 1000000;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(1000000),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691";
|
||||
|
@ -227,10 +229,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
|
||||
@override
|
||||
Future<int> get maxFee async {
|
||||
final fee = (await fees).fast;
|
||||
final satsFee = Format.satoshisToAmount(fee, coin: coin) *
|
||||
Decimal.fromInt(Constants.satsPerCoin(coin));
|
||||
return satsFee.floor().toBigInt().toInt();
|
||||
throw UnimplementedError("Not used in dogecoin");
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -915,7 +914,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -944,14 +943,14 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final result = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1250,9 +1249,18 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2241,7 +2249,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2249,7 +2257,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > 546 satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -2830,22 +2838,29 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance = runningBalance +
|
||||
Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2854,19 +2869,19 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
|
@ -2874,12 +2889,15 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
|
||||
// TODO: correct formula for doge?
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -2893,7 +2911,11 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -33,7 +33,6 @@ import 'package:stackwallet/utilities/default_epicboxes.dart';
|
|||
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
@ -857,20 +856,23 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
);
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> prepareSend(
|
||||
{required String address,
|
||||
required int satoshiAmount,
|
||||
Map<String, dynamic>? args}) async {
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
int realfee = await nativeFee(satoshiAmount);
|
||||
if (balance.spendable == satoshiAmount) {
|
||||
satoshiAmount = balance.spendable - realfee;
|
||||
int satAmount = amount.raw.toInt();
|
||||
int realfee = await nativeFee(satAmount);
|
||||
|
||||
if (balance.spendable == amount) {
|
||||
satAmount = balance.spendable.raw.toInt() - realfee;
|
||||
}
|
||||
|
||||
Map<String, dynamic> txData = {
|
||||
"fee": realfee,
|
||||
"addresss": address,
|
||||
"recipientAmt": satoshiAmount,
|
||||
"recipientAmt": satAmount,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -1939,9 +1941,13 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
bool isActive = false;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
int currentFee = await nativeFee(satoshiAmount, ifErrorEstimateFee: true);
|
||||
return currentFee;
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
int currentFee =
|
||||
await nativeFee(amount.raw.toInt(), ifErrorEstimateFee: true);
|
||||
return Amount(
|
||||
rawValue: BigInt.from(currentFee),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
// not used in epic currently
|
||||
|
@ -1973,18 +1979,21 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
|
||||
_balance = Balance(
|
||||
coin: coin,
|
||||
total: Format.decimalAmountToSatoshis(
|
||||
total: Amount.fromDecimal(
|
||||
Decimal.parse(total) + Decimal.parse(awaiting),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
spendable: Format.decimalAmountToSatoshis(
|
||||
spendable: Amount.fromDecimal(
|
||||
Decimal.parse(spendable),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: Format.decimalAmountToSatoshis(
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: Amount.fromDecimal(
|
||||
Decimal.parse(pending),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:ethereum_addresses/ethereum_addresses.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
@ -34,7 +33,6 @@ import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
|||
import 'package:stackwallet/utilities/eth_commons.dart';
|
||||
import 'package:stackwallet/utilities/extensions/extensions.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
@ -88,15 +86,27 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
if (jsonString == null) {
|
||||
return TokenBalance(
|
||||
contractAddress: contract.address,
|
||||
decimalPlaces: contract.decimals,
|
||||
total: 0,
|
||||
spendable: 0,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: contract.decimals,
|
||||
),
|
||||
spendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: contract.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: contract.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: contract.decimals,
|
||||
),
|
||||
);
|
||||
}
|
||||
return TokenBalance.fromJson(
|
||||
jsonString,
|
||||
contract.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -214,18 +224,29 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// TODO: check if toInt() is ok and if getBalance actually returns enough balance data
|
||||
_balance = Balance(
|
||||
coin: coin,
|
||||
total: ethBalance.getInWei.toInt(),
|
||||
spendable: ethBalance.getInWei.toInt(),
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount.fromDouble(
|
||||
ethBalance.getValueInUnit(web3.EtherUnit.ether),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
spendable: Amount.fromDouble(
|
||||
ethBalance.getValueInUnit(web3.EtherUnit.ether),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
await updateCachedBalance(_balance!);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
final fee = estimateFee(feeRate, _gasLimit, coin.decimals);
|
||||
return Format.decimalAmountToSatoshis(Decimal.parse(fee.toString()), coin);
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
return estimateFee(feeRate, _gasLimit, coin.decimals);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -370,9 +391,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
@override
|
||||
Future<int> get maxFee async {
|
||||
final fee = (await fees).fast;
|
||||
final feeEstimate = await estimateFeeFor(0, fee);
|
||||
return feeEstimate;
|
||||
throw UnimplementedError("Not used for eth");
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -421,10 +440,11 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> prepareSend(
|
||||
{required String address,
|
||||
required int satoshiAmount,
|
||||
Map<String, dynamic>? args}) async {
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
final feeRateType = args?["feeRate"];
|
||||
int fee = 0;
|
||||
final feeObject = await fees;
|
||||
|
@ -440,7 +460,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
break;
|
||||
}
|
||||
|
||||
final feeEstimate = await estimateFeeFor(satoshiAmount, fee);
|
||||
final feeEstimate = await estimateFeeFor(amount, fee);
|
||||
|
||||
// bool isSendAll = false;
|
||||
// final availableBalance = balance.spendable;
|
||||
|
@ -453,12 +473,6 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// satoshiAmount -= feeEstimate;
|
||||
// }
|
||||
|
||||
final decimalAmount = Format.satoshisToAmount(satoshiAmount, coin: coin);
|
||||
final bigIntAmount = amountToBigInt(
|
||||
decimalAmount.toDouble(),
|
||||
Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
|
||||
final client = getEthClient();
|
||||
|
||||
final myAddress = await currentReceivingAddress;
|
||||
|
@ -472,7 +486,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
fee,
|
||||
),
|
||||
amountOfGas: BigInt.from(_gasLimit),
|
||||
value: web3.EtherAmount.inWei(bigIntAmount),
|
||||
value: web3.EtherAmount.inWei(amount.raw),
|
||||
);
|
||||
|
||||
final nonce = args?["nonce"] as int? ??
|
||||
|
@ -494,7 +508,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
fee,
|
||||
),
|
||||
maxGas: _gasLimit,
|
||||
value: web3.EtherAmount.inWei(bigIntAmount),
|
||||
value: web3.EtherAmount.inWei(amount.raw),
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
|
@ -502,7 +516,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
"fee": feeEstimate,
|
||||
"feeInWei": fee,
|
||||
"address": address,
|
||||
"recipientAmt": satoshiAmount,
|
||||
"recipientAmt": amount,
|
||||
"ethTx": tx,
|
||||
"chainId": (await client.getChainId()).toInt(),
|
||||
"nonce": tx.nonce,
|
||||
|
|
|
@ -707,7 +707,10 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
|
|||
"txid": txId,
|
||||
"txHex": txHex,
|
||||
"value": amount,
|
||||
"fees": Format.satoshisToAmount(fee, coin: coin).toDouble(),
|
||||
"fees": Amount(
|
||||
rawValue: BigInt.from(fee),
|
||||
fractionDigits: coin.decimals,
|
||||
).decimal.toDouble(),
|
||||
"fee": fee,
|
||||
"vSize": extTx.virtualSize(),
|
||||
"jmintValue": changeToMint,
|
||||
|
@ -716,7 +719,10 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
|
|||
"height": locktime,
|
||||
"txType": "Sent",
|
||||
"confirmed_status": false,
|
||||
"amount": Format.satoshisToAmount(amount, coin: coin).toDouble(),
|
||||
"amount": Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: coin.decimals,
|
||||
).decimal.toDouble(),
|
||||
"recipientAmt": amount,
|
||||
"address": address,
|
||||
"timestamp": DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
|
@ -1030,7 +1036,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
Future<Map<String, dynamic>> prepareSendPublic({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -1059,14 +1065,17 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
final balance =
|
||||
Format.decimalAmountToSatoshis(availablePublicBalance(), coin);
|
||||
if (satoshiAmount == balance) {
|
||||
final balance = availablePublicBalance();
|
||||
if (amount == balance) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final txData =
|
||||
await coinSelection(satoshiAmount, rate, address, isSendAll);
|
||||
final txData = await coinSelection(
|
||||
amount.raw.toInt(),
|
||||
rate,
|
||||
address,
|
||||
isSendAll,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
try {
|
||||
|
@ -1139,20 +1148,22 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
final balance =
|
||||
Format.decimalAmountToSatoshis(availablePrivateBalance(), coin);
|
||||
if (satoshiAmount == balance) {
|
||||
final balance = availablePrivateBalance();
|
||||
if (amount == balance) {
|
||||
// print("is send all");
|
||||
isSendAll = true;
|
||||
}
|
||||
dynamic txHexOrError =
|
||||
await _createJoinSplitTransaction(satoshiAmount, address, isSendAll);
|
||||
dynamic txHexOrError = await _createJoinSplitTransaction(
|
||||
amount.raw.toInt(),
|
||||
address,
|
||||
isSendAll,
|
||||
);
|
||||
Logging.instance.log("txHexOrError $txHexOrError", level: LogLevel.Error);
|
||||
if (txHexOrError is int) {
|
||||
// Here, we assume that transaction crafting returned an error
|
||||
|
@ -2305,9 +2316,10 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
Future<int> _fetchMaxFee() async {
|
||||
final balance = availablePrivateBalance();
|
||||
int spendAmount = (balance * Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
int spendAmount =
|
||||
(balance.decimal * Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
int fee = await estimateJoinSplitFee(spendAmount);
|
||||
return fee;
|
||||
}
|
||||
|
@ -2503,10 +2515,23 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
_balancePrivate = Balance(
|
||||
coin: coin,
|
||||
total: intLelantusBalance + unconfirmedLelantusBalance,
|
||||
spendable: intLelantusBalance,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: unconfirmedLelantusBalance,
|
||||
total: Amount(
|
||||
rawValue:
|
||||
BigInt.from(intLelantusBalance + unconfirmedLelantusBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
spendable: Amount(
|
||||
rawValue: BigInt.from(intLelantusBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.from(unconfirmedLelantusBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
await updateCachedBalanceSecondary(_balancePrivate!);
|
||||
|
||||
|
@ -2605,8 +2630,10 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
final feesObject = await fees;
|
||||
|
||||
final Decimal fastFee =
|
||||
Format.satoshisToAmount(feesObject.fast, coin: coin);
|
||||
final Decimal fastFee = Amount(
|
||||
rawValue: BigInt.from(feesObject.fast),
|
||||
fractionDigits: coin.decimals,
|
||||
).decimal;
|
||||
int firoFee =
|
||||
(dvSize * fastFee * Decimal.fromInt(100000)).toDouble().ceil();
|
||||
// int firoFee = (vSize * feesObject.fast * (1 / 1000.0) * 100000000).ceil();
|
||||
|
@ -2795,12 +2822,18 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
"txid": txId,
|
||||
"txHex": txHex,
|
||||
"value": amount - fee,
|
||||
"fees": Format.satoshisToAmount(fee, coin: coin).toDouble(),
|
||||
"fees": Amount(
|
||||
rawValue: BigInt.from(fee),
|
||||
fractionDigits: coin.decimals,
|
||||
).decimal.toDouble(),
|
||||
"publicCoin": "",
|
||||
"height": height,
|
||||
"txType": "Sent",
|
||||
"confirmed_status": false,
|
||||
"amount": Format.satoshisToAmount(amount, coin: coin).toDouble(),
|
||||
"amount": Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: coin.decimals,
|
||||
).decimal.toDouble(),
|
||||
"timestamp": DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
"subType": "mint",
|
||||
"mintsMap": mintsMap,
|
||||
|
@ -3040,9 +3073,9 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
}
|
||||
await firoUpdateLelantusCoins(coins);
|
||||
|
||||
final amount = Format.decimalAmountToSatoshis(
|
||||
final amount = Amount.fromDecimal(
|
||||
Decimal.parse(transactionInfo["amount"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// add the send transaction
|
||||
|
@ -3059,15 +3092,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
: transactionInfo["subType"] == "join"
|
||||
? isar_models.TransactionSubType.join
|
||||
: isar_models.TransactionSubType.none,
|
||||
amount: amount,
|
||||
amountString: Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: Coin.firo.decimals,
|
||||
).toJsonString(),
|
||||
fee: Format.decimalAmountToSatoshis(
|
||||
amount: amount.raw.toInt(),
|
||||
amountString: amount.toJsonString(),
|
||||
fee: Amount.fromDecimal(
|
||||
Decimal.parse(transactionInfo["fees"].toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
height: transactionInfo["height"] as int?,
|
||||
isCancelled: false,
|
||||
isLelantus: true,
|
||||
|
@ -3154,9 +3184,18 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -3608,10 +3647,10 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
scriptPubKeyAddress:
|
||||
json["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||
json['scriptPubKey']['type'] as String,
|
||||
value: Format.decimalAmountToSatoshis(
|
||||
value: Amount.fromDecimal(
|
||||
Decimal.parse(json["value"].toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
outs.add(output);
|
||||
}
|
||||
|
@ -3692,10 +3731,22 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
final currentChainHeight = await chainHeight;
|
||||
|
||||
final List<isar_models.UTXO> outputArray = [];
|
||||
int satoshiBalanceTotal = 0;
|
||||
int satoshiBalancePending = 0;
|
||||
int satoshiBalanceSpendable = 0;
|
||||
int satoshiBalanceBlocked = 0;
|
||||
Amount satoshiBalanceTotal = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount satoshiBalancePending = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount satoshiBalanceSpendable = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount satoshiBalanceBlocked = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
for (int i = 0; i < fetchedUtxoList.length; i++) {
|
||||
for (int j = 0; j < fetchedUtxoList[i].length; j++) {
|
||||
|
@ -3720,15 +3771,19 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
blockTime: txn["blocktime"] as int?,
|
||||
);
|
||||
|
||||
satoshiBalanceTotal += utxo.value;
|
||||
final utxoAmount = Amount(
|
||||
rawValue: BigInt.from(utxo.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
satoshiBalanceTotal = satoshiBalanceTotal + utxoAmount;
|
||||
|
||||
if (utxo.isBlocked) {
|
||||
satoshiBalanceBlocked += utxo.value;
|
||||
satoshiBalanceBlocked = satoshiBalanceBlocked + utxoAmount;
|
||||
} else {
|
||||
if (utxo.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
satoshiBalanceSpendable += utxo.value;
|
||||
satoshiBalanceSpendable = satoshiBalanceSpendable + utxoAmount;
|
||||
} else {
|
||||
satoshiBalancePending += utxo.value;
|
||||
satoshiBalancePending = satoshiBalancePending + utxoAmount;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4751,7 +4806,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
int spendAmount,
|
||||
) async {
|
||||
var lelantusEntry = await _getLelantusEntry();
|
||||
final balance = availablePrivateBalance();
|
||||
final balance = availablePrivateBalance().decimal;
|
||||
int spendAmount = (balance * Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
|
@ -4808,27 +4863,34 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
// return fee;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
int fee = await estimateJoinSplitFee(satoshiAmount);
|
||||
return fee;
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
int fee = await estimateJoinSplitFee(amount.raw.toInt());
|
||||
return Amount(rawValue: BigInt.from(fee), fractionDigits: coin.decimals);
|
||||
}
|
||||
|
||||
Future<int> estimateFeeForPublic(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeForPublic(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance = runningBalance +
|
||||
Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -4837,19 +4899,24 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
final dustLimitAmount = Amount(
|
||||
rawValue: BigInt.from(DUST_LIMIT),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + dustLimitAmount) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > dustLimitAmount &&
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
|
@ -4857,12 +4924,15 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
}
|
||||
|
||||
// TODO: correct formula for firo?
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(((181 * inputCount) + (34 * outputCount) + 10) *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -4876,7 +4946,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> fastFetch(List<String> allTxHashes) async {
|
||||
|
@ -4949,9 +5023,9 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
tx["address"] = tx["vout"][sendIndex]["scriptPubKey"]["addresses"][0];
|
||||
tx["fees"] = tx["vin"][0]["nFees"];
|
||||
|
||||
final amount = Format.decimalAmountToSatoshis(
|
||||
final Amount amount = Amount.fromDecimal(
|
||||
Decimal.parse(tx["amount"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
final txn = isar_models.Transaction(
|
||||
|
@ -4961,15 +5035,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
(DateTime.now().millisecondsSinceEpoch ~/ 1000),
|
||||
type: isar_models.TransactionType.outgoing,
|
||||
subType: isar_models.TransactionSubType.join,
|
||||
amount: amount,
|
||||
amountString: Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: Coin.firo.decimals,
|
||||
).toJsonString(),
|
||||
fee: Format.decimalAmountToSatoshis(
|
||||
amount: amount.raw.toInt(),
|
||||
amountString: amount.toJsonString(),
|
||||
fee: Amount.fromDecimal(
|
||||
Decimal.parse(tx["fees"].toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
height: tx["height"] as int?,
|
||||
isCancelled: false,
|
||||
isLelantus: true,
|
||||
|
@ -5037,12 +5108,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
}
|
||||
}
|
||||
|
||||
Decimal availablePrivateBalance() {
|
||||
return balancePrivate.getSpendable();
|
||||
Amount availablePrivateBalance() {
|
||||
return balancePrivate.spendable;
|
||||
}
|
||||
|
||||
Decimal availablePublicBalance() {
|
||||
return balance.getSpendable();
|
||||
Amount availablePublicBalance() {
|
||||
return balance.spendable;
|
||||
}
|
||||
|
||||
Future<int> get chainHeight async {
|
||||
|
|
|
@ -47,8 +47,14 @@ import 'package:tuple/tuple.dart';
|
|||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 294;
|
||||
const int DUST_LIMIT_P2PKH = 546;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(294),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
final Amount DUST_LIMIT_P2PKH = Amount(
|
||||
rawValue: BigInt.from(546),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2";
|
||||
|
@ -1026,7 +1032,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -1056,14 +1062,14 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1423,9 +1429,18 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2354,8 +2369,11 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
feeRatePerKB: selectedTxFeeRate,
|
||||
);
|
||||
|
||||
final int roughEstimate =
|
||||
roughFeeEstimate(spendableOutputs.length, 1, selectedTxFeeRate);
|
||||
final int roughEstimate = roughFeeEstimate(
|
||||
spendableOutputs.length,
|
||||
1,
|
||||
selectedTxFeeRate,
|
||||
).raw.toInt();
|
||||
if (feeForOneOutput < roughEstimate) {
|
||||
feeForOneOutput = roughEstimate;
|
||||
}
|
||||
|
@ -2412,7 +2430,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2420,7 +2438,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -3229,22 +3247,29 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance = runningBalance +
|
||||
Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3253,31 +3278,35 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
}
|
||||
}
|
||||
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(
|
||||
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -3291,7 +3320,11 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:stackwallet/services/event_bus/events/global/updated_in_backgrou
|
|||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/services/mixins/coin_control_interface.dart';
|
||||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
|
@ -91,13 +92,13 @@ class Manager with ChangeNotifier {
|
|||
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
final txInfo = await _currentWallet.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: satoshiAmount,
|
||||
amount: amount,
|
||||
args: args,
|
||||
);
|
||||
// notifyListeners();
|
||||
|
@ -214,8 +215,8 @@ class Manager with ChangeNotifier {
|
|||
|
||||
bool get isConnected => _currentWallet.isConnected;
|
||||
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
return _currentWallet.estimateFeeFor(satoshiAmount, feeRate);
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
return _currentWallet.estimateFeeFor(amount, feeRate);
|
||||
}
|
||||
|
||||
Future<bool> generateNewAddress() async {
|
||||
|
|
|
@ -39,12 +39,10 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
|||
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
@ -171,7 +169,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
(await _generateAddressForChain(0, 0)).value;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
MoneroTransactionPriority priority;
|
||||
|
||||
switch (feeRate) {
|
||||
|
@ -193,9 +191,9 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
break;
|
||||
}
|
||||
|
||||
final fee = walletBase!.calculateEstimatedFee(priority, satoshiAmount);
|
||||
final fee = walletBase!.calculateEstimatedFee(priority, amount.raw.toInt());
|
||||
|
||||
return fee;
|
||||
return Amount(rawValue: BigInt.from(fee), fractionDigits: coin.decimals);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -432,7 +430,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
String toAddress = address;
|
||||
|
@ -457,16 +455,13 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// check for send all
|
||||
bool isSendAll = false;
|
||||
final balance = await _availableBalance;
|
||||
if (satoshiAmount == balance) {
|
||||
if (amount == balance) {
|
||||
isSendAll = true;
|
||||
}
|
||||
Logging.instance
|
||||
.log("$toAddress $satoshiAmount $args", level: LogLevel.Info);
|
||||
String amountToSend =
|
||||
Format.satoshisToAmount(satoshiAmount, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
Logging.instance
|
||||
.log("$satoshiAmount $amountToSend", level: LogLevel.Info);
|
||||
.log("$toAddress $amount $args", level: LogLevel.Info);
|
||||
String amountToSend = amount.decimal.toString();
|
||||
Logging.instance.log("$amount $amountToSend", level: LogLevel.Info);
|
||||
|
||||
monero_output.Output output = monero_output.Output(walletBase!);
|
||||
output.address = toAddress;
|
||||
|
@ -488,14 +483,16 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
PendingMoneroTransaction pendingMoneroTransaction =
|
||||
await (awaitPendingTransaction!) as PendingMoneroTransaction;
|
||||
|
||||
int realfee = Format.decimalAmountToSatoshis(
|
||||
Decimal.parse(pendingMoneroTransaction.feeFormatted), coin);
|
||||
debugPrint("fee? $realfee");
|
||||
final int realFee = Amount.fromDecimal(
|
||||
Decimal.parse(pendingMoneroTransaction.feeFormatted),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt();
|
||||
|
||||
Map<String, dynamic> txData = {
|
||||
"pendingMoneroTransaction": pendingMoneroTransaction,
|
||||
"fee": realfee,
|
||||
"fee": realFee,
|
||||
"addresss": toAddress,
|
||||
"recipientAmt": satoshiAmount,
|
||||
"recipientAmt": amount,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -753,25 +750,34 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
coin: coin,
|
||||
total: total,
|
||||
spendable: available,
|
||||
blockedTotal: 0,
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: total - available,
|
||||
);
|
||||
await updateCachedBalance(_balance!);
|
||||
}
|
||||
|
||||
Future<int> get _availableBalance async {
|
||||
Future<Amount> get _availableBalance async {
|
||||
try {
|
||||
int runningBalance = 0;
|
||||
for (final entry in walletBase!.balance!.entries) {
|
||||
runningBalance += entry.value.unlockedBalance;
|
||||
}
|
||||
return runningBalance;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(runningBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} catch (_) {
|
||||
return 0;
|
||||
return Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> get _totalBalance async {
|
||||
Future<Amount> get _totalBalance async {
|
||||
try {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
|
@ -780,7 +786,10 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
await _updateCachedBalance(bal);
|
||||
return bal;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(bal),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
|
@ -793,10 +802,16 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
|
||||
await _updateCachedBalance(transactionBalance);
|
||||
return transactionBalance;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(transactionBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
return _getCachedBalance();
|
||||
return Amount(
|
||||
rawValue: BigInt.from(_getCachedBalance()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ import 'package:uuid/uuid.dart';
|
|||
|
||||
const int MINIMUM_CONFIRMATIONS = 2;
|
||||
// Find real dust limit
|
||||
const int DUST_LIMIT = 546;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(546),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770";
|
||||
|
@ -1017,7 +1020,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -1047,14 +1050,14 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1413,9 +1416,18 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2347,8 +2359,11 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
feeRatePerKB: selectedTxFeeRate,
|
||||
);
|
||||
|
||||
final int roughEstimate =
|
||||
roughFeeEstimate(spendableOutputs.length, 1, selectedTxFeeRate);
|
||||
final int roughEstimate = roughFeeEstimate(
|
||||
spendableOutputs.length,
|
||||
1,
|
||||
selectedTxFeeRate,
|
||||
).raw.toInt();
|
||||
if (feeForOneOutput < roughEstimate) {
|
||||
feeForOneOutput = roughEstimate;
|
||||
}
|
||||
|
@ -2405,7 +2420,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2413,7 +2428,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -3221,22 +3236,29 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance = runningBalance +
|
||||
Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3245,19 +3267,19 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
|
@ -3265,12 +3287,16 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
|
||||
// TODO: Check if this is the correct formula for namecoin
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(
|
||||
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -3284,7 +3310,11 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -30,6 +30,7 @@ import 'package:stackwallet/services/mixins/wallet_db.dart';
|
|||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/bip32_utils.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -44,10 +45,11 @@ import 'package:stackwallet/utilities/prefs.dart';
|
|||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../../utilities/amount.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 294;
|
||||
final Amount DUST_LIMIT = Amount(
|
||||
rawValue: BigInt.from(294),
|
||||
fractionDigits: Coin.particl.decimals,
|
||||
);
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
"0000ee0784c195317ac95623e22fddb8c7b8825dc3998e0bb924d66866eccf4c";
|
||||
|
@ -945,7 +947,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -975,14 +977,14 @@ class ParticlWallet extends CoinServiceAPI
|
|||
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
if (satoshiAmount == balance.spendable) {
|
||||
if (amount == balance.spendable) {
|
||||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
satoshiAmountToSend: amount.raw.toInt(),
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
|
@ -1329,9 +1331,18 @@ class ParticlWallet extends CoinServiceAPI
|
|||
numberOfBlocksFast: f,
|
||||
numberOfBlocksAverage: m,
|
||||
numberOfBlocksSlow: s,
|
||||
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||
fast: Amount.fromDecimal(
|
||||
fast,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
medium: Amount.fromDecimal(
|
||||
medium,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
slow: Amount.fromDecimal(
|
||||
slow,
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
|
||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||
|
@ -2343,10 +2354,10 @@ class ParticlWallet extends CoinServiceAPI
|
|||
json["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||
json['scriptPubKey']?['type'] as String? ??
|
||||
"",
|
||||
value: Format.decimalAmountToSatoshis(
|
||||
value: Amount.fromDecimal(
|
||||
Decimal.parse((json["value"] ?? 0).toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
outputs.add(output);
|
||||
}
|
||||
|
@ -2514,8 +2525,11 @@ class ParticlWallet extends CoinServiceAPI
|
|||
feeRatePerKB: selectedTxFeeRate,
|
||||
);
|
||||
|
||||
final int roughEstimate =
|
||||
roughFeeEstimate(spendableOutputs.length, 1, selectedTxFeeRate);
|
||||
final int roughEstimate = roughFeeEstimate(
|
||||
spendableOutputs.length,
|
||||
1,
|
||||
selectedTxFeeRate,
|
||||
).raw.toInt();
|
||||
if (feeForOneOutput < roughEstimate) {
|
||||
feeForOneOutput = roughEstimate;
|
||||
}
|
||||
|
@ -2572,7 +2586,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
|
||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||
feeForOneOutput + DUST_LIMIT) {
|
||||
feeForOneOutput + DUST_LIMIT.raw.toInt()) {
|
||||
// Here, we know that theoretically, we may be able to include another output(change) but we first need to
|
||||
// factor in the value of this output in satoshis.
|
||||
int changeOutputSize =
|
||||
|
@ -2580,7 +2594,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
// We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
|
||||
// the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
|
||||
// change address.
|
||||
if (changeOutputSize > DUST_LIMIT &&
|
||||
if (changeOutputSize > DUST_LIMIT.raw.toInt() &&
|
||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
|
||||
feeForTwoOutputs) {
|
||||
// generate new change address if current change address has been used
|
||||
|
@ -3281,22 +3295,28 @@ class ParticlWallet extends CoinServiceAPI
|
|||
(isActive) => this.isActive = isActive;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
return satoshiAmount - (await sweepAllEstimate(feeRate));
|
||||
} else if (satoshiAmount <= 0 || satoshiAmount > available) {
|
||||
if (available == amount) {
|
||||
return amount - (await sweepAllEstimate(feeRate));
|
||||
} else if (amount <= Amount.zero || amount > available) {
|
||||
return roughFeeEstimate(1, 2, feeRate);
|
||||
}
|
||||
|
||||
int runningBalance = 0;
|
||||
Amount runningBalance = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
if (!output.isBlocked) {
|
||||
runningBalance += output.value;
|
||||
runningBalance += Amount(
|
||||
rawValue: BigInt.from(output.value),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
inputCount++;
|
||||
if (runningBalance > satoshiAmount) {
|
||||
if (runningBalance > amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3305,31 +3325,35 @@ class ParticlWallet extends CoinServiceAPI
|
|||
final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
|
||||
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee) {
|
||||
if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - satoshiAmount - twoOutPutFee;
|
||||
if (runningBalance - amount > oneOutPutFee) {
|
||||
if (runningBalance - amount > oneOutPutFee + DUST_LIMIT) {
|
||||
final change = runningBalance - amount - twoOutPutFee;
|
||||
if (change > DUST_LIMIT &&
|
||||
runningBalance - satoshiAmount - change == twoOutPutFee) {
|
||||
return runningBalance - satoshiAmount - change;
|
||||
runningBalance - amount - change == twoOutPutFee) {
|
||||
return runningBalance - amount - change;
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else {
|
||||
return runningBalance - satoshiAmount;
|
||||
return runningBalance - amount;
|
||||
}
|
||||
} else if (runningBalance - satoshiAmount == oneOutPutFee) {
|
||||
} else if (runningBalance - amount == oneOutPutFee) {
|
||||
return oneOutPutFee;
|
||||
} else {
|
||||
return twoOutPutFee;
|
||||
}
|
||||
}
|
||||
|
||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil();
|
||||
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(
|
||||
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||
(feeRatePerKB / 1000).ceil()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> sweepAllEstimate(int feeRate) async {
|
||||
Future<Amount> sweepAllEstimate(int feeRate) async {
|
||||
int available = 0;
|
||||
int inputCount = 0;
|
||||
for (final output in (await utxos)) {
|
||||
|
@ -3343,7 +3367,11 @@ class ParticlWallet extends CoinServiceAPI
|
|||
// transaction will only have 1 output minus the fee
|
||||
final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
|
||||
|
||||
return available - estimatedFee;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(available),
|
||||
fractionDigits: coin.decimals,
|
||||
) -
|
||||
estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -41,12 +41,10 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
|||
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
@ -173,7 +171,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
(await _generateAddressForChain(0, 0)).value;
|
||||
|
||||
@override
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
||||
MoneroTransactionPriority priority;
|
||||
FeeRateType feeRateType = FeeRateType.slow;
|
||||
switch (feeRate) {
|
||||
|
@ -206,18 +204,28 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
aprox = (await prepareSend(
|
||||
// This address is only used for getting an approximate fee, never for sending
|
||||
address: "WW3iVcnoAY6K9zNdU4qmdvZELefx6xZz4PMpTwUifRkvMQckyadhSPYMVPJhBdYE8P9c27fg9RPmVaWNFx1cDaj61HnetqBiy",
|
||||
satoshiAmount: satoshiAmount,
|
||||
amount: amount,
|
||||
args: {"feeRate": feeRateType}))['fee'];
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||
} catch (e, s) {
|
||||
aprox = walletBase!.calculateEstimatedFee(priority, satoshiAmount);
|
||||
aprox = walletBase!.calculateEstimatedFee(
|
||||
priority,
|
||||
amount.raw.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
print("this is the aprox fee $aprox for $satoshiAmount");
|
||||
final fee = (aprox as int);
|
||||
return fee;
|
||||
print("this is the aprox fee $aprox for $amount");
|
||||
|
||||
if (aprox is Amount) {
|
||||
return aprox as Amount;
|
||||
} else {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(aprox as int),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -451,7 +459,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
|
@ -475,16 +483,12 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// check for send all
|
||||
bool isSendAll = false;
|
||||
final balance = await _availableBalance;
|
||||
if (satoshiAmount == balance) {
|
||||
if (amount == balance) {
|
||||
isSendAll = true;
|
||||
}
|
||||
Logging.instance
|
||||
.log("$address $satoshiAmount $args", level: LogLevel.Info);
|
||||
String amountToSend =
|
||||
Format.satoshisToAmount(satoshiAmount, coin: coin)
|
||||
.toStringAsFixed(Constants.decimalPlacesForCoin(coin));
|
||||
Logging.instance
|
||||
.log("$satoshiAmount $amountToSend", level: LogLevel.Info);
|
||||
Logging.instance.log("$address $amount $args", level: LogLevel.Info);
|
||||
String amountToSend = amount.decimal.toString();
|
||||
Logging.instance.log("$amount $amountToSend", level: LogLevel.Info);
|
||||
|
||||
wownero_output.Output output = wownero_output.Output(walletBase!);
|
||||
output.address = address;
|
||||
|
@ -507,15 +511,16 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
PendingWowneroTransaction pendingWowneroTransaction =
|
||||
await (awaitPendingTransaction!) as PendingWowneroTransaction;
|
||||
int realfee = Format.decimalAmountToSatoshis(
|
||||
Decimal.parse(pendingWowneroTransaction.feeFormatted), coin);
|
||||
//todo: check if print needed
|
||||
// debugPrint("fee? $realfee");
|
||||
final int realFee = Amount.fromDecimal(
|
||||
Decimal.parse(pendingWowneroTransaction.feeFormatted),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt();
|
||||
|
||||
Map<String, dynamic> txData = {
|
||||
"pendingWowneroTransaction": pendingWowneroTransaction,
|
||||
"fee": realfee,
|
||||
"fee": realFee,
|
||||
"addresss": address,
|
||||
"recipientAmt": satoshiAmount,
|
||||
"recipientAmt": amount,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -772,25 +777,34 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
coin: coin,
|
||||
total: total,
|
||||
spendable: available,
|
||||
blockedTotal: 0,
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
pendingSpendable: total - available,
|
||||
);
|
||||
await updateCachedBalance(_balance!);
|
||||
}
|
||||
|
||||
Future<int> get _availableBalance async {
|
||||
Future<Amount> get _availableBalance async {
|
||||
try {
|
||||
int runningBalance = 0;
|
||||
for (final entry in walletBase!.balance!.entries) {
|
||||
runningBalance += entry.value.unlockedBalance;
|
||||
}
|
||||
return runningBalance;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(runningBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} catch (_) {
|
||||
return 0;
|
||||
return Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> get _totalBalance async {
|
||||
Future<Amount> get _totalBalance async {
|
||||
try {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
|
@ -799,7 +813,10 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
await _updateCachedBalance(bal);
|
||||
return bal;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(bal),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
|
@ -812,10 +829,16 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
|
||||
await _updateCachedBalance(transactionBalance);
|
||||
return transactionBalance;
|
||||
return Amount(
|
||||
rawValue: BigInt.from(transactionBalance),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
return _getCachedBalance();
|
||||
return Amount(
|
||||
rawValue: BigInt.from(_getCachedBalance()),
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
|
|||
import 'package:stackwallet/models/token_balance.dart';
|
||||
import 'package:stackwallet/services/ethereum/ethereum_api.dart';
|
||||
import 'package:stackwallet/services/mixins/eth_token_cache.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class CachedEthTokenBalance with EthTokenCache {
|
||||
|
@ -22,11 +23,22 @@ class CachedEthTokenBalance with EthTokenCache {
|
|||
await updateCachedBalance(
|
||||
TokenBalance(
|
||||
contractAddress: token.address,
|
||||
decimalPlaces: token.decimals,
|
||||
total: response.value!,
|
||||
spendable: response.value!,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount(
|
||||
rawValue: BigInt.from(response.value!),
|
||||
fractionDigits: token.decimals,
|
||||
),
|
||||
spendable: Amount(
|
||||
rawValue: BigInt.from(response.value!),
|
||||
fractionDigits: token.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: token.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: token.decimals,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -28,7 +28,6 @@ import 'package:stackwallet/utilities/eth_commons.dart';
|
|||
import 'package:stackwallet/utilities/extensions/extensions.dart';
|
||||
import 'package:stackwallet/utilities/extensions/impl/contract_abi.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:web3dart/web3dart.dart' as web3dart;
|
||||
|
@ -68,7 +67,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
|
||||
Future<Map<String, dynamic>> prepareSend({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
final feeRateType = args?["feeRate"];
|
||||
|
@ -86,12 +85,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
break;
|
||||
}
|
||||
|
||||
final feeEstimate = await estimateFeeFor(satoshiAmount, fee);
|
||||
|
||||
final decimalAmount =
|
||||
Format.satoshisToAmount(satoshiAmount, coin: Coin.ethereum);
|
||||
final bigIntAmount =
|
||||
amountToBigInt(decimalAmount.toDouble(), tokenContract.decimals);
|
||||
final feeEstimate = estimateFeeFor(fee);
|
||||
|
||||
final client = await getEthClient();
|
||||
|
||||
|
@ -101,8 +95,8 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
final est = await client.estimateGas(
|
||||
sender: myWeb3Address,
|
||||
to: web3dart.EthereumAddress.fromHex(address),
|
||||
data: _sendFunction.encodeCall(
|
||||
[web3dart.EthereumAddress.fromHex(address), bigIntAmount]),
|
||||
data: _sendFunction
|
||||
.encodeCall([web3dart.EthereumAddress.fromHex(address), amount.raw]),
|
||||
gasPrice: web3dart.EtherAmount.fromUnitAndValue(
|
||||
web3dart.EtherUnit.wei,
|
||||
fee,
|
||||
|
@ -125,7 +119,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
final tx = web3dart.Transaction.callContract(
|
||||
contract: _deployedContract,
|
||||
function: _sendFunction,
|
||||
parameters: [web3dart.EthereumAddress.fromHex(address), bigIntAmount],
|
||||
parameters: [web3dart.EthereumAddress.fromHex(address), amount.raw],
|
||||
maxGas: _gasLimit,
|
||||
gasPrice: web3dart.EtherAmount.fromUnitAndValue(
|
||||
web3dart.EtherUnit.wei,
|
||||
|
@ -138,7 +132,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
"fee": feeEstimate,
|
||||
"feeInWei": fee,
|
||||
"address": address,
|
||||
"recipientAmt": satoshiAmount,
|
||||
"recipientAmt": amount,
|
||||
"ethTx": tx,
|
||||
"chainId": (await client.getChainId()).toInt(),
|
||||
"nonce": tx.nonce,
|
||||
|
@ -238,9 +232,8 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
.sortByDerivationIndexDesc()
|
||||
.findFirst();
|
||||
|
||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||
final fee = estimateFee(feeRate, _gasLimit, coin.decimals);
|
||||
return Format.decimalAmountToSatoshis(Decimal.parse(fee.toString()), coin);
|
||||
Amount estimateFeeFor(int feeRate) {
|
||||
return estimateFee(feeRate, _gasLimit, coin.decimals);
|
||||
}
|
||||
|
||||
Future<FeeObject> get fees => EthereumAPI.getFees();
|
||||
|
@ -424,11 +417,22 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
|||
|
||||
final newBalance = TokenBalance(
|
||||
contractAddress: tokenContract.address,
|
||||
total: int.parse(_balance),
|
||||
spendable: int.parse(_balance),
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
decimalPlaces: tokenContract.decimals,
|
||||
total: Amount.fromDecimal(
|
||||
Decimal.parse(_balance),
|
||||
fractionDigits: tokenContract.decimals,
|
||||
),
|
||||
spendable: Amount.fromDecimal(
|
||||
Decimal.parse(_balance),
|
||||
fractionDigits: tokenContract.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: tokenContract.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: tokenContract.decimals,
|
||||
),
|
||||
);
|
||||
await updateCachedBalance(newBalance);
|
||||
notifyListeners();
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:stackwallet/db/isar/main_db.dart';
|
|||
import 'package:stackwallet/models/balance.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/balance_refreshed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
mixin CoinControlInterface {
|
||||
|
@ -35,24 +36,41 @@ mixin CoinControlInterface {
|
|||
final utxos = await _db.getUTXOs(_walletId).findAll();
|
||||
final currentChainHeight = await _getChainHeight();
|
||||
|
||||
int satoshiBalanceTotal = 0;
|
||||
int satoshiBalancePending = 0;
|
||||
int satoshiBalanceSpendable = 0;
|
||||
int satoshiBalanceBlocked = 0;
|
||||
Amount satoshiBalanceTotal = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _coin.decimals,
|
||||
);
|
||||
Amount satoshiBalancePending = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _coin.decimals,
|
||||
);
|
||||
Amount satoshiBalanceSpendable = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _coin.decimals,
|
||||
);
|
||||
Amount satoshiBalanceBlocked = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _coin.decimals,
|
||||
);
|
||||
|
||||
for (final utxo in utxos) {
|
||||
satoshiBalanceTotal += utxo.value;
|
||||
final utxoAmount = Amount(
|
||||
rawValue: BigInt.from(utxo.value),
|
||||
fractionDigits: _coin.decimals,
|
||||
);
|
||||
|
||||
satoshiBalanceTotal = satoshiBalanceTotal + utxoAmount;
|
||||
|
||||
if (utxo.isBlocked) {
|
||||
satoshiBalanceBlocked += utxo.value;
|
||||
satoshiBalanceBlocked = satoshiBalanceBlocked + utxoAmount;
|
||||
} else {
|
||||
if (utxo.isConfirmed(
|
||||
currentChainHeight,
|
||||
_coin.requiredConfirmations,
|
||||
)) {
|
||||
satoshiBalanceSpendable += utxo.value;
|
||||
satoshiBalanceSpendable + satoshiBalanceSpendable + utxoAmount;
|
||||
} else {
|
||||
satoshiBalancePending += utxo.value;
|
||||
satoshiBalancePending = satoshiBalancePending + utxoAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:stackwallet/models/isar/models/isar_models.dart';
|
|||
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
mixin ElectrumXParsing {
|
||||
|
@ -33,12 +32,27 @@ mixin ElectrumXParsing {
|
|||
Set<String> inputAddresses = {};
|
||||
Set<String> outputAddresses = {};
|
||||
|
||||
int totalInputValue = 0;
|
||||
int totalOutputValue = 0;
|
||||
Amount totalInputValue = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount totalOutputValue = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
int amountSentFromWallet = 0;
|
||||
int amountReceivedInWallet = 0;
|
||||
int changeAmount = 0;
|
||||
Amount amountSentFromWallet = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount amountReceivedInWallet = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
Amount changeAmount = Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// parse inputs
|
||||
for (final input in txData["vin"] as List) {
|
||||
|
@ -55,9 +69,9 @@ mixin ElectrumXParsing {
|
|||
// check matching output
|
||||
if (prevOut == output["n"]) {
|
||||
// get value
|
||||
final value = Format.decimalAmountToSatoshis(
|
||||
final value = Amount.fromDecimal(
|
||||
Decimal.parse(output["value"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// add value to total
|
||||
|
@ -83,9 +97,9 @@ mixin ElectrumXParsing {
|
|||
// parse outputs
|
||||
for (final output in txData["vout"] as List) {
|
||||
// get value
|
||||
final value = Format.decimalAmountToSatoshis(
|
||||
final value = Amount.fromDecimal(
|
||||
Decimal.parse(output["value"].toString()),
|
||||
coin,
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
|
||||
// add value to total
|
||||
|
@ -121,7 +135,7 @@ mixin ElectrumXParsing {
|
|||
Address transactionAddress = txData["address"] as Address;
|
||||
|
||||
TransactionType type;
|
||||
int amount;
|
||||
Amount amount;
|
||||
if (mySentFromAddresses.isNotEmpty && myReceivedOnAddresses.isNotEmpty) {
|
||||
// tx is sent to self
|
||||
type = TransactionType.sentToSelf;
|
||||
|
@ -189,10 +203,10 @@ mixin ElectrumXParsing {
|
|||
json["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||
json['scriptPubKey']?['type'] as String? ??
|
||||
"",
|
||||
value: Format.decimalAmountToSatoshis(
|
||||
value: Amount.fromDecimal(
|
||||
Decimal.parse(json["value"].toString()),
|
||||
coin,
|
||||
),
|
||||
fractionDigits: coin.decimals,
|
||||
).raw.toInt(),
|
||||
);
|
||||
outs.add(output);
|
||||
}
|
||||
|
@ -220,12 +234,10 @@ mixin ElectrumXParsing {
|
|||
(DateTime.now().millisecondsSinceEpoch ~/ 1000),
|
||||
type: type,
|
||||
subType: txSubType,
|
||||
amount: amount,
|
||||
amountString: Amount(
|
||||
rawValue: BigInt.from(amount),
|
||||
fractionDigits: coin.decimals,
|
||||
).toJsonString(),
|
||||
fee: fee,
|
||||
// amount may overflow. Deprecated. Use amountString
|
||||
amount: amount.raw.toInt(),
|
||||
amountString: amount.toJsonString(),
|
||||
fee: fee.raw.toInt(),
|
||||
height: txData["height"] as int?,
|
||||
isCancelled: false,
|
||||
isLelantus: false,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:stackwallet/db/hive/db.dart';
|
||||
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
|
||||
import 'package:stackwallet/models/token_balance.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
|
||||
abstract class TokenCacheKeys {
|
||||
static String tokenBalance(String contractAddress) {
|
||||
|
@ -26,15 +27,27 @@ mixin EthTokenCache {
|
|||
if (jsonString == null) {
|
||||
return TokenBalance(
|
||||
contractAddress: _token.address,
|
||||
decimalPlaces: _token.decimals,
|
||||
total: 0,
|
||||
spendable: 0,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _token.decimals,
|
||||
),
|
||||
spendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _token.decimals,
|
||||
),
|
||||
blockedTotal: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _token.decimals,
|
||||
),
|
||||
pendingSpendable: Amount(
|
||||
rawValue: BigInt.zero,
|
||||
fractionDigits: _token.decimals,
|
||||
),
|
||||
);
|
||||
}
|
||||
return TokenBalance.fromJson(
|
||||
jsonString,
|
||||
_token.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dar
|
|||
import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/models/signing_data.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/bip32_utils.dart';
|
||||
import 'package:stackwallet/utilities/bip47_utils.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -52,7 +53,7 @@ mixin PaynymWalletInterface {
|
|||
}) _estimateTxFee;
|
||||
late final Future<Map<String, dynamic>> Function({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) _prepareSend;
|
||||
late final Future<int> Function({
|
||||
|
@ -93,7 +94,7 @@ mixin PaynymWalletInterface {
|
|||
estimateTxFee,
|
||||
required Future<Map<String, dynamic>> Function({
|
||||
required String address,
|
||||
required int satoshiAmount,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
})
|
||||
prepareSend,
|
||||
|
@ -307,10 +308,11 @@ mixin PaynymWalletInterface {
|
|||
return Format.uint8listToString(bytes);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> preparePaymentCodeSend(
|
||||
{required PaymentCode paymentCode,
|
||||
required int satoshiAmount,
|
||||
Map<String, dynamic>? args}) async {
|
||||
Future<Map<String, dynamic>> preparePaymentCodeSend({
|
||||
required PaymentCode paymentCode,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
if (!(await hasConnected(paymentCode.toString()))) {
|
||||
throw PaynymSendException(
|
||||
"No notification transaction sent to $paymentCode");
|
||||
|
@ -326,7 +328,7 @@ mixin PaynymWalletInterface {
|
|||
|
||||
return _prepareSend(
|
||||
address: sendToAddress.value,
|
||||
satoshiAmount: satoshiAmount,
|
||||
amount: amount,
|
||||
args: args,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:stackwallet/db/hive/db.dart';
|
||||
import 'package:stackwallet/models/balance.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
mixin WalletCache {
|
||||
|
@ -70,10 +71,13 @@ mixin WalletCache {
|
|||
if (jsonString == null) {
|
||||
return Balance(
|
||||
coin: _coin,
|
||||
total: 0,
|
||||
spendable: 0,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
spendable:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
blockedTotal:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
pendingSpendable:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
);
|
||||
}
|
||||
return Balance.fromJson(jsonString, _coin);
|
||||
|
@ -96,10 +100,13 @@ mixin WalletCache {
|
|||
if (jsonString == null) {
|
||||
return Balance(
|
||||
coin: _coin,
|
||||
total: 0,
|
||||
spendable: 0,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: 0,
|
||||
total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
spendable:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
blockedTotal:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
pendingSpendable:
|
||||
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
|
||||
);
|
||||
}
|
||||
return Balance.fromJson(jsonString, _coin);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:intl/number_symbols.dart';
|
||||
import 'package:intl/number_symbols_data.dart';
|
||||
|
||||
final _ten = BigInt.from(10);
|
||||
|
||||
|
@ -60,6 +62,25 @@ class Amount {
|
|||
return jsonEncode(toMap());
|
||||
}
|
||||
|
||||
String localizedStringAsFixed({
|
||||
required String locale,
|
||||
int? decimalPlaces,
|
||||
}) {
|
||||
decimalPlaces ??= fractionDigits;
|
||||
assert(decimalPlaces >= 0);
|
||||
|
||||
final String separator =
|
||||
(numberFormatSymbols[locale] as NumberSymbols?)?.DECIMAL_SEP ??
|
||||
(numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?)
|
||||
?.DECIMAL_SEP ??
|
||||
".";
|
||||
|
||||
final intValue = decimal.shift(fractionDigits).toBigInt();
|
||||
final fraction = (raw - intValue).toDecimal();
|
||||
|
||||
return "$intValue$separator${fraction.toStringAsFixed(decimalPlaces).substring(2)}";
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// ======= Deserialization ===================================================
|
||||
|
||||
|
@ -132,3 +153,34 @@ class Amount {
|
|||
@override
|
||||
int get hashCode => Object.hashAll([raw, fractionDigits]);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// =============================================================================
|
||||
// ======= Extensions ==========================================================
|
||||
|
||||
extension DecimalAmountExt on Decimal {
|
||||
Amount toAmount({required int fractionDigits}) {
|
||||
return Amount.fromDecimal(
|
||||
this,
|
||||
fractionDigits: fractionDigits,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension DoubleAmountExt on double {
|
||||
Amount toAmount({required int fractionDigits}) {
|
||||
return Amount.fromDouble(
|
||||
this,
|
||||
fractionDigits: fractionDigits,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension IntAmountExtension on int {
|
||||
Amount toAmount({required int fractionDigits}) {
|
||||
return Amount(
|
||||
rawValue: BigInt.from(this),
|
||||
fractionDigits: fractionDigits,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import "package:hex/hex.dart";
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
import 'amount.dart';
|
||||
|
||||
class GasTracker {
|
||||
final Decimal average;
|
||||
final Decimal fast;
|
||||
|
@ -62,17 +64,12 @@ String getPrivateKey(String mnemonic, String mnemonicPassphrase) {
|
|||
return HEX.encode(addressAtIndex.privateKey as List<int>);
|
||||
}
|
||||
|
||||
double estimateFee(int feeRate, int gasLimit, int decimals) {
|
||||
Amount estimateFee(int feeRate, int gasLimit, int decimals) {
|
||||
final gweiAmount = feeRate / (pow(10, 9));
|
||||
final fee = gasLimit * gweiAmount;
|
||||
|
||||
//Convert gwei to ETH
|
||||
final feeInWei = fee * (pow(10, 9));
|
||||
final ethAmount = feeInWei / (pow(10, decimals));
|
||||
return ethAmount;
|
||||
}
|
||||
|
||||
BigInt amountToBigInt(num amount, int decimal) {
|
||||
final amountToSendinDecimal = amount * (pow(10, decimal));
|
||||
return BigInt.from(amountToSendinDecimal);
|
||||
return Amount.fromDouble(ethAmount, fractionDigits: decimals);
|
||||
}
|
||||
|
|
|
@ -1,48 +1,43 @@
|
|||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:intl/number_symbols.dart';
|
||||
import 'package:intl/number_symbols_data.dart' show numberFormatSymbols;
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
abstract class Format {
|
||||
static String shorten(String value, int beginCount, int endCount) {
|
||||
return "${value.substring(0, beginCount)}...${value.substring(value.length - endCount)}";
|
||||
}
|
||||
|
||||
static Decimal satoshisToAmount(int sats, {required Coin coin}) {
|
||||
return (Decimal.fromInt(sats) /
|
||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: Constants.decimalPlacesForCoin(coin));
|
||||
}
|
||||
|
||||
static Decimal satoshisToEthTokenAmount(int sats, int decimalPlaces) {
|
||||
return (Decimal.fromInt(sats) /
|
||||
Decimal.fromInt(pow(10, decimalPlaces).toInt()))
|
||||
.toDecimal(scaleOnInfinitePrecision: decimalPlaces);
|
||||
}
|
||||
|
||||
///
|
||||
static String satoshiAmountToPrettyString(
|
||||
int sats, String locale, Coin coin) {
|
||||
final amount = satoshisToAmount(sats, coin: coin);
|
||||
return localizedStringAsFixed(
|
||||
value: amount,
|
||||
locale: locale,
|
||||
decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
);
|
||||
}
|
||||
|
||||
static int decimalAmountToSatoshis(Decimal amount, Coin coin) {
|
||||
final value = (Decimal.fromInt(Constants.satsPerCoin(coin)) * amount)
|
||||
.floor()
|
||||
.toBigInt();
|
||||
return value.toInt();
|
||||
}
|
||||
// static Decimal satoshisToAmount(int sats, {required Coin coin}) {
|
||||
// return (Decimal.fromInt(sats) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(
|
||||
// scaleOnInfinitePrecision: Constants.decimalPlacesForCoin(coin));
|
||||
// }
|
||||
//
|
||||
// static Decimal satoshisToEthTokenAmount(int sats, int decimalPlaces) {
|
||||
// return (Decimal.fromInt(sats) /
|
||||
// Decimal.fromInt(pow(10, decimalPlaces).toInt()))
|
||||
// .toDecimal(scaleOnInfinitePrecision: decimalPlaces);
|
||||
// }
|
||||
//
|
||||
// ///
|
||||
// static String satoshiAmountToPrettyString(
|
||||
// int sats, String locale, Coin coin) {
|
||||
// final amount = satoshisToAmount(sats, coin: coin);
|
||||
// return localizedStringAsFixed(
|
||||
// value: amount,
|
||||
// locale: locale,
|
||||
// decimalPlaces: Constants.decimalPlacesForCoin(coin),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// static int decimalAmountToSatoshis(Decimal amount, Coin coin) {
|
||||
// final value = (Decimal.fromInt(Constants.satsPerCoin(coin)) * amount)
|
||||
// .floor()
|
||||
// .toBigInt();
|
||||
// return value.toInt();
|
||||
// }
|
||||
|
||||
// format date string from unix timestamp
|
||||
static String extractDateFrom(int timestamp, {bool localized = true}) {
|
||||
|
@ -57,26 +52,26 @@ abstract class Format {
|
|||
return "${date.day} ${Constants.monthMapShort[date.month]} ${date.year}, ${date.hour}:$minutes";
|
||||
}
|
||||
|
||||
static String localizedStringAsFixed({
|
||||
required Decimal value,
|
||||
required String locale,
|
||||
int decimalPlaces = 0,
|
||||
}) {
|
||||
assert(decimalPlaces >= 0);
|
||||
|
||||
final String separator =
|
||||
(numberFormatSymbols[locale] as NumberSymbols?)?.DECIMAL_SEP ??
|
||||
(numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?)
|
||||
?.DECIMAL_SEP ??
|
||||
".";
|
||||
|
||||
final intValue = value.truncate();
|
||||
final fraction = value - intValue;
|
||||
|
||||
return intValue.toStringAsFixed(0) +
|
||||
separator +
|
||||
fraction.toStringAsFixed(decimalPlaces).substring(2);
|
||||
}
|
||||
// static String localizedStringAsFixed({
|
||||
// required Decimal value,
|
||||
// required String locale,
|
||||
// int decimalPlaces = 0,
|
||||
// }) {
|
||||
// assert(decimalPlaces >= 0);
|
||||
//
|
||||
// final String separator =
|
||||
// (numberFormatSymbols[locale] as NumberSymbols?)?.DECIMAL_SEP ??
|
||||
// (numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?)
|
||||
// ?.DECIMAL_SEP ??
|
||||
// ".";
|
||||
//
|
||||
// final intValue = value.truncate();
|
||||
// final fraction = value - intValue;
|
||||
//
|
||||
// return intValue.toStringAsFixed(0) +
|
||||
// separator +
|
||||
// fraction.toStringAsFixed(decimalPlaces).substring(2);
|
||||
// }
|
||||
|
||||
/// format date string as dd/mm/yy from DateTime object
|
||||
static String formatDate(DateTime date) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -104,12 +103,13 @@ class _ManagedFavoriteCardState extends ConsumerState<ManagedFavorite> {
|
|||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: manager.balance.getTotal(),
|
||||
"${manager.balance.total.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces: 8,
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
decimalPlaces: manager.coin.decimals,
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
|
@ -146,11 +146,13 @@ class _ManagedFavoriteCardState extends ConsumerState<ManagedFavorite> {
|
|||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: manager.balance.getTotal(),
|
||||
locale: ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces: 8,
|
||||
"${manager.balance.total.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider.select(
|
||||
(value) => value.locale,
|
||||
),
|
||||
),
|
||||
decimalPlaces: manager.coin.decimals,
|
||||
)} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
|||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
|
@ -239,10 +240,8 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
|||
final amount = _transaction.realAmount;
|
||||
|
||||
return Text(
|
||||
"$prefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal,
|
||||
"$prefix${amount.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: amount.fractionDigits,
|
||||
)} $unit",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
);
|
||||
|
@ -283,8 +282,10 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
|||
final amount = _transaction.realAmount;
|
||||
|
||||
return Text(
|
||||
"$prefix${Format.localizedStringAsFixed(
|
||||
value: amount.decimal * price,
|
||||
"$prefix${Amount.fromDecimal(
|
||||
amount.decimal * price,
|
||||
fractionDigits: 2,
|
||||
).localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: 2,
|
||||
)} $baseCurrency",
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -33,27 +32,27 @@ class WalletInfoRowBalance extends ConsumerWidget {
|
|||
),
|
||||
);
|
||||
|
||||
Decimal balance;
|
||||
Amount totalBalance;
|
||||
int decimals;
|
||||
String unit;
|
||||
if (contractAddress == null) {
|
||||
balance = manager.balance.getTotal();
|
||||
totalBalance = manager.balance.total;
|
||||
if (manager.coin == Coin.firo || manager.coin == Coin.firoTestNet) {
|
||||
balance += (manager.wallet as FiroWallet).balancePrivate.getTotal();
|
||||
totalBalance =
|
||||
totalBalance + (manager.wallet as FiroWallet).balancePrivate.total;
|
||||
}
|
||||
unit = manager.coin.ticker;
|
||||
decimals = manager.coin.decimals;
|
||||
} else {
|
||||
final ethWallet = manager.wallet as EthereumWallet;
|
||||
final contract = MainDB.instance.getEthContractSync(contractAddress!)!;
|
||||
balance = ethWallet.getCachedTokenBalance(contract).getTotal();
|
||||
totalBalance = ethWallet.getCachedTokenBalance(contract).total;
|
||||
unit = contract.symbol;
|
||||
decimals = contract.decimals;
|
||||
}
|
||||
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: balance,
|
||||
"${totalBalance.localizedStringAsFixed(
|
||||
locale: locale,
|
||||
decimalPlaces: decimals,
|
||||
)} $unit",
|
||||
|
|
|
@ -1215,7 +1215,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1224,7 +1224,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -1913,7 +1913,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> preparePaymentCodeSend({
|
||||
required _i18.PaymentCode? paymentCode,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1922,7 +1922,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#paymentCode: paymentCode,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -2903,7 +2903,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2912,7 +2912,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -3215,7 +3215,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i19.CoinServiceAPI {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -3224,7 +3224,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i19.CoinServiceAPI {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -417,7 +417,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
@override
|
||||
_i8.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -426,7 +426,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -378,7 +378,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -387,7 +387,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -376,7 +376,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -385,7 +385,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -693,7 +693,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -702,7 +702,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -480,7 +480,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -489,7 +489,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -480,7 +480,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -489,7 +489,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -480,7 +480,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -489,7 +489,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -478,7 +478,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -487,7 +487,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -693,7 +693,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -702,7 +702,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -534,7 +534,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
@override
|
||||
_i8.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -543,7 +543,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -462,7 +462,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
@override
|
||||
_i8.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -471,7 +471,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -462,7 +462,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
@override
|
||||
_i8.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -471,7 +471,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -478,7 +478,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -487,7 +487,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -735,7 +735,7 @@ class MockManager extends _i1.Mock implements _i15.Manager {
|
|||
@override
|
||||
_i8.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -744,7 +744,7 @@ class MockManager extends _i1.Mock implements _i15.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -478,7 +478,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
@override
|
||||
_i6.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -487,7 +487,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -249,7 +249,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -258,7 +258,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -248,7 +248,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -257,7 +257,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -247,7 +247,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -256,7 +256,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -289,7 +289,7 @@ class MockManager extends _i1.Mock implements _i8.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -298,7 +298,7 @@ class MockManager extends _i1.Mock implements _i8.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -249,7 +249,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
@override
|
||||
_i7.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -258,7 +258,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -103,7 +103,7 @@ class FakeCoinServiceAPI extends CoinServiceAPI {
|
|||
@override
|
||||
Future<Map<String, dynamic>> prepareSend(
|
||||
{required String address,
|
||||
required int satoshiAmount,
|
||||
required int amount,
|
||||
Map<String, dynamic>? args}) {
|
||||
// TODO: implement prepareSend
|
||||
throw UnimplementedError();
|
||||
|
|
|
@ -392,7 +392,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
@override
|
||||
_i10.Future<Map<String, dynamic>> prepareSendPublic({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -401,7 +401,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -421,7 +421,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
@override
|
||||
_i10.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -430,7 +430,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1007,7 +1007,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1016,7 +1016,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -1704,7 +1704,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> preparePaymentCodeSend({
|
||||
required _i17.PaymentCode? paymentCode,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1713,7 +1713,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#paymentCode: paymentCode,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -2477,7 +2477,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2486,7 +2486,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -2789,7 +2789,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i19.CoinServiceAPI {
|
|||
@override
|
||||
_i22.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2798,7 +2798,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i19.CoinServiceAPI {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
|
@ -994,7 +994,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
@override
|
||||
_i21.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1003,7 +1003,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -1691,7 +1691,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
@override
|
||||
_i21.Future<Map<String, dynamic>> preparePaymentCodeSend({
|
||||
required _i17.PaymentCode? paymentCode,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1700,7 +1700,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
[],
|
||||
{
|
||||
#paymentCode: paymentCode,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -2202,7 +2202,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
@override
|
||||
_i21.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2211,7 +2211,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
@ -2514,7 +2514,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i18.CoinServiceAPI {
|
|||
@override
|
||||
_i21.Future<Map<String, dynamic>> prepareSend({
|
||||
required String? address,
|
||||
required int? satoshiAmount,
|
||||
required int? amount,
|
||||
Map<String, dynamic>? args,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2523,7 +2523,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i18.CoinServiceAPI {
|
|||
[],
|
||||
{
|
||||
#address: address,
|
||||
#satoshiAmount: satoshiAmount,
|
||||
#satoshiAmount: amount,
|
||||
#args: args,
|
||||
},
|
||||
),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue