mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Fixes
This commit is contained in:
parent
2dc5489a8e
commit
798d9a1edf
11 changed files with 181 additions and 85 deletions
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/entities/crypto_amount_format.dart';
|
||||
|
||||
|
@ -7,10 +9,32 @@ final bitcoinAmountFormat = NumberFormat()
|
|||
..maximumFractionDigits = bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
String bitcoinAmountToString({int amount}) =>
|
||||
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
String bitcoinAmountToString({int amount}) => bitcoinAmountFormat.format(
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
|
||||
double bitcoinAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||
double bitcoinAmountToDouble({int amount}) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||
|
||||
int doubleToBitcoinAmount(double amount) =>
|
||||
(amount * bitcoinAmountDivider).toInt();
|
||||
int stringDoubleToBitcoinAmount(String amount) {
|
||||
final splitted = amount.split('');
|
||||
final dotIndex = amount.indexOf('.');
|
||||
int result = 0;
|
||||
|
||||
|
||||
for (var i = 0; i < splitted.length; i++) {
|
||||
try {
|
||||
if (dotIndex == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final char = splitted[i];
|
||||
final multiplier = dotIndex < i
|
||||
? bitcoinAmountDivider ~/ pow(10, (i - dotIndex))
|
||||
: (bitcoinAmountDivider * pow(10, (dotIndex - i -1))).toInt();
|
||||
final num = int.parse(char) * multiplier;
|
||||
result += num;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ class BitcoinTransactionCredentials {
|
|||
BitcoinTransactionCredentials(this.address, this.amount, this.priority);
|
||||
|
||||
final String address;
|
||||
final double amount;
|
||||
final String amount;
|
||||
TransactionPriority priority;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
|
|||
final out = vin['tx']['vout'][vout] as Map;
|
||||
final outAddresses =
|
||||
(out['scriptPubKey']['addresses'] as List<Object>)?.toSet();
|
||||
inputsAmount += doubleToBitcoinAmount(out['value'] as double ?? 0);
|
||||
inputsAmount += stringDoubleToBitcoinAmount((out['value'] as double ?? 0).toString());
|
||||
|
||||
if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) {
|
||||
direction = TransactionDirection.outgoing;
|
||||
|
@ -58,7 +58,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
|
|||
final outAddresses =
|
||||
out['scriptPubKey']['addresses'] as List<Object> ?? [];
|
||||
final ntrs = outAddresses.toSet().intersection(addressesSet);
|
||||
final value = doubleToBitcoinAmount(out['value'] as double ?? 0.0);
|
||||
final value = stringDoubleToBitcoinAmount((out['value'] as double ?? 0.0).toString());
|
||||
totalOutAmount += value;
|
||||
|
||||
if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
|
||||
|
|
|
@ -116,6 +116,19 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
walletInfo: walletInfo);
|
||||
}
|
||||
|
||||
static int feeAmountForPriority(TransactionPriority priority) {
|
||||
switch (priority) {
|
||||
case TransactionPriority.slow:
|
||||
return 6000;
|
||||
case TransactionPriority.regular:
|
||||
return 22080;
|
||||
case TransactionPriority.fast:
|
||||
return 24000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
final BitcoinTransactionHistory transactionHistory;
|
||||
final String path;
|
||||
|
@ -243,16 +256,20 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
Object credentials) async {
|
||||
final transactionCredentials = credentials as BitcoinTransactionCredentials;
|
||||
final inputs = <BitcoinUnspent>[];
|
||||
final fee = _feeMultiplier(transactionCredentials.priority);
|
||||
final fee = feeAmountForPriority(transactionCredentials.priority);
|
||||
final amount = transactionCredentials.amount != null
|
||||
? doubleToBitcoinAmount(transactionCredentials.amount)
|
||||
: balance.total - fee;
|
||||
? stringDoubleToBitcoinAmount(transactionCredentials.amount)
|
||||
: balance.availableBalance - fee;
|
||||
final totalAmount = amount + fee;
|
||||
final txb = bitcoin.TransactionBuilder(network: bitcoin.bitcoin);
|
||||
var leftAmount = totalAmount;
|
||||
final changeAddress = address;
|
||||
var leftAmount = totalAmount;
|
||||
var totalInputAmount = 0;
|
||||
|
||||
if (totalAmount > balance.availableBalance) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
|
||||
final unspent = addresses.map((address) => eclient
|
||||
.getListUnspentWithAddress(address.address)
|
||||
.then((unspent) => unspent
|
||||
|
@ -334,7 +351,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
|
||||
@override
|
||||
double calculateEstimatedFee(TransactionPriority priority) =>
|
||||
bitcoinAmountToDouble(amount: _feeMultiplier(priority));
|
||||
bitcoinAmountToDouble(amount: feeAmountForPriority(priority));
|
||||
|
||||
@override
|
||||
Future<void> save() async {
|
||||
|
@ -386,17 +403,4 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
|
||||
String _getAddress({@required int index}) =>
|
||||
generateAddress(hd: hd, index: index);
|
||||
|
||||
int _feeMultiplier(TransactionPriority priority) {
|
||||
switch (priority) {
|
||||
case TransactionPriority.slow:
|
||||
return 6000;
|
||||
case TransactionPriority.regular:
|
||||
return 22080;
|
||||
case TransactionPriority.fast:
|
||||
return 24000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,7 +355,8 @@ Future setup(
|
|||
getIt.get<AppStore>().wallet,
|
||||
tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>()));
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
|
|
@ -62,10 +62,11 @@ class ExchangePage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => TrailButton(
|
||||
caption: S.of(context).reset, onPressed: () {
|
||||
caption: S.of(context).reset,
|
||||
onPressed: () {
|
||||
_formKey.currentState.reset();
|
||||
exchangeViewModel.reset();
|
||||
});
|
||||
});
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
@ -95,8 +96,8 @@ class ExchangePage extends BasePage {
|
|||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).accentTextTheme.body2
|
||||
.backgroundColor,
|
||||
keyboardBarColor:
|
||||
Theme.of(context).accentTextTheme.body2.backgroundColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
|
@ -160,6 +161,11 @@ class ExchangePage extends BasePage {
|
|||
padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
|
||||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
hasAllAmount: exchangeViewModel.hasAllAmount,
|
||||
allAmount: exchangeViewModel.hasAllAmount
|
||||
? () => exchangeViewModel
|
||||
.calculateDepositAllAmount()
|
||||
: null,
|
||||
amountFocusNode: _depositAmountFocus,
|
||||
key: depositKey,
|
||||
title: S.of(context).you_will_send,
|
||||
|
@ -394,30 +400,35 @@ class ExchangePage extends BasePage {
|
|||
}),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
if ((exchangeViewModel.depositCurrency == CryptoCurrency.xmr)
|
||||
&&(!(exchangeViewModel.status is SyncedSyncStatus))) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).exchange,
|
||||
alertContent: S.of(context).exchange_sync_alert_content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
} else {
|
||||
exchangeViewModel.createTrade();
|
||||
}
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white,
|
||||
isLoading: exchangeViewModel.tradeState
|
||||
is TradeIsCreating)),
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
if ((exchangeViewModel.depositCurrency ==
|
||||
CryptoCurrency.xmr) &&
|
||||
(!(exchangeViewModel.status
|
||||
is SyncedSyncStatus))) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).exchange,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.exchange_sync_alert_content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () =>
|
||||
Navigator.of(context).pop());
|
||||
});
|
||||
} else {
|
||||
exchangeViewModel.createTrade();
|
||||
}
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white,
|
||||
isLoading:
|
||||
exchangeViewModel.tradeState is TradeIsCreating)),
|
||||
]),
|
||||
)),
|
||||
));
|
||||
|
|
|
@ -27,7 +27,9 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.borderColor = Colors.transparent,
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.amountFocusNode})
|
||||
this.amountFocusNode,
|
||||
this.hasAllAmount = false,
|
||||
this.allAmount})
|
||||
: super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
|
@ -47,6 +49,8 @@ class ExchangeCard extends StatefulWidget {
|
|||
final FormFieldValidator<String> currencyValueValidator;
|
||||
final FormFieldValidator<String> addressTextFieldValidator;
|
||||
final FocusNode amountFocusNode;
|
||||
final bool hasAllAmount;
|
||||
Function allAmount;
|
||||
|
||||
@override
|
||||
ExchangeCardState createState() => ExchangeCardState();
|
||||
|
@ -197,7 +201,36 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
]),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
if (widget.hasAllAmount)
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 55,
|
||||
child: Container(
|
||||
height: 32,
|
||||
width: 32,
|
||||
margin: EdgeInsets.only(left: 14, top: 4, bottom: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.color,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: InkWell(
|
||||
onTap: () => widget.allAmount?.call(),
|
||||
child: Center(
|
||||
child: Text(S.of(context).all,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor)),
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
|
@ -232,18 +265,17 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
),
|
||||
!_isAddressEditable && widget.hasRefundAddress
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
))
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
))
|
||||
: Offstage(),
|
||||
_isAddressEditable
|
||||
? Padding(
|
||||
|
@ -251,7 +283,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
child: AddressTextField(
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address : null,
|
||||
? S.of(context).refund_address
|
||||
: null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
|
@ -265,8 +298,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context)
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
|
@ -281,8 +313,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: addressController.text));
|
||||
showBar<void>(context,
|
||||
S.of(context).copied_to_clipboard);
|
||||
showBar<void>(
|
||||
context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
|
|
@ -153,7 +153,7 @@ abstract class SettingsStoreBase with Store {
|
|||
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
false;
|
||||
final legacyTheme =
|
||||
sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy)
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
final savedTheme = ThemeList.deserialize(
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
|
@ -7,6 +9,7 @@ import 'package:cake_wallet/exchange/limits.dart';
|
|||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits_state.dart';
|
||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -27,8 +30,8 @@ part 'exchange_view_model.g.dart';
|
|||
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
|
||||
|
||||
abstract class ExchangeViewModelBase with Store {
|
||||
ExchangeViewModelBase(
|
||||
this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore) {
|
||||
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
|
||||
this.tradesStore, this._settingsStore) {
|
||||
providerList = [
|
||||
XMRTOExchangeProvider(),
|
||||
ChangeNowExchangeProvider(),
|
||||
|
@ -104,10 +107,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@observable
|
||||
bool isReceiveAmountEntered;
|
||||
|
||||
Limits limits;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
@computed
|
||||
SyncStatus get status => wallet.syncStatus;
|
||||
|
||||
|
@ -115,6 +114,15 @@ abstract class ExchangeViewModelBase with Store {
|
|||
ObservableList<ExchangeTemplate> get templates =>
|
||||
_exchangeTemplateStore.templates;
|
||||
|
||||
bool get hasAllAmount =>
|
||||
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
|
||||
|
||||
Limits limits;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
SettingsStore _settingsStore;
|
||||
|
||||
@action
|
||||
void changeProvider({ExchangeProvider provider}) {
|
||||
this.provider = provider;
|
||||
|
@ -264,9 +272,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
await trades.add(trade);
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
} catch (e) {
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: provider.title,
|
||||
error: e.toString());
|
||||
tradeState =
|
||||
TradeIsCreatedFailure(title: provider.title, error: e.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -291,6 +298,22 @@ abstract class ExchangeViewModelBase with Store {
|
|||
_onPairChange();
|
||||
}
|
||||
|
||||
@action
|
||||
void calculateDepositAllAmount() {
|
||||
if (wallet is BitcoinWallet) {
|
||||
final availableBalance = wallet.balance.availableBalance as int;
|
||||
final fee = BitcoinWalletBase.feeAmountForPriority(
|
||||
_settingsStore.transactionPriority);
|
||||
|
||||
if (availableBalance < fee || availableBalance == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final amount = availableBalance - fee;
|
||||
depositAmount = bitcoinAmountToString(amount: amount);
|
||||
}
|
||||
}
|
||||
|
||||
void updateTemplate() => _exchangeTemplateStore.update();
|
||||
|
||||
void addTemplate(
|
||||
|
|
|
@ -197,7 +197,7 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
switch (_wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
final amount = !sendAll ? double.parse(_amount) : null;
|
||||
final amount = !sendAll ? _amount : null;
|
||||
|
||||
return BitcoinTransactionCredentials(
|
||||
address, amount, _settingsStore.transactionPriority);
|
||||
|
|
Loading…
Reference in a new issue