Merged main into ltc.

This commit is contained in:
M
2021-05-10 19:51:13 +03:00
44 changed files with 1341 additions and 278 deletions
+5 -16
View File
@@ -4,23 +4,11 @@ import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:unorm_dart/unorm_dart.dart' as unorm;
import 'package:cryptography/cryptography.dart' as cryptography;
import 'package:cake_wallet/core/sec_random_native.dart';
const segwit = '100';
final wordlist = englishWordlist;
Uint8List randomBytes(int length, {bool secure = false}) {
assert(length > 0);
final random = secure ? Random.secure() : Random();
final ret = Uint8List(length);
for (var i = 0; i < length; i++) {
ret[i] = random.nextInt(256);
}
return ret;
}
double logBase(num x, num base) => log(x) / log(base);
String mnemonicEncode(int i) {
@@ -102,14 +90,15 @@ List<bool> prefixMatches(String source, List<String> prefixes) {
return prefixes.map((prefix) => hx.startsWith(prefix.toLowerCase())).toList();
}
String generateMnemonic({int strength = 132, String prefix = segwit}) {
Future<String> generateMnemonic(
{int strength = 264, String prefix = segwit}) async {
final wordBitlen = logBase(wordlist.length, 2).ceil();
final wordCount = strength / wordBitlen;
final byteCount = ((wordCount * wordBitlen).ceil() / 8).ceil();
var result = '';
do {
final bytes = randomBytes(byteCount);
final bytes = await secRandom(byteCount);
maskBytes(bytes, strength);
result = encode(bytes);
} while (!prefixMatches(result, [prefix]).first);
@@ -134,7 +123,7 @@ bool matchesAnyPrefix(String mnemonic) =>
bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
try {
return matchesAnyPrefix(mnemonic);
} catch(e) {
} catch (e) {
return false;
}
}
@@ -1,5 +1,5 @@
class BitcoinMnemonicIsIncorrectException implements Exception {
@override
String toString() =>
'Bitcoin mnemonic has incorrect format. Mnemonic should contain 12 words separated by space.';
'Bitcoin mnemonic has incorrect format. Mnemonic should contain 24 words separated by space.';
}
+1 -1
View File
@@ -24,7 +24,7 @@ class BitcoinWalletService extends WalletService<
@override
Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final wallet = BitcoinWallet(
mnemonic: generateMnemonic(),
mnemonic: await generateMnemonic(),
password: credentials.password,
walletInfo: credentials.walletInfo);
await wallet.save();
+13
View File
@@ -0,0 +1,13 @@
import 'dart:typed_data';
import 'package:flutter/services.dart';
const utils = const MethodChannel('com.cake_wallet/native_utils');
Future<Uint8List> secRandom(int count) async {
try {
return await utils.invokeMethod<Uint8List>('sec_random', {'count': count});
} on PlatformException catch (_) {
return Uint8List.fromList([]);
}
}
+2 -3
View File
@@ -19,7 +19,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.eos,
CryptoCurrency.eth,
CryptoCurrency.ltc,
CryptoCurrency.nano,
CryptoCurrency.trx,
CryptoCurrency.usdt,
CryptoCurrency.usdterc20,
@@ -29,7 +28,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
static const xmr = CryptoCurrency(title: 'XMR', raw: 0);
static const ada = CryptoCurrency(title: 'ADA', raw: 1);
static const bch = CryptoCurrency(title: 'BCH', raw: 2);
static const bnb = CryptoCurrency(title: 'BNB', raw: 3);
static const bnb = CryptoCurrency(title: 'BNB BEP2', raw: 3);
static const btc = CryptoCurrency(title: 'BTC', raw: 4);
static const dai = CryptoCurrency(title: 'DAI', raw: 5);
static const dash = CryptoCurrency(title: 'DASH', raw: 6);
@@ -90,7 +89,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
return CryptoCurrency.ada;
case 'bch':
return CryptoCurrency.bch;
case 'bnb':
case 'bnbmainnet':
return CryptoCurrency.bnb;
case 'btc':
return CryptoCurrency.btc;
+3 -1
View File
@@ -15,7 +15,9 @@ class LanguageService {
'pt': 'Português (Portuguese)',
'ru': 'Русский (Russian)',
'uk': 'Українська (Ukrainian)',
'zh': '中文 (Chinese)'
'zh': '中文 (Chinese)',
'hr': 'Hrvatski (Croatian)',
'it': 'Italiano (Italian)'
};
static final list = <String, String> {};
@@ -48,7 +48,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to,
bool isFixedRateMode}) async {
final symbol = from.toString() + '_' + to.toString();
final fromTitle = defineCurrencyTitle(from);
final toTitle = defineCurrencyTitle(to);
final symbol = fromTitle + '_' + toTitle;
final url = isFixedRateMode
? apiUri + _marketInfoUriSufix + _fixedRateUriSufix + apiKey
: apiUri + _minAmountUriSufix + symbol;
@@ -61,8 +63,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final elemFrom = elem["from"] as String;
final elemTo = elem["to"] as String;
if ((elemFrom == from.toString().toLowerCase()) &&
(elemTo == to.toString().toLowerCase())) {
if ((elemFrom == fromTitle) && (elemTo == toTitle)) {
final min = elem["min"] as double;
final max = elem["max"] as double;
@@ -84,9 +85,11 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
? apiUri + _transactionsUriSufix + _fixedRateUriSufix + apiKey
: apiUri + _transactionsUriSufix + apiKey;
final _request = request as ChangeNowRequest;
final fromTitle = defineCurrencyTitle(_request.from);
final toTitle = defineCurrencyTitle(_request.to);
final body = {
'from': _request.from.toString(),
'to': _request.to.toString(),
'from': fromTitle,
'to': toTitle,
'address': _request.address,
'amount': _request.amount,
'refundAddress': _request.refundAddress
@@ -182,6 +185,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final url = apiUri + _marketInfoUriSufix + _fixedRateUriSufix + apiKey;
final response = await get(url);
final responseJSON = json.decode(response.body) as List<dynamic>;
final fromTitle = defineCurrencyTitle(from);
final toTitle = defineCurrencyTitle(to);
var rate = 0.0;
var fee = 0.0;
@@ -189,8 +194,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final elemFrom = elem["from"] as String;
final elemTo = elem["to"] as String;
if ((elemFrom == to.toString().toLowerCase()) &&
(elemTo == from.toString().toLowerCase())) {
if ((elemFrom == toTitle) && (elemTo == fromTitle)) {
rate = elem["rate"] as double;
fee = elem["minerFee"] as double;
break;
@@ -216,22 +220,32 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
CryptoCurrency to,
double amount,
bool isFixedRateMode) {
final fromTitle = defineCurrencyTitle(from);
final toTitle = defineCurrencyTitle(to);
return isFixedRateMode
? apiUri +
_exchangeAmountUriSufix +
_fixedRateUriSufix +
amount.toString() +
'/' +
from.toString() +
fromTitle +
'_' +
to.toString() +
toTitle +
'?api_key=' + apiKey
: apiUri +
_exchangeAmountUriSufix +
amount.toString() +
'/' +
from.toString() +
fromTitle +
'_' +
to.toString();
toTitle;
}
static String defineCurrencyTitle(CryptoCurrency currency) {
const bnbTitle = 'bnbmainnet';
final currencyTitle = currency == CryptoCurrency.bnb
? bnbTitle : currency.title.toLowerCase();
return currencyTitle;
}
}
+1 -1
View File
@@ -221,7 +221,7 @@ class MoneroWalletService extends WalletService<
final name = f.path.split('/').last;
final newPath = newWalletDirPath + '/$name';
final newFile = File(newPath);
print(file.path);
if (!newFile.existsSync()) {
newFile.createSync();
}
+5 -3
View File
@@ -237,9 +237,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.unlock:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<AuthPage>(
param1: settings.arguments as OnAuthenticationFinished,
param2: false));
builder: (_) => WillPopScope(
child: getIt.get<AuthPage>(
param1: settings.arguments as OnAuthenticationFinished,
param2: false),
onWillPop: () async => false));
case Routes.nodeList:
return CupertinoPageRoute<void>(
+35 -17
View File
@@ -1,7 +1,9 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -42,7 +44,7 @@ class DashboardPage extends BasePage {
child: scaffold);
@override
bool get resizeToAvoidBottomPadding => false;
bool get resizeToAvoidBottomInset => false;
@override
Widget get endDrawer => MenuWidget(walletViewModel);
@@ -114,7 +116,7 @@ class DashboardPage extends BasePage {
)),
Container(
padding: EdgeInsets.only(left: 45, right: 45, bottom: 24),
child: Observer(builder: (_) => Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
ActionButton(
@@ -125,7 +127,7 @@ class DashboardPage extends BasePage {
image: exchangeImage,
title: S.of(context).exchange,
route: Routes.exchange),
if (walletViewModel.type == WalletType.bitcoin) Observer(
Observer(
builder: (_) => Stack(
clipBehavior: Clip.none,
alignment: Alignment.topCenter,
@@ -143,23 +145,11 @@ class DashboardPage extends BasePage {
title: S.of(context).buy,
onClick: walletViewModel.isRunningWebView
? null
: () async {
try {
walletViewModel.isRunningWebView = true;
final url =
await walletViewModel.wyreViewModel.wyreUrl;
await Navigator.of(context)
.pushNamed(Routes.wyre, arguments: url);
walletViewModel.isRunningWebView = false;
} catch(e) {
print(e.toString());
walletViewModel.isRunningWebView = false;
}
})
: () async => await _onClickBuyButton(context))
],
)),
],
)),
),
)
],
));
@@ -176,4 +166,32 @@ class DashboardPage extends BasePage {
_isEffectsInstalled = true;
}
Future <void> _onClickBuyButton(BuildContext context) async {
final walletType = walletViewModel.type;
switch (walletType) {
case WalletType.monero:
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).buy,
alertContent: S.of(context).buy_alert_content,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
break;
default:
try {
walletViewModel.isRunningWebView = true;
final url = await walletViewModel.wyreViewModel.wyreUrl;
await Navigator.of(context).pushNamed(Routes.wyre, arguments: url);
walletViewModel.isRunningWebView = false;
} catch(_) {
walletViewModel.isRunningWebView = false;
}
break;
}
}
}
+4 -2
View File
@@ -13,7 +13,7 @@ class PreSeedPage extends BasePage {
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
wordsCount = type == WalletType.monero
? 25
: 12; // FIXME: Stupid fast implementation
: 24; // FIXME: Stupid fast implementation
final Image imageDark;
final Image imageLight;
@@ -49,7 +49,9 @@ class PreSeedPage extends BasePage {
Padding(
padding: EdgeInsets.only(top: 70, left: 16, right: 16),
child: Text(
S.of(context).pre_seed_description(wordsCount.toString()),
S
.of(context)
.pre_seed_description(wordsCount.toString()),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
-2
View File
@@ -110,8 +110,6 @@ abstract class AuthViewModelBase with Store {
if (isAuthenticated) {
state = ExecutedSuccessfullyState();
} else {
state = FailureState('Failure biometric authentication');
}
}
} catch(e) {
@@ -33,8 +33,8 @@ class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
this.tradesStore, this._settingsStore) {
const excludeCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp, CryptoCurrency.bnb];
providerList = [ChangeNowExchangeProvider()];
_initialPairBasedOnWallet();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
@@ -56,10 +56,8 @@ abstract class ExchangeViewModelBase with Store {
}
});
receiveCurrencies = CryptoCurrency.all
.where((cryptoCurrency) =>
(cryptoCurrency != CryptoCurrency.xlm) &&
(cryptoCurrency != CryptoCurrency.xrp))
.toList();
.where((cryptoCurrency) => !excludeCurrencies.contains(cryptoCurrency))
.toList();
_defineIsReceiveAmountEditable();
isFixedRateMode = false;
isReceiveAmountEntered = false;