This commit is contained in:
M
2020-09-21 14:50:26 +03:00
parent 5e1132a299
commit e4ebfc94b2
273 changed files with 2472 additions and 7285 deletions
@@ -1,9 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const bitcoinAmountDivider = 100000000;
double bitcoinAmountToDouble({int amount}) =>
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
int doubleToBitcoinAmount(double amount) =>
(amount * bitcoinAmountDivider).toInt();
@@ -1,6 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const bitcoinCashAmountDivider = 100000000;
double bitcoinCashAmountToDouble({int amount}) =>
cryptoAmountToDouble(amount: amount, divider: bitcoinCashAmountDivider);
-3
View File
@@ -1,3 +0,0 @@
abstract class Balance {
const Balance();
}
@@ -1,46 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
const BalanceDisplayMode({@required String title, @required int raw})
: super(title: title, raw: raw);
static const all = [
BalanceDisplayMode.fullBalance,
BalanceDisplayMode.availableBalance,
BalanceDisplayMode.hiddenBalance
];
static const fullBalance = BalanceDisplayMode(raw: 0, title: 'Full Balance');
static const availableBalance =
BalanceDisplayMode(raw: 1, title: 'Available Balance');
static const hiddenBalance =
BalanceDisplayMode(raw: 2, title: 'Hidden Balance');
static BalanceDisplayMode deserialize({int raw}) {
switch (raw) {
case 0:
return fullBalance;
case 1:
return availableBalance;
case 2:
return hiddenBalance;
default:
return null;
}
}
@override
String toString() {
switch (this) {
case BalanceDisplayMode.fullBalance:
return S.current.xmr_full_balance;
case BalanceDisplayMode.availableBalance:
return S.current.xmr_available_balance;
case BalanceDisplayMode.hiddenBalance:
return S.current.xmr_hidden;
default:
return '';
}
}
}
-30
View File
@@ -1,30 +0,0 @@
import 'package:local_auth/local_auth.dart';
import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
class BiometricAuth {
final _localAuth = LocalAuthentication();
Future<bool> isAuthenticated() async {
try {
return await _localAuth.authenticateWithBiometrics(
localizedReason: S.current.biometric_auth_reason,
useErrorDialogs: true,
stickyAuth: false);
} on PlatformException catch (e) {
print(e);
}
return false;
}
Future<bool> canCheckBiometrics() async {
try {
return await _localAuth.canCheckBiometrics;
} on PlatformException catch (e) {
print(e);
}
return false;
}
}
@@ -1,25 +0,0 @@
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
double calculateEstimatedFee({TransactionPriority priority}) {
if (priority == TransactionPriority.slow) {
return 0.00002459;
}
if (priority == TransactionPriority.regular) {
return 0.00012305;
}
if (priority == TransactionPriority.medium) {
return 0.00024503;
}
if (priority == TransactionPriority.fast) {
return 0.00061453;
}
if (priority == TransactionPriority.fastest) {
return 0.0260216;
}
return 0;
}
@@ -1,14 +0,0 @@
String calculateFiatAmount({double price, String cryptoAmount}) {
if (price == null || cryptoAmount == null) {
return '0.00';
}
final _amount = double.parse(cryptoAmount);
final result = price * _amount;
if (result == 0.0) {
return '0.00';
}
return result > 0.01 ? result.toStringAsFixed(2) : '< 0.01';
}
@@ -1,13 +0,0 @@
String calculateFiatAmountRaw({double price, double cryptoAmount}) {
if (price == null) {
return '0.00';
}
final result = price * cryptoAmount;
if (result == 0.0) {
return '0.00';
}
return result > 0.01 ? result.toStringAsFixed(2) : '< 0.01';
}
-37
View File
@@ -1,37 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/utils/mobx.dart';
part 'contact.g.dart';
@HiveType(typeId: 0)
class Contact extends HiveObject with Keyable {
Contact({@required this.name, @required this.address, CryptoCurrency type})
: raw = type?.raw;
static const boxName = 'Contacts';
@HiveField(0)
String name;
@HiveField(1)
String address;
@HiveField(2)
int raw;
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
@override
dynamic get keyIndex => key;
@override
bool operator ==(Object o) => o is Contact && o.key == key;
@override
int get hashCode => key.hashCode;
void updateCryptoCurrency({@required CryptoCurrency currency}) =>
raw = currency.raw;
}
-38
View File
@@ -1,38 +0,0 @@
// import 'package:hive/hive.dart';
// import 'package:mobx/mobx.dart';
// import 'package:cake_wallet/src/domain/common/contact.dart';
// import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
// part 'contact_model.g.dart';
// class ContactModel = ContactModelBase with _$ContactModel;
// abstract class ContactModelBase with Store {
// ContactModelBase(this._contacts, {Contact contact}) : _contact = contact {
// name = _contact?.name;
// address = _contact?.address;
// currency = _contact?.type;
// _contacts.watch(key: contact.key).listen((event) {
// });
// }
// @observable
// String name;
// @observable
// String address;
// @observable
// CryptoCurrency currency;
// // @computed
// // bool get isReady =>
// // (name?.isNotEmpty ?? false) &&
// // (currency?.toString()?.isNotEmpty ?? false) &&
// // (address?.isNotEmpty ?? false);
// final Box<ContactBase> _contacts;
// final Contact _contact;
// }
@@ -1 +0,0 @@
double cryptoAmountToDouble({num amount, num divider}) => amount / divider;
-114
View File
@@ -1,114 +0,0 @@
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
import 'package:hive/hive.dart';
part 'crypto_currency.g.dart';
@HiveType(typeId: 0)
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
const CryptoCurrency({final String title, final int raw})
: super(title: title, raw: raw);
static const all = [
CryptoCurrency.xmr,
CryptoCurrency.ada,
CryptoCurrency.bch,
CryptoCurrency.bnb,
CryptoCurrency.btc,
CryptoCurrency.dash,
CryptoCurrency.eos,
CryptoCurrency.eth,
CryptoCurrency.ltc,
CryptoCurrency.nano,
CryptoCurrency.trx,
CryptoCurrency.usdt,
CryptoCurrency.xlm,
CryptoCurrency.xrp
];
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 btc = CryptoCurrency(title: 'BTC', raw: 4);
static const dash = CryptoCurrency(title: 'DASH', raw: 5);
static const eos = CryptoCurrency(title: 'EOS', raw: 6);
static const eth = CryptoCurrency(title: 'ETH', raw: 7);
static const ltc = CryptoCurrency(title: 'LTC', raw: 8);
static const nano = CryptoCurrency(title: 'NANO', raw: 9);
static const trx = CryptoCurrency(title: 'TRX', raw: 10);
static const usdt = CryptoCurrency(title: 'USDT', raw: 11);
static const xlm = CryptoCurrency(title: 'XLM', raw: 12);
static const xrp = CryptoCurrency(title: 'XRP', raw: 13);
static CryptoCurrency deserialize({int raw}) {
switch (raw) {
case 0:
return CryptoCurrency.xmr;
case 1:
return CryptoCurrency.ada;
case 2:
return CryptoCurrency.bch;
case 3:
return CryptoCurrency.bnb;
case 4:
return CryptoCurrency.btc;
case 5:
return CryptoCurrency.dash;
case 6:
return CryptoCurrency.eos;
case 7:
return CryptoCurrency.eth;
case 8:
return CryptoCurrency.ltc;
case 9:
return CryptoCurrency.nano;
case 10:
return CryptoCurrency.trx;
case 11:
return CryptoCurrency.usdt;
case 12:
return CryptoCurrency.xlm;
case 13:
return CryptoCurrency.xrp;
default:
return null;
}
}
static CryptoCurrency fromString(String raw) {
switch (raw.toLowerCase()) {
case 'xmr':
return CryptoCurrency.xmr;
case 'ada':
return CryptoCurrency.ada;
case 'bch':
return CryptoCurrency.bch;
case 'bnb':
return CryptoCurrency.bnb;
case 'btc':
return CryptoCurrency.btc;
case 'dash':
return CryptoCurrency.dash;
case 'eos':
return CryptoCurrency.eos;
case 'eth':
return CryptoCurrency.eth;
case 'ltc':
return CryptoCurrency.ltc;
case 'nano':
return CryptoCurrency.nano;
case 'trx':
return CryptoCurrency.trx;
case 'usdt':
return CryptoCurrency.usdt;
case 'xlm':
return CryptoCurrency.xlm;
case 'xrp':
return CryptoCurrency.xrp;
default:
return null;
}
}
@override
String toString() => title;
}
@@ -1,12 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
String cryptoToString(CryptoCurrency crypto) {
switch (crypto) {
case CryptoCurrency.xmr:
return 'XMR';
case CryptoCurrency.btc:
return 'BTC';
default:
return '';
}
}
@@ -1,178 +0,0 @@
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
import 'package:cake_wallet/src/domain/common/node_list.dart';
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
Future defaultSettingsMigration(
{@required int version,
@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
final currentVersion =
sharedPreferences.getInt('current_default_settings_migration_version') ??
0;
if (currentVersion >= version) {
return;
}
final migrationVersionsLength = version - currentVersion;
final migrationVersions = List<int>.generate(
migrationVersionsLength, (i) => currentVersion + (i + 1));
await Future.forEach(migrationVersions, (int version) async {
try {
switch (version) {
case 1:
await sharedPreferences.setString(
SettingsStoreBase.currentFiatCurrencyKey,
FiatCurrency.usd.toString());
await sharedPreferences.setInt(
SettingsStoreBase.currentTransactionPriorityKey,
TransactionPriority.standart.raw);
await sharedPreferences.setInt(
SettingsStoreBase.currentBalanceDisplayModeKey,
BalanceDisplayMode.availableBalance.raw);
await sharedPreferences.setBool('save_recipient_address', true);
await resetToDefault(nodes);
await changeMoneroCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeBitcoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
case 2:
await replaceNodesMigration(nodes: nodes);
await replaceDefaultNode(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
case 3:
await updateNodeTypes(nodes: nodes);
await addBitcoinElectrumServerList(nodes: nodes);
break;
case 4:
await changeBitcoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
default:
break;
}
await sharedPreferences.setInt(
'current_default_settings_migration_version', version);
} catch (e) {
print('Migration error: ${e.toString()}');
}
});
await sharedPreferences.setInt(
'current_default_settings_migration_version', version);
}
Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
final replaceNodes = <String, Node>{
'eu-node.cakewallet.io:18081':
Node(uri: 'xmr-node-eu.cakewallet.com:18081', type: WalletType.monero),
'node.cakewallet.io:18081': Node(
uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
'node.xmr.ru:13666':
Node(uri: 'node.monero.net:18081', type: WalletType.monero)
};
nodes.values.forEach((Node node) async {
final nodeToReplace = replaceNodes[node.uri];
if (nodeToReplace != null) {
node.uri = nodeToReplace.uri;
node.login = nodeToReplace.login;
node.password = nodeToReplace.password;
await node.save();
}
});
}
Future<void> changeMoneroCurrentNodeToDefault(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
final node = getMoneroDefaultNode(nodes: nodes);
final nodeId = node?.key as int ?? 0; // 0 - England
await sharedPreferences.setInt('current_node_id', nodeId);
}
Node getBitcoinDefaultElectrumServer({@required Box<Node> nodes}) {
final uri = 'electrumx.cakewallet.com:50002';
return nodes.values
.firstWhere((Node node) => node.uri == uri, orElse: () => null) ??
nodes.values.firstWhere((node) => node.type == WalletType.bitcoin,
orElse: () => null);
}
Node getMoneroDefaultNode({@required Box<Node> nodes}) {
final timeZone = DateTime.now().timeZoneOffset.inHours;
var nodeUri = '';
if (timeZone >= 1) {
// Eurasia
nodeUri = 'xmr-node-eu.cakewallet.com:18081';
} else if (timeZone <= -4) {
// America
nodeUri = 'xmr-node-usa-east.cakewallet.com:18081';
}
return nodes.values
.firstWhere((Node node) => node.uri == nodeUri, orElse: () => null) ??
nodes.values.first;
}
Future<void> changeBitcoinCurrentElectrumServerToDefault(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0;
await sharedPreferences.setInt('current_node_id_btc', serverId);
}
Future<void> replaceDefaultNode(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes}) async {
const nodesForReplace = <String>[
'xmr-node-uk.cakewallet.com:18081',
'eu-node.cakewallet.io:18081',
'node.cakewallet.io:18081'
];
final currentNodeId = sharedPreferences.getInt('current_node_id');
final currentNode =
nodes.values.firstWhere((Node node) => node.key == currentNodeId);
final needToReplace =
currentNode == null ? true : nodesForReplace.contains(currentNode.uri);
if (!needToReplace) {
return;
}
await changeMoneroCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
}
Future<void> updateNodeTypes({@required Box<Node> nodes}) async {
nodes.values.forEach((node) async {
if (node.type == null) {
node.type = WalletType.monero;
await node.save();
}
});
}
Future<void> addBitcoinElectrumServerList({@required Box<Node> nodes}) async {
final serverList = await loadElectrumServerList();
await nodes.addAll(serverList);
}
-96
View File
@@ -1,96 +0,0 @@
import 'dart:convert';
import 'package:dio/dio.dart' as __dio;
import 'package:crypto/crypto.dart' as crypto;
import 'dart:math' as math;
class DigestRequest {
final md5 = crypto.md5;
String generateCnonce() {
final rnd = math.Random.secure();
final values = List<int>.generate(32, (i) => rnd.nextInt(256));
return base64Url.encode(values).substring(0, 8);
}
String generateHA1({String realm, String username, String password}) {
final ha1CredentialsData =
Utf8Encoder().convert('$username:$realm:$password');
final ha1 = md5.convert(ha1CredentialsData).toString();
return ha1;
}
String generateHA2({String method, String uri}) {
final ha2Data = Utf8Encoder().convert('$method:$uri');
final ha2 = md5.convert(ha2Data).toString();
return ha2;
}
String generateResponseString(
{String ha1,
String ha2,
String nonce,
String nonceCount,
String cnonce,
String qop}) {
final responseData =
Utf8Encoder().convert('$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2');
final response = md5.convert(responseData).toString();
return response;
}
Map<String, String> parsetAuthorizationHeader({String source}) {
final authHeaderParts =
source.substring(7).split(',').map((item) => item.trim());
final authenticate = Map<String, String>();
for (final part in authHeaderParts) {
final kv = part.split('=');
authenticate[kv[0]] =
kv.getRange(1, kv.length).join('=').replaceAll('"', '');
}
return authenticate;
}
Future<__dio.Response> request(
{String uri, String login, String password}) async {
const path = '/json_rpc';
const method = 'POST';
final url = Uri.http(uri, path);
final dio = __dio.Dio();
final headers = {'Content-type': 'application/json'};
final body =
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
final credentialsResponse = await dio.post<Object>(url.toString(),
options: __dio.Options(headers: headers, validateStatus: (_) => true));
final authenticate = parsetAuthorizationHeader(
source: credentialsResponse.headers['www-authenticate'].first);
final qop = authenticate['qop'];
final algorithm = 'MD5';
final realm = 'monero-rpc';
final nonce = authenticate['nonce'];
final cnonce = generateCnonce();
final nonceCount = '00000001';
final ha1 = generateHA1(realm: realm, username: login, password: password);
final ha2 = generateHA2(method: method, uri: path);
final response = generateResponseString(
ha1: ha1,
ha2: ha2,
nonce: nonce,
nonceCount: nonceCount,
cnonce: cnonce,
qop: qop);
final authorizationHeaders = {
'Content-type': 'application/json',
'Authorization':
'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
};
return await dio.post<Object>(url.toString(),
options: __dio.Options(headers: authorizationHeaders), data: body);
}
}
-54
View File
@@ -1,54 +0,0 @@
import 'package:encrypt/encrypt.dart';
import 'package:password/password.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
String encrypt({String source, String key, int keyLength = 16}) {
final _key = Key.fromUtf8(key);
final iv = IV.fromLength(keyLength);
final encrypter = Encrypter(AES(_key));
final encrypted = encrypter.encrypt(source, iv: iv);
return encrypted.base64;
}
String decrypt({String source, String key, int keyLength = 16}) {
final _key = Key.fromUtf8(key);
final iv = IV.fromLength(keyLength);
final encrypter = Encrypter(AES(_key));
final decrypted = encrypter.decrypt64(source, iv: iv);
return decrypted;
}
String hash({String source}) {
final algorithm = PBKDF2();
final hash = Password.hash(source, algorithm);
return hash;
}
String encodedPinCode({String pin}) {
final source = '${secrets.salt}$pin';
return encrypt(source: source, key: secrets.key);
}
String decodedPinCode({String pin}) {
final decrypted = decrypt(source: pin, key: secrets.key);
return decrypted.substring(secrets.key.length, decrypted.length);
}
String encodeWalletPassword({String password}) {
final source = password;
final _key = secrets.shortKey + secrets.walletSalt;
return encrypt(source: source, key: _key);
}
String decodeWalletPassword({String password}) {
final source = password;
final _key = secrets.shortKey + secrets.walletSalt;
return decrypt(source: source, key: _key);
}
@@ -1,16 +0,0 @@
import 'package:flutter/foundation.dart';
abstract class EnumerableItem<T> {
const EnumerableItem({@required this.title, @required this.raw});
final T raw;
final String title;
@override
String toString() => title;
}
mixin Serializable<T> on EnumerableItem<T> {
static Serializable deserialize<T>({T raw}) => null;
T serialize() => raw;
}
-37
View File
@@ -1,37 +0,0 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
import 'package:cake_wallet/src/domain/common/currency_formatter.dart';
const fiatApiAuthority = 'fiat-api.cakewallet.com';
const fiatApiPath = '/v1/rates';
Future<double> fetchPriceFor({CryptoCurrency crypto, FiatCurrency fiat}) async {
double price = 0.0;
try {
final fiatStringified = fiat.toString();
final uri =
Uri.https(fiatApiAuthority, fiatApiPath, {'convert': fiatStringified});
final response = await get(uri.toString());
if (response.statusCode != 200) {
return 0.0;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final data = responseJSON['data'] as List<dynamic>;
for (final item in data) {
if (item['symbol'] == cryptoToString(crypto)) {
price = item['quote'][fiatStringified]['price'] as double;
break;
}
}
return price;
} catch (e) {
return price;
}
}
-81
View File
@@ -1,81 +0,0 @@
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
@override
bool operator ==(Object other) => other is FiatCurrency && other.raw == raw;
static const all = [
FiatCurrency.aud,
FiatCurrency.bgn,
FiatCurrency.brl,
FiatCurrency.cad,
FiatCurrency.chf,
FiatCurrency.cny,
FiatCurrency.czk,
FiatCurrency.eur,
FiatCurrency.dkk,
FiatCurrency.gbp,
FiatCurrency.hkd,
FiatCurrency.hrk,
FiatCurrency.huf,
FiatCurrency.idr,
FiatCurrency.ils,
FiatCurrency.inr,
FiatCurrency.isk,
FiatCurrency.jpy,
FiatCurrency.krw,
FiatCurrency.mxn,
FiatCurrency.myr,
FiatCurrency.nok,
FiatCurrency.nzd,
FiatCurrency.php,
FiatCurrency.pln,
FiatCurrency.ron,
FiatCurrency.rub,
FiatCurrency.sek,
FiatCurrency.sgd,
FiatCurrency.thb,
FiatCurrency.usd,
FiatCurrency.zar,
FiatCurrency.vef
];
static const aud = FiatCurrency(symbol: 'AUD');
static const bgn = FiatCurrency(symbol: 'BGN');
static const brl = FiatCurrency(symbol: 'BRL');
static const cad = FiatCurrency(symbol: 'CAD');
static const chf = FiatCurrency(symbol: 'CHF');
static const cny = FiatCurrency(symbol: 'CNY');
static const czk = FiatCurrency(symbol: 'CZK');
static const eur = FiatCurrency(symbol: 'EUR');
static const dkk = FiatCurrency(symbol: 'DKK');
static const gbp = FiatCurrency(symbol: 'GBP');
static const hkd = FiatCurrency(symbol: 'HKD');
static const hrk = FiatCurrency(symbol: 'HRK');
static const huf = FiatCurrency(symbol: 'HUF');
static const idr = FiatCurrency(symbol: 'IDR');
static const ils = FiatCurrency(symbol: 'ILS');
static const inr = FiatCurrency(symbol: 'INR');
static const isk = FiatCurrency(symbol: 'ISK');
static const jpy = FiatCurrency(symbol: 'JPY');
static const krw = FiatCurrency(symbol: 'KRW');
static const mxn = FiatCurrency(symbol: 'MXN');
static const myr = FiatCurrency(symbol: 'MYR');
static const nok = FiatCurrency(symbol: 'NOK');
static const nzd = FiatCurrency(symbol: 'NZD');
static const php = FiatCurrency(symbol: 'PHP');
static const pln = FiatCurrency(symbol: 'PLN');
static const ron = FiatCurrency(symbol: 'RON');
static const rub = FiatCurrency(symbol: 'RUB');
static const sek = FiatCurrency(symbol: 'SEK');
static const sgd = FiatCurrency(symbol: 'SGD');
static const thb = FiatCurrency(symbol: 'THB');
static const usd = FiatCurrency(symbol: 'USD');
static const zar = FiatCurrency(symbol: 'ZAR');
static const vef = FiatCurrency(symbol: 'VEF');
@override
int get hashCode => raw.hashCode ^ title.hashCode;
}
-8
View File
@@ -1,8 +0,0 @@
String formatAmount(String amount) {
if (!amount.contains('.')) {
return amount + '.00';
} else if (amount.endsWith('.')) {
return amount + '00';
}
return amount;
}
-132
View File
@@ -1,132 +0,0 @@
import 'dart:io';
import 'dart:convert';
import 'package:cake_wallet/src/domain/common/contact.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
const reservedNames = ["flutter_assets", "wallets", "db"];
Future<void> migrate_android_v1() async {
final appDocDir = await getApplicationDocumentsDirectory();
await migrate_hives(appDocDir: appDocDir);
await migrate_wallets(appDocDir: appDocDir);
}
Future<void> migrate_ios_v1() async {
final appDocDir = await getApplicationDocumentsDirectory();
}
Future<void> migrate_hives({Directory appDocDir}) async {
final dbDir = Directory('${appDocDir.path}/db');
final files = List<File>();
appDocDir.listSync().forEach((FileSystemEntity item) {
final ext = item.path.split('.').last;
if (item is File && (ext == "hive" || ext == "lock")) {
files.add(item);
}
});
if (!dbDir.existsSync()) {
dbDir.createSync();
}
files.forEach((File hive) {
final name = hive.path.split('/').last;
hive.copySync('${dbDir.path}/$name');
hive.deleteSync();
});
}
Future<void> migrate_wallets({Directory appDocDir}) async {
final walletsDir = Directory('${appDocDir.path}/wallets');
final moneroWalletsDir = Directory('${walletsDir.path}/monero');
final dirs = List<Directory>();
appDocDir.listSync().forEach((FileSystemEntity item) {
final name = item.path.split('/').last;
if (item is Directory && !reservedNames.contains(name)) {
dirs.add(item);
}
});
if (!moneroWalletsDir.existsSync()) {
await moneroWalletsDir.create(recursive: true);
}
dirs.forEach((Directory dir) {
final name = dir.path.split('/').last;
final newDir = Directory('${moneroWalletsDir.path}/$name');
newDir.createSync();
dir.listSync().forEach((file) {
if (file is File) {
final fileName = file.path.split('/').last;
file.copySync('${newDir.path}/$fileName');
file.deleteSync();
}
});
dir.deleteSync();
});
}
Future<void> migrate_ios_wallet_info(
{@required Directory appDocDir,
@required Box<WalletInfo> walletsInfo}) async {
// final walletsDir = Directory('${appDocDir.path}/wallets');
// final moneroWalletsDir = Directory('${walletsDir.path}/monero');
// moneroWalletsDir.listSync().forEach((item) async {
// try {
// if (item is Directory) {
// final name = item.path.split('/').last;
// final configFile = File('${item.path}/$name.json');
// final config =
// json.decode(configFile.readAsStringSync()) as Map<String, dynamic>;
// final isRecovery = config["isRecovery"] as bool ?? false;
// final id =
// walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
// final walletInfo =
// WalletInfo(id: id, name: name, isRecovery: isRecovery);
// await walletsInfo.add(walletInfo);
// }
// } catch (e) {
// print(e.toString());
// }
// });
}
Future<void> migrate_ios_trades_list(
{@required Directory appDocDir, @required Box<Trade> trades}) async {
final adderessBookJSON = File('${appDocDir.path}/trades_list.json');
final List<dynamic> trades =
json.decode(adderessBookJSON.readAsStringSync()) as List<dynamic>;
}
Future<void> migrate_ios_address_book(
{@required Directory appDocDir, @required Box<Contact> contacts}) async {
final adderessBookJSON = File('${appDocDir.path}/address_book.json');
final List<dynamic> addresses =
json.decode(adderessBookJSON.readAsStringSync()) as List<dynamic>;
addresses.forEach((dynamic item) async {
final _item = item as Map<String, dynamic>;
final type = _item["type"] as String;
final address = _item["address"] as String;
final name = _item["name"] as String;
final contact = Contact(
address: address, name: name, type: CryptoCurrency.fromString(type));
await contacts.add(contact);
});
}
@@ -1,23 +0,0 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart';
Future<List<int>> getEncryptionKey(
{String forKey, FlutterSecureStorage secureStorage}) async {
final stringifiedKey =
await secureStorage.read(key: 'transactionDescriptionsBoxKey');
List<int> key;
if (stringifiedKey == null) {
key = Hive.generateSecureKey();
final keyStringified = key.join(',');
await secureStorage.write(
key: 'transactionDescriptionsBoxKey', value: keyStringified);
} else {
key = stringifiedKey
.split(',')
.map((i) => int.parse(i))
.toList();
}
return key;
}
-38
View File
@@ -1,38 +0,0 @@
import 'package:flutter/material.dart';
import 'package:devicelocale/devicelocale.dart';
import 'package:intl/intl.dart';
const Map<String, String> languages = {
'en': 'English',
'de': 'Deutsch (German)',
'es': 'Español (Spanish)',
'hi': 'हिंदी (Hindi)',
'ja': '日本 (Japanese)',
'ko': '한국어 (Korean)',
'nl': 'Nederlands (Dutch)',
'pl': 'Polski (Polish)',
'pt': 'Português (Portuguese)',
'ru': 'Русский (Russian)',
'uk': 'Українська (Ukrainian)',
'zh': '中文 (Chinese)'
};
class Language with ChangeNotifier {
Language(this._currentLanguage);
String _currentLanguage;
String getCurrentLanguage() => _currentLanguage;
void setCurrentLanguage(String language) {
_currentLanguage = language;
notifyListeners();
}
static Future<String> localeDetection() async {
var locale = await Devicelocale.currentLocale;
locale = Intl.shortLocale(locale);
return languages.keys.contains(locale) ? locale : 'en';
}
}
-11
View File
@@ -1,11 +0,0 @@
class MnemonicItem {
MnemonicItem({String text}) : _text = text;
String get text => _text;
String _text;
void changeText(String text) => _text = text;
@override
String toString() => text;
}
-85
View File
@@ -1,85 +0,0 @@
import 'package:cake_wallet/utils/mobx.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/common/digest_request.dart';
part 'node.g.dart';
@HiveType(typeId: 1)
class Node extends HiveObject with Keyable {
Node(
{@required this.uri,
@required WalletType type,
this.login,
this.password}) {
this.type = type;
}
Node.fromMap(Map map)
: uri = map['uri'] as String ?? '',
login = map['login'] as String,
password = map['password'] as String,
typeRaw = map['typeRaw'] as int;
static const boxName = 'Nodes';
@HiveField(0)
String uri;
@HiveField(1)
String login;
@HiveField(2)
String password;
@HiveField(3)
int typeRaw;
WalletType get type => deserializeFromInt(typeRaw);
set type(WalletType type) => typeRaw = serializeToInt(type);
Future<bool> requestNode() async {
try {
switch (type) {
case WalletType.monero:
return requestMoneroNode();
case WalletType.bitcoin:
return requestBitcoinElectrumServer();
default:
return false;
}
} catch (_) {
return false;
}
}
Future<bool> requestMoneroNode() async {
Map<String, dynamic> resBody;
if (login != null && password != null) {
final digestRequest = DigestRequest();
final response = await digestRequest.request(
uri: uri, login: login, password: password);
resBody = response.data as Map<String, dynamic>;
} else {
final url = Uri.http(uri, '/json_rpc');
final headers = {'Content-type': 'application/json'};
final body =
json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'});
final response =
await http.post(url.toString(), headers: headers, body: body);
resBody = json.decode(response.body) as Map<String, dynamic>;
}
return !(resBody['result']['offline'] as bool);
}
Future<bool> requestBitcoinElectrumServer() async {
// FIXME: IMPLEMENT ME
return true;
}
}
-47
View File
@@ -1,47 +0,0 @@
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import "package:yaml/yaml.dart";
import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
Future<List<Node>> loadDefaultNodes() async {
final nodesRaw = await rootBundle.loadString('assets/node_list.yml');
final nodes = loadYaml(nodesRaw) as YamlList;
return nodes.map((dynamic raw) {
if (raw is Map) {
final node = Node.fromMap(raw);
node?.type = WalletType.monero;
return node;
}
return null;
}).toList();
}
Future<List<Node>> loadElectrumServerList() async {
final serverListRaw =
await rootBundle.loadString('assets/electrum_server_list.yml');
final serverList = loadYaml(serverListRaw) as YamlList;
return serverList.map((dynamic raw) {
if (raw is Map) {
final node = Node.fromMap(raw);
node?.type = WalletType.bitcoin;
return node;
}
return null;
}).toList();
}
Future resetToDefault(Box<Node> nodeSource) async {
final moneroNodes = await loadDefaultNodes();
final bitcoinElectrumServerList = await loadElectrumServerList();
final nodes = moneroNodes + bitcoinElectrumServerList;
await nodeSource.clear();
await nodeSource.addAll(nodes);
}
@@ -1,62 +0,0 @@
import 'package:basic_utils/basic_utils.dart';
class OpenaliasRecord {
OpenaliasRecord({this.address, this.name});
final String name;
final String address;
static String formatDomainName(String name) {
String formattedName = name;
if (name.contains("@")) {
formattedName = name.replaceAll("@", ".");
}
return formattedName;
}
static Future<OpenaliasRecord> fetchAddressAndName(String formattedName) async {
String address = formattedName;
String name = formattedName;
if (formattedName.contains(".")) {
try {
final txtRecord = await DnsUtils.lookupRecord(formattedName, RRecordType.TXT, dnssec: true);
if (txtRecord != null) {
for (RRecord element in txtRecord) {
String record = element.data;
if (record.contains("oa1:xmr") && record.contains("recipient_address")) {
record = record.replaceAll('\"', "");
final dataList = record.split(";");
address = dataList.where((item) => (item.contains("recipient_address")))
.toString().replaceAll("oa1:xmr recipient_address=", "")
.replaceAll("(", "").replaceAll(")", "").trim();
final recipientName = dataList.where((item) => (item.contains("recipient_name"))).toString()
.replaceAll("(", "").replaceAll(")", "").trim();
if (recipientName.isNotEmpty) {
name = recipientName.replaceAll("recipient_name=", "");
}
break;
}
}
}
} catch (e) {
print("${e.toString()}");
}
}
return OpenaliasRecord(address: address, name: name);
}
}
@@ -1,3 +0,0 @@
bool parseBoolFromString(String string) {
return string.toString() == 'true';
}
-21
View File
@@ -1,21 +0,0 @@
import 'dart:io';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
Future<String> pathForWalletDir({@required String name, @required WalletType type}) async {
final root = await getApplicationDocumentsDirectory();
final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
if (!walletDire.existsSync()) {
walletDire.createSync(recursive: true);
}
return walletDire.path;
}
Future<String> pathForWallet({@required String name, @required WalletType type}) async =>
await pathForWalletDir(name: name, type: type)
.then((path) => path + '/$name');
@@ -1,25 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cw_monero/transaction_history.dart' as transaction_history;
import 'package:cw_monero/structs/pending_transaction.dart';
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
class PendingTransaction {
PendingTransaction(
{@required this.amount, @required this.fee, @required this.hash});
PendingTransaction.fromTransactionDescription(
PendingTransactionDescription transactionDescription)
: amount = moneroAmountToString(amount: transactionDescription.amount),
fee = moneroAmountToString(amount: transactionDescription.fee),
hash = transactionDescription.hash,
_pointerAddress = transactionDescription.pointerAddress;
final String amount;
final String fee;
final String hash;
int _pointerAddress;
Future<void> commit() async => transaction_history
.commitTransactionFromPointerAddress(address: _pointerAddress);
}
-15
View File
@@ -1,15 +0,0 @@
import 'package:barcode_scan/barcode_scan.dart';
var isQrScannerShown = false;
Future<String> presentQRScanner() async {
isQrScannerShown = true;
try {
final result = await BarcodeScanner.scan();
isQrScannerShown = false;
return result.rawContent;
} catch (e) {
isQrScannerShown = false;
rethrow;
}
}
@@ -1,27 +0,0 @@
enum SecretStoreKey { moneroWalletPassword, pinCodePassword }
const moneroWalletPassword = "MONERO_WALLET_PASSWORD";
const pinCodePassword = "PIN_CODE_PASSWORD";
String generateStoreKeyFor({SecretStoreKey key, String walletName = "",}) {
var _key = "";
switch (key) {
case SecretStoreKey.moneroWalletPassword:
{
_key = moneroWalletPassword + "_" + walletName.toUpperCase();
}
break;
case SecretStoreKey.pinCodePassword:
{
_key = pinCodePassword;
}
break;
default:
{}
}
return _key;
}
-83
View File
@@ -1,83 +0,0 @@
import 'package:cake_wallet/generated/i18n.dart';
abstract class SyncStatus {
const SyncStatus();
double progress();
String title();
}
class SyncingSyncStatus extends SyncStatus {
SyncingSyncStatus(this.blocksLeft, this.ptc);
final double ptc;
final int blocksLeft;
@override
double progress() => ptc;
@override
String title() => S.current.sync_status_syncronizing;
@override
String toString() => '$blocksLeft';
}
class SyncedSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_syncronized;
}
class NotConnectedSyncStatus extends SyncStatus {
const NotConnectedSyncStatus();
@override
double progress() => 0.0;
@override
String title() => S.current.sync_status_not_connected;
}
class StartingSyncStatus extends SyncStatus {
@override
double progress() => 0.0;
@override
String title() => S.current.sync_status_starting_sync;
}
class FailedSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_failed_connect;
}
class ConnectingSyncStatus extends SyncStatus {
@override
double progress() => 0.0;
@override
String title() => S.current.sync_status_connecting;
}
class ConnectedSyncStatus extends SyncStatus {
@override
double progress() => 0.0;
@override
String title() => S.current.sync_status_connected;
}
class LostConnectionSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_failed_connect;
}
-22
View File
@@ -1,22 +0,0 @@
import 'package:hive/hive.dart';
part 'template.g.dart';
@HiveType(typeId: 6)
class Template extends HiveObject {
Template({this.name, this.address, this.cryptoCurrency, this.amount});
static const boxName = 'Template';
@HiveField(0)
String name;
@HiveField(1)
String address;
@HiveField(2)
String cryptoCurrency;
@HiveField(3)
String amount;
}
@@ -1 +0,0 @@
abstract class TransactionCreationCredentials {}
@@ -1,17 +0,0 @@
enum TransactionDirection { incoming, outgoing }
TransactionDirection parseTransactionDirectionFromInt(int raw) {
switch (raw) {
case 0: return TransactionDirection.incoming;
case 1: return TransactionDirection.outgoing;
default: return null;
}
}
TransactionDirection parseTransactionDirectionFromNumber(String raw) {
switch (raw) {
case "0": return TransactionDirection.incoming;
case "1": return TransactionDirection.outgoing;
default: return null;
}
}
@@ -1,8 +0,0 @@
import 'package:rxdart/rxdart.dart';
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
abstract class TransactionHistory {
Observable<List<TransactionInfo>> transactions;
Future<List<TransactionInfo>> getAll();
Future update();
}
@@ -1,14 +0,0 @@
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
abstract class TransactionInfo extends Object {
String id;
int amount;
TransactionDirection direction;
bool isPending;
DateTime date;
int height;
int confirmations;
String amountFormatted();
String fiatAmount();
void changeFiatAmount(String amount);
}
@@ -1,56 +0,0 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
const TransactionPriority({String title, int raw})
: super(title: title, raw: raw);
static const all = [
TransactionPriority.slow,
TransactionPriority.regular,
TransactionPriority.medium,
TransactionPriority.fast,
TransactionPriority.fastest
];
static const slow = TransactionPriority(title: 'Slow', raw: 0);
static const regular = TransactionPriority(title: 'Regular', raw: 1);
static const medium = TransactionPriority(title: 'Medium', raw: 2);
static const fast = TransactionPriority(title: 'Fast', raw: 3);
static const fastest = TransactionPriority(title: 'Fastest', raw: 4);
static const standart = slow;
static TransactionPriority deserialize({int raw}) {
switch (raw) {
case 0:
return slow;
case 1:
return regular;
case 2:
return medium;
case 3:
return fast;
case 4:
return fastest;
default:
return null;
}
}
@override
String toString() {
switch (this) {
case TransactionPriority.slow:
return S.current.transaction_priority_slow;
case TransactionPriority.regular:
return S.current.transaction_priority_regular;
case TransactionPriority.medium:
return S.current.transaction_priority_medium;
case TransactionPriority.fast:
return S.current.transaction_priority_fast;
case TransactionPriority.fastest:
return S.current.transaction_priority_fastest;
default:
return '';
}
}
}
-61
View File
@@ -1,61 +0,0 @@
import 'package:rxdart/rxdart.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/common/transaction_creation_credentials.dart';
import 'package:cake_wallet/src/domain/common/pending_transaction.dart';
import 'package:cake_wallet/src/domain/common/balance.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
abstract class Wallet {
WalletType getType();
WalletType walletType;
Observable<Balance> onBalanceChange;
Observable<SyncStatus> syncStatus;
Observable<String> get onNameChange;
Observable<String> get onAddressChange;
String get name;
String get address;
Future updateInfo();
Future<String> getFilename();
Future<String> getName();
Future<String> getAddress();
Future<String> getSeed();
Future<Map<String, String>> getKeys();
Future<String> getFullBalance();
Future<String> getUnlockedBalance();
Future<int> getCurrentHeight();
Future<int> getNodeHeight();
Future<bool> isConnected();
Future close();
TransactionHistory getHistory();
Future connectToNode({Node node, bool useSSL = false, bool isLightWallet = false});
Future startSync();
Future<PendingTransaction> createTransaction(
TransactionCreationCredentials credentials);
Future rescan({int restoreHeight = 0});
}
@@ -1,8 +0,0 @@
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
class WalletDescription {
WalletDescription({this.name, this.type});
final String name;
final WalletType type;
}
-52
View File
@@ -1,52 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
part 'wallet_info.g.dart';
@HiveType(typeId: 4)
class WalletInfo extends HiveObject {
WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
this.timestamp, this.dirPath, this.path);
factory WalletInfo.external(
{@required String id,
@required String name,
@required WalletType type,
@required bool isRecovery,
@required int restoreHeight,
@required DateTime date,
@required String dirPath,
@required String path}) {
return WalletInfo(id, name, type, isRecovery, restoreHeight,
date.millisecondsSinceEpoch ?? 0, dirPath, path);
}
static const boxName = 'WalletInfo';
@HiveField(0)
String id;
@HiveField(1)
String name;
@HiveField(2)
WalletType type;
@HiveField(3)
bool isRecovery;
@HiveField(4)
int restoreHeight;
@HiveField(5)
int timestamp;
@HiveField(6)
String dirPath;
@HiveField(7)
String path;
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
}
-50
View File
@@ -1,50 +0,0 @@
import 'package:hive/hive.dart';
part 'wallet_type.g.dart';
const walletTypes = [WalletType.monero, WalletType.bitcoin];
@HiveType(typeId: 5)
enum WalletType {
@HiveField(0)
monero,
@HiveField(1)
none,
@HiveField(2)
bitcoin
}
int serializeToInt(WalletType type) {
switch (type) {
case WalletType.monero:
return 0;
case WalletType.bitcoin:
return 1;
default:
return -1;
}
}
WalletType deserializeFromInt(int raw) {
switch (raw) {
case 0:
return WalletType.monero;
case 1:
return WalletType.bitcoin;
default:
return null;
}
}
String walletTypeToString(WalletType type) {
switch (type) {
case WalletType.monero:
return 'Monero';
case WalletType.bitcoin:
return 'Bitcoin';
default:
return '';
}
}
@@ -1,18 +0,0 @@
import 'package:cake_wallet/src/domain/common/wallet.dart';
import 'package:cake_wallet/src/domain/common/wallet_description.dart';
abstract class WalletsManager {
Future<Wallet> create(String name, String password, String language);
Future<Wallet> restoreFromSeed(
String name, String password, String seed, int restoreHeight);
Future<Wallet> restoreFromKeys(String name, String password, String language,
int restoreHeight, String address, String viewKey, String spendKey);
Future<Wallet> openWallet(String name, String password);
Future<bool> isWalletExit(String name);
Future remove(WalletDescription wallet);
}
@@ -1,6 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const dashAmountDivider = 100000000;
double dashAmountToDouble({int amount}) =>
cryptoAmountToDouble(amount: amount, divider: dashAmountDivider);
@@ -1,6 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const ethereumAmountDivider = 1000000000000000000;
double ethereumAmountToDouble({num amount}) =>
cryptoAmountToDouble(amount: amount, divider: ethereumAmountDivider);
@@ -1,163 +0,0 @@
import 'dart:convert';
import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_pair.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/limits.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/trade_state.dart';
import 'package:cake_wallet/src/domain/exchange/changenow/changenow_request.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
class ChangeNowExchangeProvider extends ExchangeProvider {
ChangeNowExchangeProvider()
: super(
pairList: CryptoCurrency.all
.map((i) {
return CryptoCurrency.all.map((k) {
if (i == CryptoCurrency.btc && k == CryptoCurrency.xmr) {
return ExchangePair(from: i, to: k, reverse: false);
}
if (i == CryptoCurrency.xmr && k == CryptoCurrency.btc) {
return null;
}
return ExchangePair(from: i, to: k, reverse: true);
}).where((c) => c != null);
})
.expand((i) => i)
.toList());
static const apiUri = 'https://changenow.io/api/v1';
static const apiKey = secrets.change_now_api_key;
static const _exchangeAmountUriSufix = '/exchange-amount/';
static const _transactionsUriSufix = '/transactions/';
static const _minAmountUriSufix = '/min-amount/';
@override
String get title => 'ChangeNOW';
@override
ExchangeProviderDescription get description =>
ExchangeProviderDescription.changeNow;
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
final symbol = from.toString() + '_' + to.toString();
final url = apiUri + _minAmountUriSufix + symbol;
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final min = responseJSON['minAmount'] as double;
return Limits(min: min, max: null);
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
const url = apiUri + _transactionsUriSufix + apiKey;
final _request = request as ChangeNowRequest;
final body = {
'from': _request.from.toString(),
'to': _request.to.toString(),
'address': _request.address,
'amount': _request.amount,
'refundAddress': _request.refundAddress
};
final response = await post(url,
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
if (response.statusCode != 200) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['message'] as String;
throw TradeNotCreatedException(description, description: error);
}
throw TradeNotCreatedException(description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String;
final inputAddress = responseJSON['payinAddress'] as String;
final refundAddress = responseJSON['refundAddress'] as String;
final extraId = responseJSON['payinExtraId'] as String;
return Trade(
id: id,
from: _request.from,
to: _request.to,
provider: description,
inputAddress: inputAddress,
refundAddress: refundAddress,
extraId: extraId,
createdAt: DateTime.now(),
amount: _request.amount,
state: TradeState.created);
}
@override
Future<Trade> findTradeById({@required String id}) async {
final url = apiUri + _transactionsUriSufix + id + '/' + apiKey;
final response = await get(url);
if (response.statusCode != 200) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['message'] as String;
throw TradeNotFoundException(id,
provider: description, description: error);
}
throw TradeNotFoundException(id, provider: description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['fromCurrency'] as String;
final from = CryptoCurrency.fromString(fromCurrency);
final toCurrency = responseJSON['toCurrency'] as String;
final to = CryptoCurrency.fromString(toCurrency);
final inputAddress = responseJSON['payinAddress'] as String;
final expectedSendAmount = responseJSON['expectedSendAmount'].toString();
final status = responseJSON['status'] as String;
final state = TradeState.deserialize(raw: status);
final extraId = responseJSON['payinExtraId'] as String;
final outputTransaction = responseJSON['payoutHash'] as String;
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,
state: state,
extraId: extraId,
outputTransaction: outputTransaction);
}
@override
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
final url = apiUri +
_exchangeAmountUriSufix +
amount.toString() +
'/' +
from.toString() +
'_' +
to.toString();
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final estimatedAmount = responseJSON['estimatedAmount'] as double;
return estimatedAmount;
}
}
@@ -1,18 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
class ChangeNowRequest extends TradeRequest {
ChangeNowRequest(
{@required this.from,
@required this.to,
@required this.address,
@required this.amount,
@required this.refundAddress});
CryptoCurrency from;
CryptoCurrency to;
String address;
String amount;
String refundAddress;
}
@@ -1,9 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
class ExchangePair {
ExchangePair({this.from, this.to, this.reverse = true});
final CryptoCurrency from;
final CryptoCurrency to;
final bool reverse;
}
@@ -1,24 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_pair.dart';
import 'package:cake_wallet/src/domain/exchange/limits.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
abstract class ExchangeProvider {
ExchangeProvider({this.pairList});
String get title;
List<ExchangePair> pairList;
ExchangeProviderDescription description;
@override
String toString() => title;
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to});
Future<Trade> createTrade({TradeRequest request});
Future<Trade> findTradeById({@required String id});
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount});
}
@@ -1,26 +0,0 @@
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
class ExchangeProviderDescription extends EnumerableItem<int>
with Serializable<int> {
const ExchangeProviderDescription({String title, int raw})
: super(title: title, raw: raw);
static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0);
static const changeNow =
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1);
static const morphToken =
ExchangeProviderDescription(title: 'MorphToken', raw: 2);
static ExchangeProviderDescription deserialize({int raw}) {
switch (raw) {
case 0:
return xmrto;
case 1:
return changeNow;
case 2:
return morphToken;
default:
return null;
}
}
}
@@ -1,35 +0,0 @@
import 'package:hive/hive.dart';
part 'exchange_template.g.dart';
@HiveType(typeId: 7)
class ExchangeTemplate extends HiveObject {
ExchangeTemplate({
this.amount,
this.depositCurrency,
this.receiveCurrency,
this.provider,
this.depositAddress,
this.receiveAddress
});
static const boxName = 'ExchangeTemplate';
@HiveField(0)
String amount;
@HiveField(1)
String depositCurrency;
@HiveField(2)
String receiveCurrency;
@HiveField(3)
String provider;
@HiveField(4)
String depositAddress;
@HiveField(5)
String receiveAddress;
}
-6
View File
@@ -1,6 +0,0 @@
class Limits {
const Limits({this.min, this.max});
final double min;
final double max;
}
@@ -1,241 +0,0 @@
import 'dart:convert';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_pair.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/limits.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/trade_state.dart';
import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_request.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
import 'package:cake_wallet/src/domain/bitcoin/bitcoin_amount_format.dart';
import 'package:cake_wallet/src/domain/bitcoin_cash/bitcoin_cash_amount_format.dart';
import 'package:cake_wallet/src/domain/dash/dash_amount_format.dart';
import 'package:cake_wallet/src/domain/ethereum/ethereum_amount_format.dart';
import 'package:cake_wallet/src/domain/litecoin/litecoin_amount_format.dart';
class MorphTokenExchangeProvider extends ExchangeProvider {
MorphTokenExchangeProvider({@required this.trades})
: super(
pairList: [
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.eth),
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.bch),
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.ltc),
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.dash),
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.btc),
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.eth),
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.bch),
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.ltc),
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.xmr),
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.btc),
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.eth),
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.bch),
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.dash),
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.xmr),
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.btc),
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.eth),
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.ltc),
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.dash),
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.xmr),
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.btc),
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.bch),
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.ltc),
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.dash),
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.xmr),
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.eth),
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.bch),
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.ltc),
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.dash),
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.xmr)
]);
Box<Trade> trades;
static const apiUri = 'https://api.morphtoken.com';
static const _morphURISuffix = '/morph';
static const _limitsURISuffix = '/limits';
static const _ratesURISuffix = '/rates';
static const weight = 10000;
@override
String get title => 'MorphToken';
@override
ExchangeProviderDescription get description =>
ExchangeProviderDescription.morphToken;
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
final url = apiUri + _limitsURISuffix;
final headers = {'Content-type': 'application/json'};
final body =
json.encode({
"input": {
"asset": from.toString()
},
"output": [{
"asset": to.toString(),
"weight": weight
}]});
final response =
await post(url, headers: headers, body: body);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final min = responseJSON['input']['limits']['min'] as int;
int max;
double ethMax;
if (from == CryptoCurrency.eth) {
ethMax = responseJSON['input']['limits']['max'] as double;
} else {
max = responseJSON['input']['limits']['max'] as int;
}
double minFormatted;
double maxFormatted;
switch (from) {
case CryptoCurrency.xmr:
minFormatted = moneroAmountToDouble(amount: min);
maxFormatted = moneroAmountToDouble(amount: max);
break;
case CryptoCurrency.btc:
minFormatted = bitcoinAmountToDouble(amount: min);
maxFormatted = bitcoinAmountToDouble(amount: max);
break;
case CryptoCurrency.bch:
minFormatted = bitcoinCashAmountToDouble(amount: min);
maxFormatted = bitcoinCashAmountToDouble(amount: max);
break;
case CryptoCurrency.dash:
minFormatted = dashAmountToDouble(amount: min);
maxFormatted = dashAmountToDouble(amount: max);
break;
case CryptoCurrency.eth:
minFormatted = ethereumAmountToDouble(amount: min);
maxFormatted = ethereumAmountToDouble(amount: ethMax);
break;
case CryptoCurrency.ltc:
minFormatted = litecoinAmountToDouble(amount: min);
maxFormatted = litecoinAmountToDouble(amount: max);
break;
}
return Limits(min: minFormatted, max: maxFormatted);
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
const url = apiUri + _morphURISuffix;
final _request = request as MorphTokenRequest;
final body = {
"input": {
"asset": _request.from.toString(),
"refund": _request.refundAddress
},
"output": [{
"asset": _request.to.toString(),
"weight": weight,
"address": _request.address
}],
"tag": "cakewallet"
};
final response = await post(url,
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
if (response.statusCode != 200) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['description'] as String;
throw TradeNotCreatedException(description, description: error);
}
throw TradeNotCreatedException(description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String;
return Trade(
id: id,
provider: description,
from: _request.from,
to: _request.to,
state: TradeState.created,
amount: _request.amount,
createdAt: DateTime.now());
}
@override
Future<Trade> findTradeById({@required String id}) async {
final url = apiUri + _morphURISuffix + '/' + id;
final response = await get(url);
if (response.statusCode != 200) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['description'] as String;
throw TradeNotFoundException(id,
provider: description, description: error);
}
throw TradeNotFoundException(id, provider: description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['input']['asset'] as String;
final from = CryptoCurrency.fromString(fromCurrency.toLowerCase());
final toCurrency = responseJSON['output'][0]['asset'] as String;
final to = CryptoCurrency.fromString(toCurrency.toLowerCase());
final inputAddress = responseJSON['input']['deposit_address'] as String;
final status = responseJSON['state'] as String;
final state = TradeState.deserialize(raw: status.toLowerCase());
String amount = "";
for (final trade in trades.values) {
if (trade.id == id) {
amount = trade.amount;
break;
}
}
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: amount,
state: state);
}
@override
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
final url = apiUri + _ratesURISuffix;
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final rate = responseJSON['data'][from.toString()][to.toString()] as String;
try {
final estimatedAmount = double.parse(rate) * amount;
return estimatedAmount;
} catch(e) {
return 0.0;
}
}
}
@@ -1,18 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
class MorphTokenRequest extends TradeRequest {
MorphTokenRequest(
{@required this.from,
@required this.to,
@required this.address,
@required this.amount,
@required this.refundAddress});
CryptoCurrency from;
CryptoCurrency to;
String address;
String amount;
String refundAddress;
}
-107
View File
@@ -1,107 +0,0 @@
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/trade_state.dart';
import 'package:cake_wallet/src/domain/common/format_amount.dart';
part 'trade.g.dart';
@HiveType(typeId: 3)
class Trade extends HiveObject {
Trade(
{this.id,
ExchangeProviderDescription provider,
CryptoCurrency from,
CryptoCurrency to,
TradeState state,
this.createdAt,
this.expiredAt,
this.amount,
this.inputAddress,
this.extraId,
this.outputTransaction,
this.refundAddress,
this.walletId})
: providerRaw = provider?.raw,
fromRaw = from?.raw,
toRaw = to?.raw,
stateRaw = state?.raw;
static const boxName = 'Trades';
@HiveField(0)
String id;
@HiveField(1)
int providerRaw;
ExchangeProviderDescription get provider =>
ExchangeProviderDescription.deserialize(raw: providerRaw);
@HiveField(2)
int fromRaw;
CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw);
@HiveField(3)
int toRaw;
CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw);
@HiveField(4)
String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw);
@HiveField(5)
DateTime createdAt;
@HiveField(6)
DateTime expiredAt;
@HiveField(7)
String amount;
@HiveField(8)
String inputAddress;
@HiveField(9)
String extraId;
@HiveField(10)
String outputTransaction;
@HiveField(11)
String refundAddress;
@HiveField(12)
String walletId;
static Trade fromMap(Map map) {
return Trade(
id: map['id'] as String,
provider: ExchangeProviderDescription.deserialize(
raw: map['provider'] as int),
from: CryptoCurrency.deserialize(raw: map['input'] as int),
to: CryptoCurrency.deserialize(raw: map['output'] as int),
createdAt: map['date'] != null
? DateTime.fromMillisecondsSinceEpoch(map['date'] as int)
: null,
amount: map['amount'] as String,
walletId: map['wallet_id'] as String);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'provider': provider.serialize(),
'input': from.serialize(),
'output': to.serialize(),
'date': createdAt != null ? createdAt.millisecondsSinceEpoch : null,
'amount': amount,
'wallet_id': walletId
};
}
String amountFormatted() => formatAmount(amount);
}
@@ -1,19 +0,0 @@
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/generated/i18n.dart';
class TradeNotCreatedException implements Exception {
TradeNotCreatedException(this.provider, {this.description = ''});
ExchangeProviderDescription provider;
String description;
@override
String toString() {
var text = provider != null
? S.current.trade_for_not_created(provider.title)
: S.current.trade_not_created;
text += ' $description';
return text;
}
}
@@ -1,20 +0,0 @@
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/generated/i18n.dart';
class TradeNotFoundException implements Exception {
TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
String tradeId;
ExchangeProviderDescription provider;
String description;
@override
String toString() {
var text = tradeId != null && provider != null
? S.current.trade_id_not_found(tradeId, provider.title)
: S.current.trade_not_found;
text += ' $description';
return text;
}
}
@@ -1 +0,0 @@
abstract class TradeRequest {}
-72
View File
@@ -1,72 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
class TradeState extends EnumerableItem<String> with Serializable<String> {
const TradeState({@required String raw, @required String title})
: super(raw: raw, title: title);
@override
bool operator ==(Object other) => other is TradeState && other.raw == raw;
static const pending = TradeState(raw: 'pending', title: 'Pending');
static const confirming = TradeState(raw: 'confirming', title: 'Confirming');
static const trading = TradeState(raw: 'trading', title: 'Trading');
static const traded = TradeState(raw: 'traded', title: 'Traded');
static const complete = TradeState(raw: 'complete', title: 'Complete');
static const toBeCreated =
TradeState(raw: 'TO_BE_CREATED', title: 'To be created');
static const unpaid = TradeState(raw: 'UNPAID', title: 'Unpaid');
static const underpaid = TradeState(raw: 'UNDERPAID', title: 'Underpaid');
static const paidUnconfirmed =
TradeState(raw: 'PAID_UNCONFIRMED', title: 'Paid unconfirmed');
static const paid = TradeState(raw: 'PAID', title: 'Paid');
static const btcSent = TradeState(raw: 'BTC_SENT', title: 'Btc sent');
static const timeout = TradeState(raw: 'TIMED_OUT', title: 'Timeout');
static const notFound = TradeState(raw: 'NOT_FOUND', title: 'Not found');
static const created = TradeState(raw: 'created', title: 'Created');
static const finished = TradeState(raw: 'finished', title: 'Finished');
static const waiting = TradeState(raw: 'waiting', title: 'Waiting');
static const processing = TradeState(raw: 'processing', title: 'Processing');
static TradeState deserialize({String raw}) {
switch (raw) {
case 'pending':
return pending;
case 'confirming':
return confirming;
case 'trading':
return trading;
case 'traded':
return traded;
case 'complete':
return complete;
case 'TO_BE_CREATED':
return toBeCreated;
case 'UNPAID':
return unpaid;
case 'UNDERPAID':
return underpaid;
case 'PAID_UNCONFIRMED':
return paidUnconfirmed;
case 'PAID':
return paid;
case 'BTC_SENT':
return btcSent;
case 'TIMED_OUT':
return timeout;
case 'created':
return created;
case 'finished':
return finished;
case 'waiting':
return waiting;
case 'processing':
return processing;
default:
return null;
}
}
@override
int get hashCode => raw.hashCode ^ title.hashCode;
}
@@ -1,198 +0,0 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_pair.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/limits.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/trade_state.dart';
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
class XMRTOExchangeProvider extends ExchangeProvider {
XMRTOExchangeProvider()
: super(pairList: [
ExchangePair(
from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
]);
static const userAgent = 'CakeWallet/XMR iOS';
static const originalApiUri = 'https://xmr.to/api/v2/xmr2btc';
static const proxyApiUri = 'https://xmrproxy.net/api/v2/xmr2btc';
static const _orderParameterUriSufix = '/order_parameter_query';
static const _orderStatusUriSufix = '/order_status_query/';
static const _orderCreateUriSufix = '/order_create/';
static String _apiUri = '';
static Future<String> getApiUri() async {
if (_apiUri != null && _apiUri.isNotEmpty) {
return _apiUri;
}
const url = originalApiUri + _orderParameterUriSufix;
final response =
await get(url, headers: {'Content-Type': 'application/json'});
_apiUri = response.statusCode == 403 ? proxyApiUri : originalApiUri;
return _apiUri;
}
@override
String get title => 'XMR.TO';
@override
ExchangeProviderDescription get description =>
ExchangeProviderDescription.xmrto;
double _rate = 0;
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
final url = await getApiUri() + _orderParameterUriSufix;
final response = await get(url);
final correction = 0.001;
if (response.statusCode != 200) {
return Limits(min: 0, max: 0);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
double min = responseJSON['lower_limit'] as double;
double max = responseJSON['upper_limit'] as double;
final price = responseJSON['price'] as double;
if (price > 0) {
try {
min = min/price + correction;
min = _limitsFormat(min);
max = max/price - correction;
max = _limitsFormat(max);
} catch (e) {
min = 0;
max = 0;
}
} else {
min = 0;
max = 0;
}
return Limits(min: min, max: max);
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
final _request = request as XMRTOTradeRequest;
final url = await getApiUri() + _orderCreateUriSufix;
final body = {
'xmr_amount': _request.amount,
'btc_dest_address': _request.address
};
final response = await post(url,
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
if (response.statusCode != 201) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error_msg'] as String;
throw TradeNotCreatedException(description, description: error);
}
throw TradeNotCreatedException(description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final uuid = responseJSON["uuid"] as String;
return Trade(
id: uuid,
provider: description,
from: _request.from,
to: _request.to,
state: TradeState.created,
amount: _request.amount,
createdAt: DateTime.now());
}
@override
Future<Trade> findTradeById({@required String id}) async {
const headers = {
'Content-Type': 'application/json',
'User-Agent': userAgent
};
final url = await getApiUri() + _orderStatusUriSufix;
final body = {'uuid': id};
final response = await post(url, headers: headers, body: json.encode(body));
if (response.statusCode != 200) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error_msg'] as String;
throw TradeNotFoundException(id,
provider: description, description: error);
}
throw TradeNotFoundException(id, provider: description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final address = responseJSON['xmr_receiving_integrated_address'] as String;
final paymentId = responseJSON['xmr_required_payment_id_short'] as String;
final amount = responseJSON['xmr_amount_total'].toString();
final stateRaw = responseJSON['state'] as String;
final expiredAtRaw = responseJSON['expires_at'] as String;
final expiredAt = DateTime.parse(expiredAtRaw).toLocal();
final outputTransaction = responseJSON['btc_transaction_id'] as String;
final state = TradeState.deserialize(raw: stateRaw);
return Trade(
id: id,
provider: description,
from: CryptoCurrency.xmr,
to: CryptoCurrency.btc,
inputAddress: address,
extraId: paymentId,
expiredAt: expiredAt,
amount: amount,
state: state,
outputTransaction: outputTransaction);
}
@override
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
return 0;
}
if (_rate == null || _rate == 0) {
_rate = await _fetchRates();
}
final double result = _rate * amount;
return double.parse(result.toStringAsFixed(12));
}
Future<double> _fetchRates() async {
try {
final url = await getApiUri() + _orderParameterUriSufix;
final response =
await get(url, headers: {'Content-Type': 'application/json'});
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final price = responseJSON['price'] as double;
return price;
} catch (e) {
print(e.toString());
return 0.0;
}
}
double _limitsFormat(double limit) => double.parse(limit.toStringAsFixed(3));
}
@@ -1,18 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
class XMRTOTradeRequest extends TradeRequest {
XMRTOTradeRequest(
{@required this.from,
@required this.to,
@required this.amount,
@required this.address,
@required this.refundAddress});
final CryptoCurrency from;
final CryptoCurrency to;
final String amount;
final String address;
final String refundAddress;
}
@@ -1,6 +0,0 @@
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const litecoinAmountDivider = 100000000;
double litecoinAmountToDouble({int amount}) =>
cryptoAmountToDouble(amount: amount, divider: litecoinAmountDivider);
-16
View File
@@ -1,16 +0,0 @@
import 'package:cw_monero/structs/account_row.dart';
class Account {
Account({this.id, this.label});
Account.fromMap(Map map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.label = (map['label'] ?? '') as String;
Account.fromRow(AccountRow row)
: this.id = row.getId(),
this.label = row.getLabel();
final int id;
final String label;
}
-68
View File
@@ -1,68 +0,0 @@
import 'package:rxdart/rxdart.dart';
import 'package:cw_monero/account_list.dart' as account_list;
import 'package:cake_wallet/src/domain/monero/account.dart';
class AccountList {
AccountList() {
_isRefreshing = false;
_isUpdating = false;
_accounts = BehaviorSubject<List<Account>>();
}
Observable<List<Account>> get accounts => _accounts.stream;
BehaviorSubject<List<Account>> _accounts;
bool _isRefreshing;
bool _isUpdating;
Future update() async {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh();
final accounts = getAll();
_accounts.add(accounts);
_isUpdating = false;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
List<Account> getAll() {
return account_list
.getAllAccount()
.map((accountRow) => Account.fromRow(accountRow))
.toList();
}
Future addAccount({String label}) async {
await account_list.addAccount(label: label);
await update();
}
Future setLabelSubaddress({int accountIndex, String label}) async {
await account_list.setLabelForAccount(
accountIndex: accountIndex, label: label);
await update();
}
void refresh() {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
account_list.refreshAccounts();
_isRefreshing = false;
} catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}
@@ -1,102 +0,0 @@
import 'package:intl/intl.dart';
final dateFormat = DateFormat('yyyy-MM');
final dates = {
"2014-5": 18844,
"2014-6": 65406,
"2014-7": 108882,
"2014-8": 153594,
"2014-9": 198072,
"2014-10": 241088,
"2014-11": 285305,
"2014-12": 328069,
"2015-1": 372369,
"2015-2": 416505,
"2015-3": 456631,
"2015-4": 501084,
"2015-5": 543973,
"2015-6": 588326,
"2015-7": 631187,
"2015-8": 675484,
"2015-9": 719725,
"2015-10": 762463,
"2015-11": 806528,
"2015-12": 849041,
"2016-1": 892866,
"2016-2": 936736,
"2016-3": 977691,
"2016-4": 1015848,
"2016-5": 1037417,
"2016-6": 1059651,
"2016-7": 1081269,
"2016-8": 1103630,
"2016-9": 1125983,
"2016-10": 1147617,
"2016-11": 1169779,
"2016-12": 1191402,
"2017-1": 1213861,
"2017-2": 1236197,
"2017-3": 1256358,
"2017-4": 1278622,
"2017-5": 1300239,
"2017-6": 1322564,
"2017-7": 1344225,
"2017-8": 1366664,
"2017-9": 1389113,
"2017-10": 1410738,
"2017-11": 1433039,
"2017-12": 1454639,
"2018-1": 1477201,
"2018-2": 1499599,
"2018-3": 1519796,
"2018-4": 1542067,
"2018-5": 1562861,
"2018-6": 1585135,
"2018-7": 1606715,
"2018-8": 1629017,
"2018-9": 1651347,
"2018-10": 1673031,
"2018-11": 1695128,
"2018-12": 1716687,
"2019-1": 1738923,
"2019-2": 1761435,
"2019-3": 1781681,
"2019-4": 1803081,
"2019-5": 1824671,
"2019-6": 1847005,
"2019-7": 1868590,
"2019-8": 1888590,
"2019-9": 1898590,
};
int getHeigthByDate({DateTime date}) {
final raw = '${date.year}' + '-' + '${date.month}';
var endHeight = dates[raw] ?? 0;
int preLastYear = date.year;
int preLastMonth = date.month - 1;
if (endHeight <= 0) {
endHeight = dates.values.toList()[dates.length - 1];
final preLastDate =
dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
preLastYear = preLastDate.year;
preLastMonth = preLastDate.month;
} else {
preLastYear = date.year;
preLastMonth = date.month - 1;
}
if (preLastMonth <= 0) {
preLastMonth = 12;
preLastYear -= 1;
}
final startRaw = '$preLastYear' + '-' + '$preLastMonth';
final startHeight = dates[startRaw];
final diff = endHeight - startHeight;
final heightPerDay = diff / 30;
final daysHeight = date.day * heightPerDay.round();
final height = endHeight + daysHeight;
return height;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,15 +0,0 @@
import 'package:intl/intl.dart';
import 'package:cake_wallet/src/domain/common/crypto_amount_format.dart';
const moneroAmountLength = 12;
const moneroAmountDivider = 1000000000000;
final moneroAmountFormat = NumberFormat()
..maximumFractionDigits = moneroAmountLength
..minimumFractionDigits = 1;
String moneroAmountToString({int amount}) =>
moneroAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
double moneroAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
int moneroParseAmount({String amount}) => moneroAmountFormat.parse(amount).toInt();
@@ -1,9 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/src/domain/common/balance.dart';
class MoneroBalance extends Balance {
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance});
final String fullBalance;
final String unlockedBalance;
}
@@ -1,13 +0,0 @@
import 'package:cake_wallet/src/domain/common/transaction_creation_credentials.dart';
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
class MoneroTransactionCreationCredentials
extends TransactionCreationCredentials {
MoneroTransactionCreationCredentials(
{this.address, this.paymentId, this.priority, this.amount});
final String address;
final String paymentId;
final String amount;
final TransactionPriority priority;
}
@@ -1,70 +0,0 @@
import 'dart:core';
import 'package:cake_wallet/src/domain/monero/monero_transaction_info.dart';
import 'package:flutter/services.dart';
import 'package:rxdart/rxdart.dart';
import 'package:cw_monero/transaction_history.dart'
as monero_transaction_history;
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
List<TransactionInfo> _getAllTransactions(dynamic _) =>
monero_transaction_history
.getAllTransations()
.map((row) => MoneroTransactionInfo.fromRow(row))
.toList();
class MoneroTransactionHistory extends TransactionHistory {
MoneroTransactionHistory()
: _transactions = BehaviorSubject<List<TransactionInfo>>.seeded([]);
@override
Observable<List<TransactionInfo>> get transactions => _transactions.stream;
final BehaviorSubject<List<TransactionInfo>> _transactions;
bool _isUpdating = false;
bool _isRefreshing = false;
bool _needToCheckForRefresh = false;
@override
Future update() async {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
_transactions.value = await getAll(force: true);
_isUpdating = false;
if (!_needToCheckForRefresh) {
_needToCheckForRefresh = true;
}
} catch (e) {
_isUpdating = false;
print(e);
rethrow;
}
}
@override
Future<List<TransactionInfo>> getAll({bool force = false}) async {
await refresh();
return _getAllTransactions(null);
}
Future refresh() async {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
monero_transaction_history.refreshTransactions();
_isRefreshing = false;
} on PlatformException catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}
@@ -1,50 +0,0 @@
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
import 'package:cw_monero/structs/transaction_info_row.dart';
import 'package:cake_wallet/src/domain/common/parseBoolFromString.dart';
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
import 'package:cake_wallet/src/domain/common/format_amount.dart';
class MoneroTransactionInfo extends TransactionInfo {
MoneroTransactionInfo(this.id, this.height, this.direction, this.date,
this.isPending, this.amount, this.accountIndex);
MoneroTransactionInfo.fromMap(Map map)
: id = (map['hash'] ?? '') as String,
height = (map['height'] ?? 0) as int,
direction =
parseTransactionDirectionFromNumber(map['direction'] as String) ??
TransactionDirection.incoming,
date = DateTime.fromMillisecondsSinceEpoch(
(int.parse(map['timestamp'] as String) ?? 0) * 1000),
isPending = parseBoolFromString(map['isPending'] as String),
amount = map['amount'] as int,
accountIndex = int.parse(map['accountIndex'] as String);
MoneroTransactionInfo.fromRow(TransactionInfoRow row)
: id = row.getHash(),
height = row.blockHeight,
direction = parseTransactionDirectionFromInt(row.direction) ??
TransactionDirection.incoming,
date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
isPending = row.isPending != 0,
amount = row.getAmount(),
accountIndex = row.subaddrAccount;
final String id;
final int height;
final TransactionDirection direction;
final DateTime date;
final int accountIndex;
final bool isPending;
final int amount;
String recipientAddress;
String _fiatAmount;
String amountFormatted() => '${formatAmount(moneroAmountToString(amount: amount))} XMR';
String fiatAmount() => _fiatAmount ?? '';
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
}
-421
View File
@@ -1,421 +0,0 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import 'package:rxdart/rxdart.dart';
import 'package:cw_monero/wallet.dart' as monero_wallet;
import 'package:cw_monero/transaction_history.dart' as transaction_history;
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
import 'package:cake_wallet/src/domain/common/wallet.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
import 'package:cake_wallet/src/domain/common/transaction_creation_credentials.dart';
import 'package:cake_wallet/src/domain/common/pending_transaction.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
import 'package:cake_wallet/src/domain/monero/account.dart';
import 'package:cake_wallet/src/domain/monero/account_list.dart';
import 'package:cake_wallet/src/domain/monero/subaddress_list.dart';
import 'package:cake_wallet/src/domain/monero/monero_transaction_creation_credentials.dart';
import 'package:cake_wallet/src/domain/monero/monero_transaction_history.dart';
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
import 'package:cake_wallet/src/domain/common/balance.dart';
import 'package:cake_wallet/src/domain/monero/monero_balance.dart';
const moneroBlockSize = 1000;
class MoneroWallet extends Wallet {
MoneroWallet({this.walletInfoSource, this.walletInfo}) {
_cachedBlockchainHeight = 0;
_isSaving = false;
_lastSaveTime = 0;
_lastRefreshTime = 0;
_refreshHeight = 0;
_lastSyncHeight = 0;
_name = BehaviorSubject<String>();
_address = BehaviorSubject<String>();
_syncStatus = BehaviorSubject<SyncStatus>();
_onBalanceChange = BehaviorSubject<MoneroBalance>();
_account = BehaviorSubject<Account>()..add(Account(id: 0));
_subaddress = BehaviorSubject<Subaddress>();
setListeners();
}
static Future<MoneroWallet> createdWallet(
{Box<WalletInfo> walletInfoSource,
String name,
bool isRecovery = false,
int restoreHeight = 0}) async {
// const type = WalletType.monero;
// final id = walletTypeToString(type).toLowerCase() + '_' + name;
// final walletInfo = WalletInfo(
// id: id,
// name: name,
// type: type,
// isRecovery: isRecovery,
// restoreHeight: restoreHeight);
// await walletInfoSource.add(walletInfo);
// return await configured(
// walletInfo: walletInfo, walletInfoSource: walletInfoSource);
return null;
}
static Future<MoneroWallet> load(
Box<WalletInfo> walletInfoSource, String name, WalletType type) async {
final id = walletTypeToString(type).toLowerCase() + '_' + name;
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == id, orElse: () => null);
return await configured(
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
}
static Future<MoneroWallet> configured(
{@required Box<WalletInfo> walletInfoSource,
@required WalletInfo walletInfo}) async {
final wallet = MoneroWallet(
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
if (walletInfo.isRecovery) {
wallet.setRecoveringFromSeed();
if (walletInfo.restoreHeight != null) {
wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
}
}
return wallet;
}
@override
String get address => _address.value;
@override
String get name => _name.value;
@override
WalletType getType() => WalletType.monero;
@override
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
@override
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
@override
Observable<String> get onNameChange => _name.stream;
@override
Observable<String> get onAddressChange => _address.stream;
Observable<Account> get onAccountChange => _account.stream;
Observable<Subaddress> get subaddress => _subaddress.stream;
bool get isRecovery => walletInfo.isRecovery;
Account get account => _account.value;
Box<WalletInfo> walletInfoSource;
WalletInfo walletInfo;
BehaviorSubject<Account> _account;
BehaviorSubject<MoneroBalance> _onBalanceChange;
BehaviorSubject<SyncStatus> _syncStatus;
BehaviorSubject<String> _name;
BehaviorSubject<String> _address;
BehaviorSubject<Subaddress> _subaddress;
int _cachedBlockchainHeight;
bool _isSaving;
int _lastSaveTime;
int _lastRefreshTime;
int _refreshHeight;
int _lastSyncHeight;
TransactionHistory _cachedTransactionHistory;
SubaddressList _cachedSubaddressList;
AccountList _cachedAccountList;
@override
Future updateInfo() async {
_name.value = await getName();
final acccountList = getAccountList()..refresh();
_account.value = acccountList.getAll().first;
final subaddressList = getSubaddress();
subaddressList.refresh(
accountIndex: _account.value != null ? _account.value.id : 0);
final subaddresses = subaddressList.getAll();
_subaddress.value = subaddresses.first;
_address.value = await getAddress();
}
@override
Future<String> getFilename() async => monero_wallet.getFilename();
@override
Future<String> getName() async => getFilename()
.then((filename) => filename.split('/'))
.then((splitted) => splitted.last);
@override
Future<String> getAddress() async => monero_wallet.getAddress(
accountIndex: _account.value.id, addressIndex: _subaddress.value.id);
@override
Future<String> getSeed() async => monero_wallet.getSeed();
@override
Future<String> getFullBalance() async => moneroAmountToString(
amount: monero_wallet.getFullBalance(accountIndex: _account.value.id));
@override
Future<String> getUnlockedBalance() async => moneroAmountToString(
amount:
monero_wallet.getUnlockedBalance(accountIndex: _account.value.id));
@override
Future<int> getCurrentHeight() async => monero_wallet.getCurrentHeight();
@override
Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
@override
Future<bool> isConnected() async => monero_wallet.isConnected();
@override
Future<Map<String, String>> getKeys() async => {
'publicViewKey': monero_wallet.getPublicViewKey(),
'privateViewKey': monero_wallet.getSecretViewKey(),
'publicSpendKey': monero_wallet.getPublicSpendKey(),
'privateSpendKey': monero_wallet.getSecretSpendKey()
};
@override
TransactionHistory getHistory() {
if (_cachedTransactionHistory == null) {
_cachedTransactionHistory = MoneroTransactionHistory();
}
return _cachedTransactionHistory;
}
SubaddressList getSubaddress() {
if (_cachedSubaddressList == null) {
_cachedSubaddressList = SubaddressList();
}
return _cachedSubaddressList;
}
AccountList getAccountList() {
if (_cachedAccountList == null) {
_cachedAccountList = AccountList();
}
return _cachedAccountList;
}
@override
Future close() async {
// monero_wallet.closeListeners();
monero_wallet.closeCurrentWallet();
await _name.close();
await _address.close();
await _subaddress.close();
}
@override
Future connectToNode(
{Node node, bool useSSL = false, bool isLightWallet = false}) async {
try {
_syncStatus.value = ConnectingSyncStatus();
await monero_wallet.setupNode(
address: node.uri,
login: node.login,
password: node.password,
useSSL: useSSL,
isLightWallet: isLightWallet);
_syncStatus.value = ConnectedSyncStatus();
} catch (e) {
_syncStatus.value = FailedSyncStatus();
print(e);
}
}
@override
Future startSync() async {
try {
_syncStatus.value = StartingSyncStatus();
monero_wallet.startRefresh();
} on PlatformException catch (e) {
_syncStatus.value = FailedSyncStatus();
print(e);
rethrow;
}
}
Future askForSave() async {
final diff = DateTime.now().millisecondsSinceEpoch - _lastSaveTime;
if (_lastSaveTime != 0 && diff < 120000) {
return;
}
await store();
}
Future<int> getNodeHeightOrUpdate(int baseHeight) async {
if (_cachedBlockchainHeight < baseHeight) {
_cachedBlockchainHeight = await getNodeHeight();
}
return _cachedBlockchainHeight;
}
@override
Future<PendingTransaction> createTransaction(
TransactionCreationCredentials credentials) async {
final _credentials = credentials as MoneroTransactionCreationCredentials;
final transactionDescription = await transaction_history.createTransaction(
address: _credentials.address,
paymentId: _credentials.paymentId,
amount: _credentials.amount,
priorityRaw: _credentials.priority.serialize(),
accountIndex: _account.value.id);
return PendingTransaction.fromTransactionDescription(
transactionDescription);
}
@override
Future rescan({int restoreHeight = 0}) async {
_syncStatus.value = StartingSyncStatus();
setRefreshFromBlockHeight(height: restoreHeight);
monero_wallet.rescanBlockchainAsync();
_syncStatus.value = StartingSyncStatus();
}
void setRecoveringFromSeed() =>
monero_wallet.setRecoveringFromSeed(isRecovery: true);
void setRefreshFromBlockHeight({int height}) =>
monero_wallet.setRefreshFromBlockHeight(height: height);
Future setAsRecovered() async {
walletInfo.isRecovery = false;
await walletInfo.save();
}
Future askForUpdateBalance() async {
final fullBalance = await getFullBalance();
final unlockedBalance = await getUnlockedBalance();
final needToChange = _onBalanceChange.value != null
? _onBalanceChange.value.fullBalance != fullBalance ||
_onBalanceChange.value.unlockedBalance != unlockedBalance
: true;
if (!needToChange) {
return;
}
_onBalanceChange.add(MoneroBalance(
fullBalance: fullBalance, unlockedBalance: unlockedBalance));
}
Future askForUpdateTransactionHistory() async => await getHistory().update();
void changeCurrentSubaddress(Subaddress subaddress) =>
_subaddress.value = subaddress;
void changeAccount(Account account) {
_account.add(account);
final subaddress = getSubaddress()..refresh(accountIndex: account.id);
_subaddress.value = subaddress.getAll().first;
}
Future store() async {
if (_isSaving) {
return;
}
try {
_isSaving = true;
await monero_wallet.store();
_isSaving = false;
} on PlatformException catch (e) {
print(e);
_isSaving = false;
rethrow;
}
}
void setListeners() => null;
// monero_wallet.setListeners(
// _onNewBlock, _onNeedToRefresh, _onNewTransaction);
// Future _onNewBlock(int height) async {
// try {
// final nodeHeight = await getNodeHeightOrUpdate(height);
//
// if (isRecovery && _refreshHeight <= 0) {
// _refreshHeight = height;
// }
//
// if (isRecovery &&
// (_lastSyncHeight == 0 ||
// (height - _lastSyncHeight) > moneroBlockSize)) {
// _lastSyncHeight = height;
// await askForUpdateBalance();
// await askForUpdateTransactionHistory();
// }
//
// if (height > 0 && ((nodeHeight - height) < moneroBlockSize)) {
// _syncStatus.add(SyncedSyncStatus());
// } else {
// _syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight));
// }
// } catch (e) {
// print(e);
// }
// }
// Future _onNeedToRefresh() async {
// try {
//
//
// if (_syncStatus.value is FailedSyncStatus) {
// return;
// }
//
// await askForUpdateBalance();
//
// _syncStatus.add(SyncedSyncStatus());
//
// if (isRecovery) {
// await askForUpdateTransactionHistory();
// }
//
//// if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) {
//// await setAsRecovered();
//// }
//
// final now = DateTime.now().millisecondsSinceEpoch;
// final diff = now - _lastRefreshTime;
//
// if (diff >= 0 && diff < 60000) {
// return;
// }
//
// await store();
// _lastRefreshTime = now;
// } catch (e) {
// print(e);
// }
// }
// Future _onNewTransaction() async {
// await askForUpdateBalance();
// await askForUpdateTransactionHistory();
// }
}
@@ -1,163 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/src/domain/common/pathForWallet.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager;
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/common/wallets_manager.dart';
import 'package:cake_wallet/src/domain/common/wallet.dart';
import 'package:cake_wallet/src/domain/monero/monero_wallet.dart';
import 'package:cake_wallet/src/domain/common/wallet_description.dart';
class MoneroWalletsManager extends WalletsManager {
MoneroWalletsManager({@required this.walletInfoSource});
static const type = WalletType.monero;
Box<WalletInfo> walletInfoSource;
@override
Future<Wallet> create(String name, String password, String language) async {
try {
const isRecovery = false;
final path = await pathForWallet(name: name, type: WalletType.monero);
await monero_wallet_manager.createWallet(
path: path, password: password, language: language);
final wallet = await MoneroWallet.createdWallet(
walletInfoSource: walletInfoSource,
name: name,
isRecovery: isRecovery);
await wallet.updateInfo();
return wallet;
} catch (e) {
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
@override
Future<Wallet> restoreFromSeed(
String name, String password, String seed, int restoreHeight) async {
try {
const isRecovery = true;
final path = await pathForWallet(name: name, type: WalletType.monero);
await monero_wallet_manager.restoreFromSeed(
path: path,
password: password,
seed: seed,
restoreHeight: restoreHeight);
final wallet = await MoneroWallet.createdWallet(
walletInfoSource: walletInfoSource,
name: name,
isRecovery: isRecovery,
restoreHeight: restoreHeight);
await wallet.updateInfo();
return wallet;
} catch (e) {
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
@override
Future<Wallet> restoreFromKeys(
String name,
String password,
String language,
int restoreHeight,
String address,
String viewKey,
String spendKey) async {
try {
const isRecovery = true;
final path = await pathForWallet(name: name, type: WalletType.monero);
await monero_wallet_manager.restoreFromKeys(
path: path,
password: password,
language: language,
restoreHeight: restoreHeight,
address: address,
viewKey: viewKey,
spendKey: spendKey);
final wallet = await MoneroWallet.createdWallet(
walletInfoSource: walletInfoSource,
name: name,
isRecovery: isRecovery,
restoreHeight: restoreHeight);
await wallet.updateInfo();
return wallet;
} catch (e) {
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
@override
Future<Wallet> openWallet(String name, String password) async {
try {
final path = await pathForWallet(name: name, type: WalletType.monero);
monero_wallet_manager.openWallet(path: path, password: password);
final wallet = await MoneroWallet.load(walletInfoSource, name, type);
await wallet.updateInfo();
return wallet;
} catch (e) {
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
@override
Future<bool> isWalletExit(String name) async {
try {
final path = await pathForWallet(name: name, type: WalletType.monero);
return monero_wallet_manager.isWalletExist(path: path);
} catch (e) {
print('MoneroWalletsManager Error: $e');
rethrow;
}
}
@override
Future remove(WalletDescription wallet) async {
final dir = await getApplicationDocumentsDirectory();
final root = dir.path.replaceAll('app_flutter', 'files');
final walletFilePath = root + '/cw_monero/' + wallet.name;
final keyPath = walletFilePath + '.keys';
final addressFilePath = walletFilePath + '.address.txt';
final walletFile = File(walletFilePath);
final keyFile = File(keyPath);
final addressFile = File(addressFilePath);
if (await walletFile.exists()) {
await walletFile.delete();
}
if (await keyFile.exists()) {
await keyFile.delete();
}
if (await addressFile.exists()) {
await addressFile.delete();
}
final id =
walletTypeToString(wallet.type).toLowerCase() + '_' + wallet.name;
final info = walletInfoSource.values
.firstWhere((info) => info.id == id, orElse: () => null);
await info?.delete();
}
}
-19
View File
@@ -1,19 +0,0 @@
import 'package:cw_monero/structs/subaddress_row.dart';
class Subaddress {
Subaddress({this.id, this.address, this.label});
Subaddress.fromMap(Map map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.address = (map['address'] ?? '') as String,
this.label = (map['label'] ?? '') as String;
Subaddress.fromRow(SubaddressRow row)
: this.id = row.getId(),
this.address = row.getAddress(),
this.label = row.getLabel();
final int id;
final String address;
final String label;
}
@@ -1,70 +0,0 @@
import 'package:flutter/services.dart';
import 'package:rxdart/rxdart.dart';
import 'package:cw_monero/subaddress_list.dart' as subaddress_list;
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
class SubaddressList {
SubaddressList() {
_isRefreshing = false;
_isUpdating = false;
_subaddress = BehaviorSubject<List<Subaddress>>();
}
Observable<List<Subaddress>> get subaddresses => _subaddress.stream;
BehaviorSubject<List<Subaddress>> _subaddress;
bool _isRefreshing;
bool _isUpdating;
void update({int accountIndex}) {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh(accountIndex: accountIndex);
_subaddress.add(getAll());
_isUpdating = false;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
List<Subaddress> getAll() {
return subaddress_list
.getAllSubaddresses()
.map((subaddressRow) => Subaddress.fromRow(subaddressRow))
.toList();
}
Future addSubaddress({int accountIndex, String label}) async {
await subaddress_list.addSubaddress(
accountIndex: accountIndex, label: label);
await update(accountIndex: accountIndex);
}
Future setLabelSubaddress(
{int accountIndex, int addressIndex, String label}) async {
await subaddress_list.setLabelForSubaddress(
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
await update(accountIndex: accountIndex);
}
void refresh({int accountIndex}) {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
_isRefreshing = false;
} on PlatformException catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}
@@ -1,16 +0,0 @@
import 'package:hive/hive.dart';
part 'transaction_description.g.dart';
@HiveType(typeId: 2)
class TransactionDescription extends HiveObject {
TransactionDescription({this.id, this.recipientAddress});
static const boxName = 'TransactionDescriptions';
@HiveField(0)
String id;
@HiveField(1)
String recipientAddress;
}
@@ -1,10 +0,0 @@
import 'dart:async';
import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/common/fetch_price.dart';
class FiatConvertationService {
Future<double> getPrice({CryptoCurrency crypto, FiatCurrency fiat}) async {
return await fetchPriceFor(crypto: crypto, fiat: fiat);
}
}
-46
View File
@@ -1,46 +0,0 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/common/secret_store_key.dart';
import 'package:cake_wallet/src/domain/common/encrypt.dart';
class UserService {
UserService({this.sharedPreferences, this.secureStorage});
final FlutterSecureStorage secureStorage;
final SharedPreferences sharedPreferences;
Future setPassword(String password) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
try {
final encodedPassord = encodedPinCode(pin: password);
await secureStorage.write(key: key, value: encodedPassord);
} catch (e) {
print(e);
}
}
Future<bool> canAuthenticate() async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final sharedPreferences = await SharedPreferences.getInstance();
final walletName = sharedPreferences.getString("current_wallet_name") ?? "";
var password = '';
try {
password = await secureStorage.read(key: key);
} catch (e) {
print(e);
}
return walletName.isNotEmpty && password.isNotEmpty;
}
Future<bool> authenticate(String pin) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPin = await secureStorage.read(key: key);
final decodedPin = decodedPinCode(pin: encodedPin);
return decodedPin == pin;
}
}
@@ -1,163 +0,0 @@
import 'dart:async';
import 'package:cake_wallet/bitcoin/key.dart';
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:uuid/uuid.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/common/encrypt.dart';
import 'package:cake_wallet/src/domain/common/wallet.dart';
import 'package:cake_wallet/src/domain/common/wallet_description.dart';
import 'package:cake_wallet/src/domain/common/wallets_manager.dart';
import 'package:cake_wallet/src/domain/common/secret_store_key.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/monero/monero_wallets_manager.dart';
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
class WalletIsExistException implements Exception {
WalletIsExistException(this.name);
String name;
@override
String toString() => "Wallet with name $name is already exist!";
}
class WalletListService {
WalletListService(
{this.secureStorage,
this.walletInfoSource,
this.walletsManager,
@required this.walletService,
@required this.sharedPreferences})
: _type = WalletType.monero;
final FlutterSecureStorage secureStorage;
final WalletService walletService;
final Box<WalletInfo> walletInfoSource;
final SharedPreferences sharedPreferences;
WalletsManager walletsManager;
WalletType _type;
Future<List<WalletDescription>> getAll() async => walletInfoSource.values
.map((info) => WalletDescription(name: info.name, type: info.type))
.toList();
Future create(String name, String language) async {
if (await walletsManager.isWalletExit(name)) {
throw WalletIsExistException(name);
}
if (walletService.currentWallet != null) {
await walletService.close();
}
final password = _generatePassword();
await saveWalletPassword(password: password, walletName: name);
final wallet = await walletsManager.create(name, password, language);
await onWalletChange(wallet);
}
Future restoreFromSeed(String name, String seed, int restoreHeight) async {
if (await walletsManager.isWalletExit(name)) {
throw WalletIsExistException(name);
}
if (walletService.currentWallet != null) {
await walletService.close();
}
final password = _generatePassword();
await saveWalletPassword(password: password, walletName: name);
final wallet = await walletsManager.restoreFromSeed(
name, password, seed, restoreHeight);
await onWalletChange(wallet);
}
Future restoreFromKeys(String name, String language, int restoreHeight,
String address, String viewKey, String spendKey) async {
if (await walletsManager.isWalletExit(name)) {
throw WalletIsExistException(name);
}
if (walletService.currentWallet != null) {
await walletService.close();
}
final password = _generatePassword();
await saveWalletPassword(password: password, walletName: name);
final wallet = await walletsManager.restoreFromKeys(
name, password, language, restoreHeight, address, viewKey, spendKey);
await onWalletChange(wallet);
}
Future openWallet(String name) async {
if (walletService.currentWallet != null) {
await walletService.close();
}
final password = await getWalletPassword(walletName: name);
final wallet = await walletsManager.openWallet(name, password);
await onWalletChange(wallet);
}
Future changeWalletManger({WalletType walletType}) async {
_type = walletType;
switch (walletType) {
case WalletType.monero:
walletsManager =
MoneroWalletsManager(walletInfoSource: walletInfoSource);
break;
case WalletType.bitcoin:
// walletsManager = BitcoinWalletManager();
break;
case WalletType.none:
walletsManager = null;
break;
}
}
Future onWalletChange(Wallet wallet) async {
walletService.currentWallet = wallet;
final walletName = await wallet.getName();
print('walletName $walletName ');
await sharedPreferences.setString('current_wallet_name', walletName);
}
Future remove(WalletDescription wallet) async =>
await walletsManager.remove(wallet);
Future<String> getWalletPassword({String walletName}) async {
final key = generateStoreKeyFor(
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = await secureStorage.read(key: key);
return decodeWalletPassword(password: encodedPassword);
}
Future saveWalletPassword({String walletName, String password}) async {
final key = generateStoreKeyFor(
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = encodeWalletPassword(password: password);
await secureStorage.write(key: key, value: encodedPassword);
}
String _generatePassword() {
switch (_type) {
case WalletType.bitcoin:
return generateKey();
default:
return Uuid().v4();
}
}
}
-131
View File
@@ -1,131 +0,0 @@
import 'package:rxdart/rxdart.dart';
import 'package:cake_wallet/src/domain/common/balance.dart';
import 'package:cake_wallet/src/domain/common/wallet_description.dart';
import 'package:cake_wallet/src/domain/common/wallet.dart';
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/domain/common/transaction_creation_credentials.dart';
import 'package:cake_wallet/src/domain/common/pending_transaction.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
class WalletService extends Wallet {
WalletService() {
_currentWallet = null;
walletType = WalletType.none;
_syncStatus = BehaviorSubject<SyncStatus>();
_onBalanceChange = BehaviorSubject<Balance>();
_onWalletChanged = BehaviorSubject<Wallet>();
}
@override
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
@override
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
@override
Observable<String> get onAddressChange => _currentWallet.onAddressChange;
@override
Observable<String> get onNameChange => _currentWallet.onNameChange;
@override
String get address => _currentWallet.address;
@override
String get name => _currentWallet.name;
@override
WalletType get walletType => _currentWallet.walletType;
Observable<Wallet> get onWalletChange => _onWalletChanged.stream;
SyncStatus get syncStatusValue => _syncStatus.value;
Wallet get currentWallet => _currentWallet;
set currentWallet(Wallet wallet) {
_currentWallet = wallet;
if (wallet == null) {
return;
}
_currentWallet.onBalanceChange
.listen((wallet) => _onBalanceChange.add(wallet));
_currentWallet.syncStatus.listen((status) => _syncStatus.add(status));
_onWalletChanged.add(wallet);
final type = wallet.getType();
wallet.getName().then(
(name) => description = WalletDescription(name: name, type: type));
}
BehaviorSubject<Wallet> _onWalletChanged;
BehaviorSubject<Balance> _onBalanceChange;
BehaviorSubject<SyncStatus> _syncStatus;
Wallet _currentWallet;
WalletDescription description;
@override
WalletType getType() => _currentWallet.getType();
@override
Future<String> getFilename() => _currentWallet.getFilename();
@override
Future<String> getName() => _currentWallet.getName();
@override
Future<String> getAddress() => _currentWallet.getAddress();
@override
Future<String> getSeed() => _currentWallet.getSeed();
@override
Future<Map<String, String>> getKeys() => _currentWallet.getKeys();
@override
Future<String> getFullBalance() => _currentWallet.getFullBalance();
@override
Future<String> getUnlockedBalance() => _currentWallet.getUnlockedBalance();
@override
Future<int> getCurrentHeight() => _currentWallet.getCurrentHeight();
@override
Future<int> getNodeHeight() => _currentWallet.getNodeHeight();
@override
Future<bool> isConnected() => _currentWallet.isConnected();
@override
Future close() => _currentWallet.close();
@override
Future connectToNode(
{Node node, bool useSSL = false, bool isLightWallet = false}) =>
_currentWallet.connectToNode(
node: node, useSSL: useSSL, isLightWallet: isLightWallet);
@override
Future startSync() => _currentWallet.startSync();
@override
TransactionHistory getHistory() => _currentWallet.getHistory();
@override
Future<PendingTransaction> createTransaction(
TransactionCreationCredentials credentials) =>
_currentWallet.createTransaction(credentials);
@override
Future updateInfo() async => _currentWallet.updateInfo();
@override
Future rescan({int restoreHeight = 0}) async =>
_currentWallet.rescan(restoreHeight: restoreHeight);
}
+98 -98
View File
@@ -1,98 +1,98 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
import 'package:cake_wallet/src/start_updating_price.dart';
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/src/stores/price/price_store.dart';
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
import 'package:cake_wallet/src/stores/login/login_store.dart';
Timer _reconnectionTimer;
ReactionDisposer _connectToNodeDisposer;
ReactionDisposer _onSyncStatusChangeDisposer;
ReactionDisposer _onCurrentWalletChangeDisposer;
void setReactions(
{@required SettingsStore settingsStore,
@required PriceStore priceStore,
@required SyncStore syncStore,
@required WalletStore walletStore,
@required WalletService walletService,
// @required AuthenticationStore authenticationStore,
@required LoginStore loginStore}) {
connectToNode(settingsStore: settingsStore, walletStore: walletStore);
onSyncStatusChange(
syncStore: syncStore,
walletStore: walletStore,
settingsStore: settingsStore);
onCurrentWalletChange(
walletStore: walletStore,
settingsStore: settingsStore,
priceStore: priceStore);
autorun((_) async {
// if (authenticationStore.state == AuthenticationState.allowed) {
// await loginStore.loadCurrentWallet();
// authenticationStore.state = AuthenticationState.readyToLogin;
// }
});
}
void connectToNode({SettingsStore settingsStore, WalletStore walletStore}) {
_connectToNodeDisposer?.call();
_connectToNodeDisposer = reaction((_) => settingsStore.node,
(Node node) async => await walletStore.connectToNode(node: node));
}
void onCurrentWalletChange(
{WalletStore walletStore,
SettingsStore settingsStore,
PriceStore priceStore}) {
_onCurrentWalletChangeDisposer?.call();
reaction((_) => walletStore.name, (String _) {
walletStore.connectToNode(node: settingsStore.node);
startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
});
}
void onSyncStatusChange(
{SyncStore syncStore,
WalletStore walletStore,
SettingsStore settingsStore}) {
// _onSyncStatusChangeDisposer?.call();
// reaction((_) => syncStore.status, (SyncStatus status) async {
// if (status is ConnectedSyncStatus) {
// await walletStore.startSync();
// }
// // Reconnect to the node if the app is not started sync after 30 seconds
// if (status is StartingSyncStatus) {
// startReconnectionObserver(syncStore: syncStore, walletStore: walletStore);
// }
// });
}
void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
if (_reconnectionTimer != null) {
_reconnectionTimer.cancel();
}
_reconnectionTimer = Timer.periodic(Duration(minutes: 1), (_) async {
try {
final isConnected = await walletStore.isConnected();
if (!isConnected) {
await walletStore.reconnect();
}
} catch (e) {
print(e);
}
});
}
// import 'dart:async';
// import 'package:flutter/foundation.dart';
// import 'package:mobx/mobx.dart';
// import 'package:cake_wallet/entities/node.dart';
// import 'package:cake_wallet/entities/sync_status.dart';
// import 'package:cake_wallet/src/domain/services/wallet_service.dart';
// import 'package:cake_wallet/src/start_updating_price.dart';
// import 'package:cake_wallet/src/stores/sync/sync_store.dart';
// import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
// import 'package:cake_wallet/src/stores/settings/settings_store.dart';
// import 'package:cake_wallet/src/stores/price/price_store.dart';
// import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
// import 'package:cake_wallet/src/stores/login/login_store.dart';
//
// Timer _reconnectionTimer;
// ReactionDisposer _connectToNodeDisposer;
// ReactionDisposer _onSyncStatusChangeDisposer;
// ReactionDisposer _onCurrentWalletChangeDisposer;
//
// void setReactions(
// {@required SettingsStore settingsStore,
// @required PriceStore priceStore,
// @required SyncStore syncStore,
// @required WalletStore walletStore,
// @required WalletService walletService,
// // @required AuthenticationStore authenticationStore,
// @required LoginStore loginStore}) {
// connectToNode(settingsStore: settingsStore, walletStore: walletStore);
// onSyncStatusChange(
// syncStore: syncStore,
// walletStore: walletStore,
// settingsStore: settingsStore);
// onCurrentWalletChange(
// walletStore: walletStore,
// settingsStore: settingsStore,
// priceStore: priceStore);
// autorun((_) async {
// // if (authenticationStore.state == AuthenticationState.allowed) {
// // await loginStore.loadCurrentWallet();
// // authenticationStore.state = AuthenticationState.readyToLogin;
// // }
// });
// }
//
// void connectToNode({SettingsStore settingsStore, WalletStore walletStore}) {
// _connectToNodeDisposer?.call();
//
// _connectToNodeDisposer = reaction((_) => settingsStore.node,
// (Node node) async => await walletStore.connectToNode(node: node));
// }
//
// void onCurrentWalletChange(
// {WalletStore walletStore,
// SettingsStore settingsStore,
// PriceStore priceStore}) {
// _onCurrentWalletChangeDisposer?.call();
//
// reaction((_) => walletStore.name, (String _) {
// walletStore.connectToNode(node: settingsStore.node);
// startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
// });
// }
//
// void onSyncStatusChange(
// {SyncStore syncStore,
// WalletStore walletStore,
// SettingsStore settingsStore}) {
// // _onSyncStatusChangeDisposer?.call();
//
// // reaction((_) => syncStore.status, (SyncStatus status) async {
// // if (status is ConnectedSyncStatus) {
// // await walletStore.startSync();
// // }
//
// // // Reconnect to the node if the app is not started sync after 30 seconds
// // if (status is StartingSyncStatus) {
// // startReconnectionObserver(syncStore: syncStore, walletStore: walletStore);
// // }
// // });
// }
//
// void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
// if (_reconnectionTimer != null) {
// _reconnectionTimer.cancel();
// }
//
// _reconnectionTimer = Timer.periodic(Duration(minutes: 1), (_) async {
// try {
// final isConnected = await walletStore.isConnected();
//
// if (!isConnected) {
// await walletStore.reconnect();
// }
// } catch (e) {
// print(e);
// }
// });
// }
+30 -51
View File
@@ -5,20 +5,18 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/auth_state.dart';
import 'package:cake_wallet/view_model/auth_view_model.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/entities/biometric_auth.dart';
import 'package:cake_wallet/core/execution_state.dart';
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
class AuthPage extends StatefulWidget {
AuthPage(
{@required this.allowBiometricalAuthentication,
this.onAuthenticationFinished,
this.authViewModel,
this.closable = true});
AuthPage(this.authViewModel,
{this.onAuthenticationFinished, this.closable = true});
final AuthViewModel authViewModel;
final OnAuthenticationFinished onAuthenticationFinished;
final bool allowBiometricalAuthentication;
final bool closable;
@override
@@ -35,8 +33,8 @@ class AuthPageState extends State<AuthPage> {
@override
void initState() {
_reaction ??=
reaction((_) => widget.authViewModel.state, (AuthState state) {
if (state is AuthenticatedSuccessfully) {
reaction((_) => widget.authViewModel.state, (ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.onAuthenticationFinished != null) {
widget.onAuthenticationFinished(true, this);
@@ -51,7 +49,7 @@ class AuthPageState extends State<AuthPage> {
});
}
if (state is AuthenticationInProgress) {
if (state is IsExecutingState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_key.currentState.showSnackBar(
SnackBar(
@@ -62,7 +60,7 @@ class AuthPageState extends State<AuthPage> {
});
}
if (state is AuthenticationFailure) {
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_pinCodeKey.currentState.clear();
_key.currentState.hideCurrentSnackBar();
@@ -97,23 +95,10 @@ class AuthPageState extends State<AuthPage> {
}
});
if (widget.allowBiometricalAuthentication) {
if (widget.authViewModel.isBiometricalAuthenticationAllowed) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
print('post');
await Future<void>.delayed(Duration(milliseconds: 100));
print('after timeout');
final biometricAuth = BiometricAuth();
final isAuth = await biometricAuth.isAuthenticated();
if (isAuth) {
widget.authViewModel.biometricAuth();
_key.currentState.showSnackBar(
SnackBar(
content: Text(S.of(context).authenticated),
backgroundColor: Colors.green,
),
);
}
await widget.authViewModel.biometricAuth();
});
}
@@ -133,34 +118,28 @@ class AuthPageState extends State<AuthPage> {
@override
Widget build(BuildContext context) {
print('start');
return Scaffold(
key: _key,
appBar: CupertinoNavigationBar(
leading: widget.closable
? SizedBox(
height: 37,
width: 20,
child: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () => Navigator.of(context).pop(),
child: _backArrowImageDarkTheme),
),
)
: Container(),
backgroundColor: Theme.of(context).backgroundColor,
border: null,
),
leading: widget.closable
? SizedBox(
height: 37,
width: 20,
child: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () => Navigator.of(context).pop(),
child: _backArrowImageDarkTheme),
),
)
: Container(),
backgroundColor: Theme.of(context).backgroundColor,
border: null),
resizeToAvoidBottomPadding: false,
body: PinCode(
(pin, _) => widget.authViewModel
.auth(password: pin.fold('', (ac, val) => ac + '$val')),
false,
_pinCodeKey));
body: PinCode((pin, _) => widget.authViewModel.auth(password: pin),
(_) => null, widget.authViewModel.pinLength, false, _pinCodeKey));
}
}
@@ -1,29 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/services/user_service.dart';
import 'package:cake_wallet/src/domain/services/wallet_list_service.dart';
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/stores/auth/auth_store.dart';
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
Widget createLoginPage(
{@required SharedPreferences sharedPreferences,
@required UserService userService,
@required WalletService walletService,
@required WalletListService walletListService,
@required AuthenticationStore authenticationStore}) =>
null;
// Provider(
// create: (_) => AuthStore(
// sharedPreferences: sharedPreferences,
// userService: userService,
// walletService: walletService),
// child: AuthPage(
// onAuthenticationFinished: (isAuthenticated, state) {
// if (isAuthenticated) {
// authenticationStore.loggedIn();
// }
// },
// closable: false));
@@ -1,24 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/services/user_service.dart';
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/stores/auth/auth_store.dart';
Widget createUnlockPage(
{@required SharedPreferences sharedPreferences,
@required UserService userService,
@required WalletService walletService,
@required Function(bool, AuthPageState) onAuthenticationFinished}) =>
null;
// WillPopScope(
// onWillPop: () async => false,
// child: Provider(
// create: (_) => AuthStore(
// sharedPreferences: sharedPreferences,
// userService: userService,
// walletService: walletService),
// child: AuthPage(
// onAuthenticationFinished: onAuthenticationFinished,
// closable: false)));
+3 -3
View File
@@ -94,8 +94,8 @@ abstract class BasePage extends StatelessWidget {
leading: leading(context),
middle: middle(context),
trailing: trailing(context),
backgroundColor:
_isDarkTheme ? backgroundDarkColor : backgroundLightColor);
backgroundColor: Colors.transparent);
// _isDarkTheme ? backgroundDarkColor : backgroundLightColor);
case AppBarStyle.withShadow:
return NavBar.withShadow(
@@ -131,7 +131,7 @@ abstract class BasePage extends StatelessWidget {
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
endDrawer: endDrawer,
appBar: appBar(context),
body: body(context), //SafeArea(child: ),
body: body(context),
floatingActionButton: floatingActionButton(context));
return rootWrapper?.call(context, root) ?? root;
@@ -5,7 +5,7 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
+5 -5
View File
@@ -6,9 +6,9 @@ import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/address_validator.dart';
import 'package:cake_wallet/core/contact_name_validator.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model_state.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
@@ -48,12 +48,12 @@ class ContactPage extends BasePage {
final downArrow = Image.asset('assets/images/arrow_bottom_purple_icon.png',
color: Theme.of(context).primaryTextTheme.overline.color, height: 8);
reaction((_) => contactViewModel.state, (ContactViewModelState state) {
if (state is ContactCreationFailure) {
reaction((_) => contactViewModel.state, (ExecutionState state) {
if (state is FailureState) {
_onContactSavingFailure(context, state.error);
}
if (state is ContactSavingSuccessfully) {
if (state is ExecutedSuccessfullyState) {
_onContactSavedSuccessfully(context);
}
});
@@ -1,31 +1,33 @@
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
import 'package:cake_wallet/src/stores/action_list/trade_filter_store.dart';
import 'package:cake_wallet/src/stores/action_list/transaction_filter_store.dart';
import 'package:cake_wallet/src/stores/price/price_store.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
import 'package:cake_wallet/exchange/trade.dart';
// import 'package:cake_wallet/monero/transaction_description.dart';
// import 'package:cake_wallet/src/domain/services/wallet_service.dart';
// import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
// import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
// import 'package:cake_wallet/src/stores/action_list/trade_filter_store.dart';
// import 'package:cake_wallet/src/stores/action_list/transaction_filter_store.dart';
// import 'package:cake_wallet/src/stores/price/price_store.dart';
// import 'package:cake_wallet/src/stores/settings/settings_store.dart';
// import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
Widget createDashboardPage(
{@required WalletService walletService,
@required PriceStore priceStore,
@required Box<TransactionDescription> transactionDescriptions,
@required SettingsStore settingsStore,
@required Box<Trade> trades,
@required WalletStore walletStore}) =>
Provider(
create: (_) => ActionListStore(
walletService: walletService,
settingsStore: settingsStore,
priceStore: priceStore,
tradesSource: trades,
transactionFilterStore: TransactionFilterStore(),
tradeFilterStore: TradeFilterStore(walletStore: walletStore),
transactionDescriptions: transactionDescriptions),
child: DashboardPage());
// FIXME: Remove me.
// Widget createDashboardPage(
// {@required WalletService walletService,
// @required PriceStore priceStore,
// @required Box<TransactionDescription> transactionDescriptions,
// @required SettingsStore settingsStore,
// @required Box<Trade> trades,
// @required WalletStore walletStore}) =>
// Provider(
// create: (_) => ActionListStore(
// walletService: walletService,
// settingsStore: settingsStore,
// priceStore: priceStore,
// tradesSource: trades,
// transactionFilterStore: TransactionFilterStore(),
// tradeFilterStore: TradeFilterStore(walletStore: walletStore),
// transactionDescriptions: transactionDescriptions),
// child: DashboardPage());
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
@@ -1,26 +1,21 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
class DateSectionRaw extends StatelessWidget {
DateSectionRaw({this.date});
static final nowDate = DateTime.now();
final DateTime date;
@override
Widget build(BuildContext context) {
final nowDate = DateTime.now();
final diffDays = date.difference(nowDate).inDays;
final isToday = nowDate.day == date.day &&
nowDate.month == date.month &&
nowDate.year == date.year;
final settingsStore = Provider.of<SettingsStore>(context);
final currentLanguage = settingsStore.languageCode;
final dateSectionDateFormat = settingsStore.getCurrentDateFormat(
formatUSA: "yyyy MMM d",
formatDefault: "d MMM yyyy");
final dateSectionDateFormat = DateFormatter.withCurrentLocal();
var title = "";
if (isToday) {
@@ -28,21 +23,19 @@ class DateSectionRaw extends StatelessWidget {
} else if (diffDays == 0) {
title = S.of(context).yesterday;
} else if (diffDays > -7 && diffDays < 0) {
final dateFormat = DateFormat.EEEE(currentLanguage);
final dateFormat = DateFormat.EEEE();
title = dateFormat.format(date);
} else {
title = dateSectionDateFormat.format(date);
}
return Container(
height: 35,
alignment: Alignment.center,
color: Colors.transparent,
child: Text(title,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).textTheme.overline.backgroundColor
))
);
height: 35,
alignment: Alignment.center,
color: Colors.transparent,
child: Text(title,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).textTheme.overline.backgroundColor)));
}
}
@@ -2,7 +2,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
import 'package:flutter/rendering.dart';
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/entities/sync_status.dart';
class SyncIndicator extends StatelessWidget {
SyncIndicator({@required this.dashboardViewModel});

Some files were not shown because too many files have changed in this diff Show More