mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
commit
7c4840fb24
11 changed files with 306 additions and 622 deletions
|
@ -359,10 +359,16 @@ class _ConfirmChangeNowSendViewState
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${(transactionInfo["fee"] as int).toAmountAsRaw(
|
"${(transactionInfo["fee"] is Amount ? transactionInfo["fee"] as Amount : (transactionInfo["fee"] as int).toAmountAsRaw(
|
||||||
fractionDigits: ref.watch(
|
fractionDigits: ref.watch(
|
||||||
managerProvider
|
managerProvider
|
||||||
.select((value) => value.coin.decimals),
|
.select((value) => value.coin.decimals),
|
||||||
|
),
|
||||||
|
)).localizedStringAsFixed(
|
||||||
|
locale: ref.watch(
|
||||||
|
localeServiceChangeNotifierProvider.select(
|
||||||
|
(value) => value.locale,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)} ${ref.watch(
|
)} ${ref.watch(
|
||||||
managerProvider.select((value) => value.coin),
|
managerProvider.select((value) => value.coin),
|
||||||
|
@ -401,10 +407,12 @@ class _ConfirmChangeNowSendViewState
|
||||||
final coin = ref.watch(
|
final coin = ref.watch(
|
||||||
managerProvider.select((value) => value.coin),
|
managerProvider.select((value) => value.coin),
|
||||||
);
|
);
|
||||||
final fee =
|
final fee = transactionInfo["fee"] is Amount
|
||||||
(transactionInfo["fee"] as int).toAmountAsRaw(
|
? transactionInfo["fee"] as Amount
|
||||||
fractionDigits: coin.decimals,
|
: (transactionInfo["fee"] as int)
|
||||||
);
|
.toAmountAsRaw(
|
||||||
|
fractionDigits: coin.decimals,
|
||||||
|
);
|
||||||
final amount =
|
final amount =
|
||||||
transactionInfo["recipientAmt"] as Amount;
|
transactionInfo["recipientAmt"] as Amount;
|
||||||
final total = amount + fee;
|
final total = amount + fee;
|
||||||
|
@ -637,17 +645,17 @@ class _ConfirmChangeNowSendViewState
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${(transactionInfo["fee"] as int).toAmountAsRaw(fractionDigits: ref.watch(
|
"${(transactionInfo["fee"] is Amount ? transactionInfo["fee"] as Amount : (transactionInfo["fee"] as int).toAmountAsRaw(fractionDigits: ref.watch(
|
||||||
managerProvider.select(
|
managerProvider.select(
|
||||||
(value) => value.coin.decimals,
|
(value) => value.coin.decimals,
|
||||||
),
|
),
|
||||||
)).localizedStringAsFixed(
|
))).localizedStringAsFixed(
|
||||||
locale: ref.watch(
|
locale: ref.watch(
|
||||||
localeServiceChangeNotifierProvider.select(
|
localeServiceChangeNotifierProvider.select(
|
||||||
(value) => value.locale,
|
(value) => value.locale,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)} ${ref.watch(
|
)} ${ref.watch(
|
||||||
managerProvider.select((value) => value.coin),
|
managerProvider.select((value) => value.coin),
|
||||||
).ticker}",
|
).ticker}",
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
|
@ -733,10 +741,11 @@ class _ConfirmChangeNowSendViewState
|
||||||
final coin = ref.watch(
|
final coin = ref.watch(
|
||||||
managerProvider.select((value) => value.coin),
|
managerProvider.select((value) => value.coin),
|
||||||
);
|
);
|
||||||
final fee =
|
final fee = transactionInfo["fee"] is Amount
|
||||||
(transactionInfo["fee"] as int).toAmountAsRaw(
|
? transactionInfo["fee"] as Amount
|
||||||
fractionDigits: coin.decimals,
|
: (transactionInfo["fee"] as int).toAmountAsRaw(
|
||||||
);
|
fractionDigits: coin.decimals,
|
||||||
|
);
|
||||||
final amount =
|
final amount =
|
||||||
transactionInfo["recipientAmt"] as Amount;
|
transactionInfo["recipientAmt"] as Amount;
|
||||||
final total = amount + fee;
|
final total = amount + fee;
|
||||||
|
|
|
@ -427,18 +427,18 @@ class _ConfirmTransactionViewState
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${(transactionInfo["fee"] as int).toAmountAsRaw(
|
"${(transactionInfo["fee"] is Amount ? transactionInfo["fee"] as Amount : (transactionInfo["fee"] as int).toAmountAsRaw(
|
||||||
fractionDigits: ref.watch(
|
fractionDigits: ref.watch(
|
||||||
managerProvider.select(
|
managerProvider.select(
|
||||||
(value) => value.coin.decimals,
|
(value) => value.coin.decimals,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
).localizedStringAsFixed(
|
),
|
||||||
locale: ref.watch(
|
)).localizedStringAsFixed(
|
||||||
localeServiceChangeNotifierProvider
|
locale: ref.watch(
|
||||||
.select((value) => value.locale),
|
localeServiceChangeNotifierProvider
|
||||||
),
|
.select((value) => value.locale),
|
||||||
)} ${ref.watch(
|
),
|
||||||
|
)} ${ref.watch(
|
||||||
managerProvider.select((value) => value.coin),
|
managerProvider.select((value) => value.coin),
|
||||||
).ticker}",
|
).ticker}",
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
|
@ -552,10 +552,22 @@ class _ConfirmTransactionViewState
|
||||||
String fiatAmount = "N/A";
|
String fiatAmount = "N/A";
|
||||||
|
|
||||||
if (externalCalls) {
|
if (externalCalls) {
|
||||||
final price = ref
|
final price = widget.isTokenTx
|
||||||
.read(priceAnd24hChangeNotifierProvider)
|
? ref
|
||||||
.getPrice(coin)
|
.read(
|
||||||
.item1;
|
priceAnd24hChangeNotifierProvider)
|
||||||
|
.getTokenPrice(
|
||||||
|
ref
|
||||||
|
.read(tokenServiceProvider)!
|
||||||
|
.tokenContract
|
||||||
|
.address,
|
||||||
|
)
|
||||||
|
.item1
|
||||||
|
: ref
|
||||||
|
.read(
|
||||||
|
priceAnd24hChangeNotifierProvider)
|
||||||
|
.getPrice(coin)
|
||||||
|
.item1;
|
||||||
if (price > Decimal.zero) {
|
if (price > Decimal.zero) {
|
||||||
fiatAmount = (amount.decimal * price)
|
fiatAmount = (amount.decimal * price)
|
||||||
.toAmount(fractionDigits: 2)
|
.toAmount(fractionDigits: 2)
|
||||||
|
@ -678,10 +690,12 @@ class _ConfirmTransactionViewState
|
||||||
value.getManager(walletId)))
|
value.getManager(walletId)))
|
||||||
.coin;
|
.coin;
|
||||||
|
|
||||||
final fee = (transactionInfo["fee"] as int)
|
final fee = transactionInfo["fee"] is Amount
|
||||||
.toAmountAsRaw(
|
? transactionInfo["fee"] as Amount
|
||||||
fractionDigits: coin.decimals,
|
: (transactionInfo["fee"] as int)
|
||||||
);
|
.toAmountAsRaw(
|
||||||
|
fractionDigits: coin.decimals,
|
||||||
|
);
|
||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
"${fee.localizedStringAsFixed(
|
"${fee.localizedStringAsFixed(
|
||||||
|
@ -857,9 +871,11 @@ class _ConfirmTransactionViewState
|
||||||
.select((value) => value.getManager(walletId)))
|
.select((value) => value.getManager(walletId)))
|
||||||
.coin;
|
.coin;
|
||||||
|
|
||||||
final fee = (transactionInfo["fee"] as int).toAmountAsRaw(
|
final fee = transactionInfo["fee"] is Amount
|
||||||
fractionDigits: coin.decimals,
|
? transactionInfo["fee"] as Amount
|
||||||
);
|
: (transactionInfo["fee"] as int).toAmountAsRaw(
|
||||||
|
fractionDigits: coin.decimals,
|
||||||
|
);
|
||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
"${fee.localizedStringAsFixed(
|
"${fee.localizedStringAsFixed(
|
||||||
|
@ -879,56 +895,28 @@ class _ConfirmTransactionViewState
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 23 : 12,
|
height: isDesktop ? 23 : 12,
|
||||||
),
|
),
|
||||||
Padding(
|
if (!widget.isTokenTx)
|
||||||
padding: isDesktop
|
Padding(
|
||||||
? const EdgeInsets.symmetric(
|
|
||||||
horizontal: 32,
|
|
||||||
)
|
|
||||||
: const EdgeInsets.all(0),
|
|
||||||
child: RoundedContainer(
|
|
||||||
padding: isDesktop
|
padding: isDesktop
|
||||||
? const EdgeInsets.symmetric(
|
? const EdgeInsets.symmetric(
|
||||||
horizontal: 16,
|
horizontal: 32,
|
||||||
vertical: 18,
|
|
||||||
)
|
)
|
||||||
: const EdgeInsets.all(12),
|
: const EdgeInsets.all(0),
|
||||||
color: Theme.of(context)
|
child: RoundedContainer(
|
||||||
.extension<StackColors>()!
|
padding: isDesktop
|
||||||
.snackBarBackSuccess,
|
? const EdgeInsets.symmetric(
|
||||||
child: Row(
|
horizontal: 16,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
vertical: 18,
|
||||||
children: [
|
)
|
||||||
Text(
|
: const EdgeInsets.all(12),
|
||||||
isDesktop ? "Total amount to send" : "Total amount",
|
color: Theme.of(context)
|
||||||
style: isDesktop
|
.extension<StackColors>()!
|
||||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
.snackBarBackSuccess,
|
||||||
.copyWith(
|
child: Row(
|
||||||
color: Theme.of(context)
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
.extension<StackColors>()!
|
children: [
|
||||||
.textConfirmTotalAmount,
|
Text(
|
||||||
)
|
isDesktop ? "Total amount to send" : "Total amount",
|
||||||
: STextStyles.titleBold12(context).copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.textConfirmTotalAmount,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Builder(builder: (context) {
|
|
||||||
final coin = ref.watch(walletsChangeNotifierProvider
|
|
||||||
.select((value) => value.getManager(walletId).coin));
|
|
||||||
final fee = (transactionInfo["fee"] as int)
|
|
||||||
.toAmountAsRaw(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
|
style: isDesktop
|
||||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
|
@ -936,18 +924,51 @@ class _ConfirmTransactionViewState
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.textConfirmTotalAmount,
|
.textConfirmTotalAmount,
|
||||||
)
|
)
|
||||||
: STextStyles.itemSubtitle12(context).copyWith(
|
: STextStyles.titleBold12(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.textConfirmTotalAmount,
|
.textConfirmTotalAmount,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.right,
|
),
|
||||||
);
|
Builder(builder: (context) {
|
||||||
}),
|
final coin = ref.watch(
|
||||||
],
|
walletsChangeNotifierProvider.select(
|
||||||
|
(value) => value.getManager(walletId).coin));
|
||||||
|
final fee = transactionInfo["fee"] is Amount
|
||||||
|
? transactionInfo["fee"] as Amount
|
||||||
|
: (transactionInfo["fee"] as int)
|
||||||
|
.toAmountAsRaw(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,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 28 : 16,
|
height: isDesktop ? 28 : 16,
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:event_bus/event_bus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
||||||
import 'package:stackwallet/pages/token_view/sub_widgets/token_summary.dart';
|
import 'package:stackwallet/pages/token_view/sub_widgets/token_summary.dart';
|
||||||
import 'package:stackwallet/pages/token_view/sub_widgets/token_transaction_list_widget.dart';
|
import 'package:stackwallet/pages/token_view/sub_widgets/token_transaction_list_widget.dart';
|
||||||
import 'package:stackwallet/pages/token_view/token_view.dart';
|
import 'package:stackwallet/pages/token_view/token_view.dart';
|
||||||
|
@ -89,7 +90,10 @@ class _DesktopTokenViewState extends ConsumerState<DesktopTokenView> {
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.topNavIconPrimary,
|
.topNavIconPrimary,
|
||||||
),
|
),
|
||||||
onPressed: Navigator.of(context).pop,
|
onPressed: () {
|
||||||
|
ref.refresh(feeSheetSessionCacheProvider);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 15,
|
width: 15,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:stackwallet/models/models.dart';
|
import 'package:stackwallet/models/models.dart';
|
||||||
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
||||||
|
import 'package:stackwallet/pages/token_view/token_view.dart';
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
import 'package:stackwallet/providers/ui/fee_rate_type_state_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/providers/wallet/public_private_balance_state_provider.dart';
|
||||||
|
@ -22,9 +23,11 @@ class DesktopFeeDropDown extends ConsumerStatefulWidget {
|
||||||
const DesktopFeeDropDown({
|
const DesktopFeeDropDown({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
|
this.isToken = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
|
final bool isToken;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<DesktopFeeDropDown> createState() => _DesktopFeeDropDownState();
|
ConsumerState<DesktopFeeDropDown> createState() => _DesktopFeeDropDownState();
|
||||||
|
@ -52,66 +55,84 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
|
||||||
switch (feeRateType) {
|
switch (feeRateType) {
|
||||||
case FeeRateType.fast:
|
case FeeRateType.fast:
|
||||||
if (ref.read(feeSheetSessionCacheProvider).fast[amount] == null) {
|
if (ref.read(feeSheetSessionCacheProvider).fast[amount] == null) {
|
||||||
final manager =
|
if (widget.isToken == false) {
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
final manager =
|
||||||
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
if (coin == Coin.monero || coin == Coin.wownero) {
|
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||||
final fee = await manager.estimateFeeFor(
|
final fee = await manager.estimateFeeFor(
|
||||||
amount, MoneroTransactionPriority.fast.raw!);
|
amount, MoneroTransactionPriority.fast.raw!);
|
||||||
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
||||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||||
"Private") {
|
"Private") {
|
||||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||||
await (manager.wallet as FiroWallet)
|
await (manager.wallet as FiroWallet)
|
||||||
.estimateFeeForPublic(amount, feeRate);
|
.estimateFeeForPublic(amount, feeRate);
|
||||||
|
} else {
|
||||||
|
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
||||||
|
await manager.estimateFeeFor(amount, feeRate);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ref.read(feeSheetSessionCacheProvider).fast[amount] =
|
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||||
await manager.estimateFeeFor(amount, feeRate);
|
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||||
|
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
|
return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
|
||||||
|
|
||||||
case FeeRateType.average:
|
case FeeRateType.average:
|
||||||
if (ref.read(feeSheetSessionCacheProvider).average[amount] == null) {
|
if (ref.read(feeSheetSessionCacheProvider).average[amount] == null) {
|
||||||
final manager =
|
if (widget.isToken == false) {
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
final manager =
|
||||||
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
if (coin == Coin.monero || coin == Coin.wownero) {
|
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||||
final fee = await manager.estimateFeeFor(
|
final fee = await manager.estimateFeeFor(
|
||||||
amount, MoneroTransactionPriority.regular.raw!);
|
amount, MoneroTransactionPriority.regular.raw!);
|
||||||
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
||||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||||
"Private") {
|
"Private") {
|
||||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||||
await (manager.wallet as FiroWallet)
|
await (manager.wallet as FiroWallet)
|
||||||
.estimateFeeForPublic(amount, feeRate);
|
.estimateFeeForPublic(amount, feeRate);
|
||||||
|
} else {
|
||||||
|
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
||||||
|
await manager.estimateFeeFor(amount, feeRate);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ref.read(feeSheetSessionCacheProvider).average[amount] =
|
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||||
await manager.estimateFeeFor(amount, feeRate);
|
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||||
|
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ref.read(feeSheetSessionCacheProvider).average[amount]!;
|
return ref.read(feeSheetSessionCacheProvider).average[amount]!;
|
||||||
|
|
||||||
case FeeRateType.slow:
|
case FeeRateType.slow:
|
||||||
if (ref.read(feeSheetSessionCacheProvider).slow[amount] == null) {
|
if (ref.read(feeSheetSessionCacheProvider).slow[amount] == null) {
|
||||||
final manager =
|
if (widget.isToken == false) {
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
final manager =
|
||||||
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
if (coin == Coin.monero || coin == Coin.wownero) {
|
if (coin == Coin.monero || coin == Coin.wownero) {
|
||||||
final fee = await manager.estimateFeeFor(
|
final fee = await manager.estimateFeeFor(
|
||||||
amount, MoneroTransactionPriority.slow.raw!);
|
amount, MoneroTransactionPriority.slow.raw!);
|
||||||
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
||||||
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||||
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
ref.read(publicPrivateBalanceStateProvider.state).state !=
|
||||||
"Private") {
|
"Private") {
|
||||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||||
await (manager.wallet as FiroWallet)
|
await (manager.wallet as FiroWallet)
|
||||||
.estimateFeeForPublic(amount, feeRate);
|
.estimateFeeForPublic(amount, feeRate);
|
||||||
|
} else {
|
||||||
|
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
||||||
|
await manager.estimateFeeFor(amount, feeRate);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ref.read(feeSheetSessionCacheProvider).slow[amount] =
|
final tokenWallet = ref.read(tokenServiceProvider)!;
|
||||||
await manager.estimateFeeFor(amount, feeRate);
|
final fee = tokenWallet.estimateFeeFor(feeRate);
|
||||||
|
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
|
return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
|
||||||
|
@ -321,14 +342,16 @@ class FeeDropDownChild extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
if (feeObject != null)
|
if (feeObject != null)
|
||||||
Text(
|
Text(
|
||||||
estimatedTimeToBeIncludedInNextBlock(
|
manager.coin == Coin.ethereum
|
||||||
Constants.targetBlockTimeInSeconds(manager.coin),
|
? ""
|
||||||
feeRateType == FeeRateType.fast
|
: estimatedTimeToBeIncludedInNextBlock(
|
||||||
? feeObject!.numberOfBlocksFast
|
Constants.targetBlockTimeInSeconds(manager.coin),
|
||||||
: feeRateType == FeeRateType.slow
|
feeRateType == FeeRateType.fast
|
||||||
? feeObject!.numberOfBlocksSlow
|
? feeObject!.numberOfBlocksFast
|
||||||
: feeObject!.numberOfBlocksAverage,
|
: feeRateType == FeeRateType.slow
|
||||||
),
|
? feeObject!.numberOfBlocksSlow
|
||||||
|
: feeObject!.numberOfBlocksAverage,
|
||||||
|
),
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
|
|
|
@ -1412,7 +1412,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash)
|
if (coin != Coin.epicCash)
|
||||||
Text(
|
Text(
|
||||||
"Transaction fee (estimated)",
|
"Transaction fee (${coin == Coin.ethereum ? "max" : "estimated"})",
|
||||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
|
|
|
@ -71,12 +71,14 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
late TextEditingController sendToController;
|
late TextEditingController sendToController;
|
||||||
late TextEditingController cryptoAmountController;
|
late TextEditingController cryptoAmountController;
|
||||||
late TextEditingController baseAmountController;
|
late TextEditingController baseAmountController;
|
||||||
|
late TextEditingController nonceController;
|
||||||
|
|
||||||
late final SendViewAutoFillData? _data;
|
late final SendViewAutoFillData? _data;
|
||||||
|
|
||||||
final _addressFocusNode = FocusNode();
|
final _addressFocusNode = FocusNode();
|
||||||
final _cryptoFocus = FocusNode();
|
final _cryptoFocus = FocusNode();
|
||||||
final _baseFocus = FocusNode();
|
final _baseFocus = FocusNode();
|
||||||
|
final _nonceFocusNode = FocusNode();
|
||||||
|
|
||||||
String? _note;
|
String? _note;
|
||||||
|
|
||||||
|
@ -229,6 +231,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
amount: amount,
|
amount: amount,
|
||||||
args: {
|
args: {
|
||||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||||
|
"nonce": int.tryParse(nonceController.text),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -305,7 +308,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
right: 32,
|
right: 32,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: SelectableText(
|
||||||
e.toString(),
|
e.toString(),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||||
|
@ -370,8 +373,12 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
_cachedAmountToSend = _amountToSend;
|
_cachedAmountToSend = _amountToSend;
|
||||||
|
|
||||||
final price =
|
final price = ref
|
||||||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
.read(priceAnd24hChangeNotifierProvider)
|
||||||
|
.getTokenPrice(
|
||||||
|
ref.read(tokenServiceProvider)!.tokenContract.address,
|
||||||
|
)
|
||||||
|
.item1;
|
||||||
|
|
||||||
if (price > Decimal.zero) {
|
if (price > Decimal.zero) {
|
||||||
final String fiatAmountString = Amount.fromDecimal(
|
final String fiatAmountString = Amount.fromDecimal(
|
||||||
|
@ -512,8 +519,12 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
.toAmount(fractionDigits: 2)
|
.toAmount(fractionDigits: 2)
|
||||||
: Decimal.parse(baseAmountString).toAmount(fractionDigits: 2);
|
: Decimal.parse(baseAmountString).toAmount(fractionDigits: 2);
|
||||||
|
|
||||||
final Decimal _price =
|
final Decimal _price = ref
|
||||||
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
|
.read(priceAnd24hChangeNotifierProvider)
|
||||||
|
.getTokenPrice(
|
||||||
|
ref.read(tokenServiceProvider)!.tokenContract.address,
|
||||||
|
)
|
||||||
|
.item1;
|
||||||
|
|
||||||
if (_price == Decimal.zero) {
|
if (_price == Decimal.zero) {
|
||||||
_amountToSend = Decimal.zero.toAmount(fractionDigits: tokenDecimals);
|
_amountToSend = Decimal.zero.toAmount(fractionDigits: tokenDecimals);
|
||||||
|
@ -577,6 +588,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
sendToController = TextEditingController();
|
sendToController = TextEditingController();
|
||||||
cryptoAmountController = TextEditingController();
|
cryptoAmountController = TextEditingController();
|
||||||
baseAmountController = TextEditingController();
|
baseAmountController = TextEditingController();
|
||||||
|
nonceController = TextEditingController();
|
||||||
// feeController = TextEditingController();
|
// feeController = TextEditingController();
|
||||||
|
|
||||||
onCryptoAmountChanged = _cryptoAmountChanged;
|
onCryptoAmountChanged = _cryptoAmountChanged;
|
||||||
|
@ -621,11 +633,13 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
sendToController.dispose();
|
sendToController.dispose();
|
||||||
cryptoAmountController.dispose();
|
cryptoAmountController.dispose();
|
||||||
baseAmountController.dispose();
|
baseAmountController.dispose();
|
||||||
|
nonceController.dispose();
|
||||||
// feeController.dispose();
|
// feeController.dispose();
|
||||||
|
|
||||||
_addressFocusNode.dispose();
|
_addressFocusNode.dispose();
|
||||||
_cryptoFocus.dispose();
|
_cryptoFocus.dispose();
|
||||||
_baseFocus.dispose();
|
_baseFocus.dispose();
|
||||||
|
_nonceFocusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,7 +993,7 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Transaction fee (estimated)",
|
"Transaction fee (max)",
|
||||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
|
@ -990,9 +1004,59 @@ class _DesktopTokenSendState extends ConsumerState<DesktopTokenSend> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
// TODO mod this for token fees
|
|
||||||
DesktopFeeDropDown(
|
DesktopFeeDropDown(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
|
isToken: true,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Nonce",
|
||||||
|
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldActiveSearchIconRight,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
minLines: 1,
|
||||||
|
maxLines: 1,
|
||||||
|
key: const Key("sendViewNonceFieldKey"),
|
||||||
|
controller: nonceController,
|
||||||
|
readOnly: false,
|
||||||
|
autocorrect: false,
|
||||||
|
enableSuggestions: false,
|
||||||
|
keyboardType: const TextInputType.numberWithOptions(),
|
||||||
|
focusNode: _nonceFocusNode,
|
||||||
|
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldActiveText,
|
||||||
|
height: 1.8,
|
||||||
|
),
|
||||||
|
decoration: standardInputDecoration(
|
||||||
|
"Leave empty to auto select nonce",
|
||||||
|
_nonceFocusNode,
|
||||||
|
context,
|
||||||
|
desktopMed: true,
|
||||||
|
).copyWith(
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 11,
|
||||||
|
bottom: 12,
|
||||||
|
right: 5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 36,
|
height: 36,
|
||||||
|
|
|
@ -923,7 +923,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
||||||
// precision may be lost here hence the following amountString
|
// precision may be lost here hence the following amountString
|
||||||
amount: (txData["recipientAmt"] as Amount).raw.toInt(),
|
amount: (txData["recipientAmt"] as Amount).raw.toInt(),
|
||||||
amountString: (txData["recipientAmt"] as Amount).toJsonString(),
|
amountString: (txData["recipientAmt"] as Amount).toJsonString(),
|
||||||
fee: txData["fee"] as int,
|
fee: (txData["fee"] as Amount).raw.toInt(),
|
||||||
height: null,
|
height: null,
|
||||||
isCancelled: false,
|
isCancelled: false,
|
||||||
isLelantus: false,
|
isLelantus: false,
|
||||||
|
|
|
@ -449,7 +449,7 @@ abstract class EthereumAPI {
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
final uri = Uri.parse(
|
final uri = Uri.parse(
|
||||||
"$stackBaseServer/state?addrs=$address&parts=nonce",
|
"$stackBaseServer/state?addrs=$address&parts=all",
|
||||||
);
|
);
|
||||||
final response = await get(uri);
|
final response = await get(uri);
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ abstract class EthereumAPI {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw EthApiException(
|
throw EthApiException(
|
||||||
"getWalletTokenBalance($address) failed with status code: "
|
"getAddressNonce($address) failed with status code: "
|
||||||
"${response.statusCode}",
|
"${response.statusCode}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -480,7 +480,7 @@ abstract class EthereumAPI {
|
||||||
);
|
);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"getWalletTokenBalance(): $e\n$s",
|
"getAddressNonce(): $e\n$s",
|
||||||
level: LogLevel.Error,
|
level: LogLevel.Error,
|
||||||
);
|
);
|
||||||
return EthereumResponse(
|
return EthereumResponse(
|
||||||
|
@ -501,12 +501,19 @@ abstract class EthereumAPI {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final json = jsonDecode(response.body) as Map;
|
final json = jsonDecode(response.body) as Map;
|
||||||
if (json["success"] == true) {
|
if (json["success"] == true) {
|
||||||
return EthereumResponse(
|
try {
|
||||||
GasTracker.fromJson(
|
return EthereumResponse(
|
||||||
Map<String, dynamic>.from(json["result"] as Map),
|
GasTracker.fromJson(
|
||||||
),
|
Map<String, dynamic>.from(json["result"]["result"] as Map),
|
||||||
null,
|
),
|
||||||
);
|
null,
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
throw EthApiException(
|
||||||
|
"getGasOracle() failed with response: "
|
||||||
|
"${response.body}",
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw EthApiException(
|
throw EthApiException(
|
||||||
"getGasOracle() failed with response: "
|
"getGasOracle() failed with response: "
|
||||||
|
|
|
@ -90,30 +90,10 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
||||||
final myAddress = await currentReceivingAddress;
|
final myAddress = await currentReceivingAddress;
|
||||||
final myWeb3Address = web3dart.EthereumAddress.fromHex(myAddress);
|
final myWeb3Address = web3dart.EthereumAddress.fromHex(myAddress);
|
||||||
|
|
||||||
final est = await client.estimateGas(
|
|
||||||
sender: myWeb3Address,
|
|
||||||
to: web3dart.EthereumAddress.fromHex(address),
|
|
||||||
data: _sendFunction
|
|
||||||
.encodeCall([web3dart.EthereumAddress.fromHex(address), amount.raw]),
|
|
||||||
gasPrice: web3dart.EtherAmount.fromUnitAndValue(
|
|
||||||
web3dart.EtherUnit.wei,
|
|
||||||
fee,
|
|
||||||
),
|
|
||||||
amountOfGas: BigInt.from(_gasLimit),
|
|
||||||
);
|
|
||||||
|
|
||||||
final nonce = args?["nonce"] as int? ??
|
final nonce = args?["nonce"] as int? ??
|
||||||
await client.getTransactionCount(myWeb3Address,
|
await client.getTransactionCount(myWeb3Address,
|
||||||
atBlock: const web3dart.BlockNum.pending());
|
atBlock: const web3dart.BlockNum.pending());
|
||||||
|
|
||||||
final nResponse = await EthereumAPI.getAddressNonce(address: myAddress);
|
|
||||||
print("==============================================================");
|
|
||||||
print("TOKEN client.estimateGas: $est");
|
|
||||||
print("TOKEN estimateFeeFor : $feeEstimate");
|
|
||||||
print("TOKEN nonce custom response: $nResponse");
|
|
||||||
print("TOKEN actual nonce : $nonce");
|
|
||||||
print("==============================================================");
|
|
||||||
|
|
||||||
final tx = web3dart.Transaction.callContract(
|
final tx = web3dart.Transaction.callContract(
|
||||||
contract: _deployedContract,
|
contract: _deployedContract,
|
||||||
function: _sendFunction,
|
function: _sendFunction,
|
||||||
|
@ -179,7 +159,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
|
||||||
// precision may be lost here hence the following amountString
|
// precision may be lost here hence the following amountString
|
||||||
amount: (txData["recipientAmt"] as Amount).raw.toInt(),
|
amount: (txData["recipientAmt"] as Amount).raw.toInt(),
|
||||||
amountString: (txData["recipientAmt"] as Amount).toJsonString(),
|
amountString: (txData["recipientAmt"] as Amount).toJsonString(),
|
||||||
fee: txData["fee"] as int,
|
fee: (txData["fee"] as Amount).raw.toInt(),
|
||||||
height: null,
|
height: null,
|
||||||
isCancelled: false,
|
isCancelled: false,
|
||||||
isLelantus: false,
|
isLelantus: false,
|
||||||
|
|
|
@ -1,425 +0,0 @@
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stackwallet/db/hive/db.dart';
|
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|
||||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
|
||||||
|
|
||||||
class TokenInfo {
|
|
||||||
final Coin coin;
|
|
||||||
final String walletId;
|
|
||||||
final String contractAddress;
|
|
||||||
|
|
||||||
const TokenInfo(
|
|
||||||
{required this.coin,
|
|
||||||
required this.walletId,
|
|
||||||
required this.contractAddress});
|
|
||||||
|
|
||||||
factory TokenInfo.fromJson(Map<String, dynamic> jsonObject) {
|
|
||||||
return TokenInfo(
|
|
||||||
coin: Coin.values.byName(jsonObject["coin"] as String),
|
|
||||||
walletId: jsonObject["id"] as String,
|
|
||||||
contractAddress: jsonObject["contractAddress"] as String,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> toMap() {
|
|
||||||
return {
|
|
||||||
"contractAddress": contractAddress,
|
|
||||||
"walletId": walletId,
|
|
||||||
"coin": coin.name,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
String toJsonString() {
|
|
||||||
return jsonEncode(toMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return "TokenInfo: ${toJsonString()}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TokensService extends ChangeNotifier {
|
|
||||||
late final SecureStorageInterface _secureStore;
|
|
||||||
|
|
||||||
// Future<Map<String, TokenInfo>>? _walletNames;
|
|
||||||
// Future<Map<String, TokenInfo>> get walletNames =>
|
|
||||||
// _walletNames ??= _fetchWalletNames();
|
|
||||||
|
|
||||||
TokensService({
|
|
||||||
required SecureStorageInterface secureStorageInterface,
|
|
||||||
}) {
|
|
||||||
_secureStore = secureStorageInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future<Coin> getWalletCryptoCurrency({required String walletName}) async {
|
|
||||||
// final id = await getWalletId(walletName);
|
|
||||||
// final currency = DB.instance.get<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: "${id}_cryptoCurrency");
|
|
||||||
// return Coin.values.byName(currency as String);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Future<bool> renameWallet({
|
|
||||||
// required String from,
|
|
||||||
// required String to,
|
|
||||||
// required bool shouldNotifyListeners,
|
|
||||||
// }) async {
|
|
||||||
// if (from == to) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final walletInfo = DB.instance
|
|
||||||
// .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map;
|
|
||||||
//
|
|
||||||
// final info = walletInfo.values.firstWhere(
|
|
||||||
// (element) => element['name'] == from,
|
|
||||||
// orElse: () => <String, String>{}) as Map;
|
|
||||||
//
|
|
||||||
// if (info.isEmpty) {
|
|
||||||
// // tried to rename a non existing wallet
|
|
||||||
// Logging.instance
|
|
||||||
// .log("Tried to rename a non existing wallet!", level: LogLevel.Error);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (from != to &&
|
|
||||||
// (walletInfo.values.firstWhere((element) => element['name'] == to,
|
|
||||||
// orElse: () => <String, String>{}) as Map)
|
|
||||||
// .isNotEmpty) {
|
|
||||||
// // name already exists
|
|
||||||
// Logging.instance.log("wallet with name \"$to\" already exists!",
|
|
||||||
// level: LogLevel.Error);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// info["name"] = to;
|
|
||||||
// walletInfo[info['id']] = info;
|
|
||||||
//
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: 'names', value: walletInfo);
|
|
||||||
// await refreshWallets(shouldNotifyListeners);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Future<Map<String, WalletInfo>> _fetchWalletNames() async {
|
|
||||||
// final names = DB.instance
|
|
||||||
// .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
|
||||||
// if (names == null) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "Fetched wallet 'names' returned null. Setting initializing 'names'",
|
|
||||||
// level: LogLevel.Info);
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: 'names',
|
|
||||||
// value: <String, dynamic>{});
|
|
||||||
// return {};
|
|
||||||
// }
|
|
||||||
// Logging.instance.log("Fetched wallet names: $names", level: LogLevel.Info);
|
|
||||||
// final mapped = Map<String, dynamic>.from(names);
|
|
||||||
// mapped.removeWhere((name, dyn) {
|
|
||||||
// final jsonObject = Map<String, dynamic>.from(dyn as Map);
|
|
||||||
// try {
|
|
||||||
// Coin.values.byName(jsonObject["coin"] as String);
|
|
||||||
// return false;
|
|
||||||
// } catch (e, s) {
|
|
||||||
// Logging.instance.log("Error, ${jsonObject["coin"]} does not exist",
|
|
||||||
// level: LogLevel.Error);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// return mapped.map((name, dyn) => MapEntry(
|
|
||||||
// name, WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map))));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Future<void> addExistingStackWallet({
|
|
||||||
// required String name,
|
|
||||||
// required String walletId,
|
|
||||||
// required Coin coin,
|
|
||||||
// required bool shouldNotifyListeners,
|
|
||||||
// }) async {
|
|
||||||
// final _names = DB.instance
|
|
||||||
// .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> names;
|
|
||||||
// if (_names == null) {
|
|
||||||
// names = {};
|
|
||||||
// } else {
|
|
||||||
// names = Map<String, dynamic>.from(_names);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (names.keys.contains(walletId)) {
|
|
||||||
// throw Exception("Wallet with walletId \"$walletId\" already exists!");
|
|
||||||
// }
|
|
||||||
// if (names.values.where((element) => element['name'] == name).isNotEmpty) {
|
|
||||||
// throw Exception("Wallet with name \"$name\" already exists!");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// names[walletId] = {
|
|
||||||
// "id": walletId,
|
|
||||||
// "coin": coin.name,
|
|
||||||
// "name": name,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: 'names', value: names);
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_cryptoCurrency",
|
|
||||||
// value: coin.name);
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_mnemonicHasBeenVerified",
|
|
||||||
// value: false);
|
|
||||||
// await DB.instance.addWalletBox(walletId: walletId);
|
|
||||||
// await refreshWallets(shouldNotifyListeners);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// returns the new walletId if successful, otherwise null
|
|
||||||
// Future<String?> addNewWallet({
|
|
||||||
// required String name,
|
|
||||||
// required Coin coin,
|
|
||||||
// required bool shouldNotifyListeners,
|
|
||||||
// }) async {
|
|
||||||
// final _names = DB.instance
|
|
||||||
// .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> names;
|
|
||||||
// if (_names == null) {
|
|
||||||
// names = {};
|
|
||||||
// } else {
|
|
||||||
// names = Map<String, dynamic>.from(_names);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Prevent overwriting or storing empty names
|
|
||||||
// if (name.isEmpty ||
|
|
||||||
// names.values.where((element) => element['name'] == name).isNotEmpty) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final id = const Uuid().v1();
|
|
||||||
// names[id] = {
|
|
||||||
// "id": id,
|
|
||||||
// "coin": coin.name,
|
|
||||||
// "name": name,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: 'names', value: names);
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${id}_cryptoCurrency",
|
|
||||||
// value: coin.name);
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${id}_mnemonicHasBeenVerified",
|
|
||||||
// value: false);
|
|
||||||
// await DB.instance.addWalletBox(walletId: id);
|
|
||||||
// await refreshWallets(shouldNotifyListeners);
|
|
||||||
// return id;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Future<List<String>> getFavoriteWalletIds() async {
|
|
||||||
// return DB.instance
|
|
||||||
// .values<String>(boxName: DB.boxNameFavoriteWallets)
|
|
||||||
// .toList();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Future<void> saveFavoriteWalletIds(List<String> walletIds) async {
|
|
||||||
// await DB.instance.deleteAll<String>(boxName: DB.boxNameFavoriteWallets);
|
|
||||||
// await DB.instance
|
|
||||||
// .addAll(boxName: DB.boxNameFavoriteWallets, values: walletIds);
|
|
||||||
// debugPrint("saveFavoriteWalletIds list: $walletIds");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> addFavorite(String walletId) async {
|
|
||||||
// final list = await getFavoriteWalletIds();
|
|
||||||
// if (!list.contains(walletId)) {
|
|
||||||
// list.add(walletId);
|
|
||||||
// }
|
|
||||||
// await saveFavoriteWalletIds(list);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> removeFavorite(String walletId) async {
|
|
||||||
// final list = await getFavoriteWalletIds();
|
|
||||||
// list.remove(walletId);
|
|
||||||
// await saveFavoriteWalletIds(list);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> moveFavorite({
|
|
||||||
// required int fromIndex,
|
|
||||||
// required int toIndex,
|
|
||||||
// }) async {
|
|
||||||
// final list = await getFavoriteWalletIds();
|
|
||||||
// if (fromIndex < toIndex) {
|
|
||||||
// toIndex -= 1;
|
|
||||||
// }
|
|
||||||
// final walletId = list.removeAt(fromIndex);
|
|
||||||
// list.insert(toIndex, walletId);
|
|
||||||
// await saveFavoriteWalletIds(list);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<bool> checkForDuplicate(String name) async {
|
|
||||||
// final names = DB.instance
|
|
||||||
// .get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
|
||||||
// if (names == null) return false;
|
|
||||||
//
|
|
||||||
// return names.values.where((element) => element['name'] == name).isNotEmpty;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Future<String?> getWalletId(String walletName) async {
|
|
||||||
final names = DB.instance
|
|
||||||
.get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map;
|
|
||||||
final shells =
|
|
||||||
names.values.where((element) => element['name'] == walletName);
|
|
||||||
if (shells.isEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return shells.first["id"] as String;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future<bool> isMnemonicVerified({required String walletId}) async {
|
|
||||||
// final isVerified = DB.instance.get<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_mnemonicHasBeenVerified") as bool?;
|
|
||||||
//
|
|
||||||
// if (isVerified == null) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "isMnemonicVerified(walletId: $walletId) returned null which should never happen!",
|
|
||||||
// level: LogLevel.Error,
|
|
||||||
// );
|
|
||||||
// throw Exception(
|
|
||||||
// "isMnemonicVerified(walletId: $walletId) returned null which should never happen!");
|
|
||||||
// } else {
|
|
||||||
// return isVerified;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> setMnemonicVerified({required String walletId}) async {
|
|
||||||
// final isVerified = DB.instance.get<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_mnemonicHasBeenVerified") as bool?;
|
|
||||||
//
|
|
||||||
// if (isVerified == null) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "setMnemonicVerified(walletId: $walletId) tried running on non existent wallet!",
|
|
||||||
// level: LogLevel.Error,
|
|
||||||
// );
|
|
||||||
// throw Exception(
|
|
||||||
// "setMnemonicVerified(walletId: $walletId) tried running on non existent wallet!");
|
|
||||||
// } else if (isVerified) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "setMnemonicVerified(walletId: $walletId) tried running on already verified wallet!",
|
|
||||||
// level: LogLevel.Error,
|
|
||||||
// );
|
|
||||||
// throw Exception(
|
|
||||||
// "setMnemonicVerified(walletId: $walletId) tried running on already verified wallet!");
|
|
||||||
// } else {
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_mnemonicHasBeenVerified",
|
|
||||||
// value: true);
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "setMnemonicVerified(walletId: $walletId) successful",
|
|
||||||
// level: LogLevel.Error,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // pin + mnemonic as well as anything else in secureStore
|
|
||||||
// Future<int> deleteWallet(String name, bool shouldNotifyListeners) async {
|
|
||||||
// final names = DB.instance.get<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: 'names') as Map? ??
|
|
||||||
// {};
|
|
||||||
//
|
|
||||||
// final walletId = await getWalletId(name);
|
|
||||||
// if (walletId == null) {
|
|
||||||
// return 3;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "deleteWallet called with name=$name and id=$walletId",
|
|
||||||
// level: LogLevel.Warning,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// final shell = names.remove(walletId);
|
|
||||||
//
|
|
||||||
// if (shell == null) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // TODO delete derivations!!!
|
|
||||||
// await _secureStore.delete(key: "${walletId}_pin");
|
|
||||||
// await _secureStore.delete(key: "${walletId}_mnemonic");
|
|
||||||
//
|
|
||||||
// await DB.instance.delete<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: "${walletId}_cryptoCurrency");
|
|
||||||
// await DB.instance.delete<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData,
|
|
||||||
// key: "${walletId}_mnemonicHasBeenVerified");
|
|
||||||
// if (coinFromPrettyName(shell['coin'] as String) == Coin.wownero) {
|
|
||||||
// final wowService =
|
|
||||||
// wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
|
|
||||||
// await wowService.remove(walletId);
|
|
||||||
// Logging.instance
|
|
||||||
// .log("monero wallet: $walletId deleted", level: LogLevel.Info);
|
|
||||||
// } else if (coinFromPrettyName(shell['coin'] as String) == Coin.monero) {
|
|
||||||
// final xmrService =
|
|
||||||
// monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
|
|
||||||
// await xmrService.remove(walletId);
|
|
||||||
// Logging.instance
|
|
||||||
// .log("monero wallet: $walletId deleted", level: LogLevel.Info);
|
|
||||||
// } else if (coinFromPrettyName(shell['coin'] as String) == Coin.epicCash) {
|
|
||||||
// final deleteResult =
|
|
||||||
// await deleteEpicWallet(walletId: walletId, secureStore: _secureStore);
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "epic wallet: $walletId deleted with result: $deleteResult",
|
|
||||||
// level: LogLevel.Info);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // box data may currently still be read/written to if wallet was refreshing
|
|
||||||
// // when delete was requested so instead of deleting now we mark the wallet
|
|
||||||
// // as needs delete by adding it's id to a list which gets checked on app start
|
|
||||||
// await DB.instance.add<String>(
|
|
||||||
// boxName: DB.boxNameWalletsToDeleteOnStart, value: walletId);
|
|
||||||
//
|
|
||||||
// final lookupService = TradeSentFromStackService();
|
|
||||||
// for (final lookup in lookupService.all) {
|
|
||||||
// if (lookup.walletIds.contains(walletId)) {
|
|
||||||
// // update lookup data to reflect deleted wallet
|
|
||||||
// await lookupService.save(
|
|
||||||
// tradeWalletLookup: lookup.copyWith(
|
|
||||||
// walletIds: lookup.walletIds.where((id) => id != walletId).toList(),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // delete notifications tied to deleted wallet
|
|
||||||
// for (final notification in NotificationsService.instance.notifications) {
|
|
||||||
// if (notification.walletId == walletId) {
|
|
||||||
// await NotificationsService.instance.delete(notification, false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (names.isEmpty) {
|
|
||||||
// await DB.instance.deleteAll<dynamic>(boxName: DB.boxNameAllWalletsData);
|
|
||||||
// _walletNames = Future(() => {});
|
|
||||||
// notifyListeners();
|
|
||||||
// return 2; // error code no wallets on device
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// await DB.instance.put<dynamic>(
|
|
||||||
// boxName: DB.boxNameAllWalletsData, key: 'names', value: names);
|
|
||||||
// await refreshWallets(shouldNotifyListeners);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> refreshWallets(bool shouldNotifyListeners) async {
|
|
||||||
// final newNames = await _fetchWalletNames();
|
|
||||||
// _walletNames = Future(() => newNames);
|
|
||||||
// if (shouldNotifyListeners) notifyListeners();
|
|
||||||
// }
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ class GasTracker {
|
||||||
final int numberOfBlocksAverage;
|
final int numberOfBlocksAverage;
|
||||||
final int numberOfBlocksSlow;
|
final int numberOfBlocksSlow;
|
||||||
|
|
||||||
final int timestamp;
|
final String lastBlock;
|
||||||
|
|
||||||
const GasTracker({
|
const GasTracker({
|
||||||
required this.average,
|
required this.average,
|
||||||
|
@ -24,19 +24,20 @@ class GasTracker {
|
||||||
required this.numberOfBlocksFast,
|
required this.numberOfBlocksFast,
|
||||||
required this.numberOfBlocksAverage,
|
required this.numberOfBlocksAverage,
|
||||||
required this.numberOfBlocksSlow,
|
required this.numberOfBlocksSlow,
|
||||||
required this.timestamp,
|
required this.lastBlock,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory GasTracker.fromJson(Map<String, dynamic> json) {
|
factory GasTracker.fromJson(Map<String, dynamic> json) {
|
||||||
final targetTime = Constants.targetBlockTimeInSeconds(Coin.ethereum);
|
final targetTime = Constants.targetBlockTimeInSeconds(Coin.ethereum);
|
||||||
return GasTracker(
|
return GasTracker(
|
||||||
average: Decimal.parse(json["average"]["price"].toString()),
|
fast: Decimal.parse(json["FastGasPrice"].toString()),
|
||||||
fast: Decimal.parse(json["fast"]["price"].toString()),
|
average: Decimal.parse(json["ProposeGasPrice"].toString()),
|
||||||
slow: Decimal.parse(json["slow"]["price"].toString()),
|
slow: Decimal.parse(json["SafeGasPrice"].toString()),
|
||||||
numberOfBlocksAverage: (json["average"]["time"] as int) ~/ targetTime,
|
// TODO fix hardcoded
|
||||||
numberOfBlocksFast: (json["fast"]["time"] as int) ~/ targetTime,
|
numberOfBlocksFast: 30 ~/ targetTime,
|
||||||
numberOfBlocksSlow: (json["slow"]["time"] as int) ~/ targetTime,
|
numberOfBlocksAverage: 180 ~/ targetTime,
|
||||||
timestamp: json["timestamp"] as int,
|
numberOfBlocksSlow: 240 ~/ targetTime,
|
||||||
|
lastBlock: json["LastBlock"] as String,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue